/* 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
#include "struct.h"
#include "sdlscreen.h"
#include "global.h"
#include "erreurs.h"
#include "boutons.h"
#include "moteur.h"
#include "divers.h"
#include "clavier.h"
#include "sdlscreen.h"
#include "windows.h"
#include "palette.h"
#include "input.h"
word Count_used_colors(dword* usage)
{
int nb_pixels=0;
Uint8* Pixel_Courant=Main_screen;
Uint8 color;
word nb_colors=0;
int i;
for (i=0;i<256;i++) usage[i]=0;
//Calcul du nombre de pixels dans l'image
nb_pixels=Main_image_height*Main_image_width;
// On parcourt l'écran courant pour compter les utilisations des couleurs
for(i=0;i0;dx--)
{
esi = Debut_de_colonne;
// Pout chaque colonne
for(cx=Brush_height;cx>0;cx--)
{
*edi = *esi;
esi+=Brush_width;
edi++;
}
Debut_de_colonne--;
}
}
// Replace une couleur par une autre dans un buffer
void Remap_general_lowlevel(byte * conversion_table,byte * buffer,short width,short height,short buffer_width)
{
int dx,cx;
// Pour chaque ligne
for(dx=height;dx>0;dx--)
{
// Pour chaque pixel
for(cx=width;cx>0;cx--)
{
*buffer = conversion_table[*buffer];
buffer++;
}
buffer += buffer_width-width;
}
}
void Copy_image_to_brush(short start_x,short start_y,short Brush_width,short Brush_height,word image_width)
{
byte* src=start_y*image_width+start_x+Main_screen; //Adr départ image (ESI)
byte* dest=Brush; //Adr dest brosse (EDI)
int dx;
for (dx=Brush_height;dx!=0;dx--)
//Pour chaque ligne
{
// On fait une copie de la ligne
memcpy(dest,src,Brush_width);
// On passe à la ligne suivante
src+=image_width;
dest+=Brush_width;
}
}
byte Read_pixel_from_feedback_screen (word x,word y)
{
return *(FX_feedback_screen+y*Main_image_width+x);
}
dword Round_div(dword numerator,dword divisor)
{
return numerator/divisor;
}
byte Effect_sieve(word x,word y)
{
return Sieve[x % Sieve_width][y % Sieve_height];
}
void Set_mouse_position(void)
{
SDL_WarpMouse(
Mouse_X*Pixel_width,
Mouse_Y*Pixel_height
);
}
void Replace_colors_within_limits(byte * replace_table)
{
int line;
int counter;
byte* Adresse;
byte old;
// Pour chaque ligne :
for(line = Limit_top;line <= Limit_bottom; line++)
{
// Pour chaque pixel sur la ligne :
for (counter = Limit_left;counter <= Limit_right;counter ++)
{
Adresse = Main_screen+line*Main_image_width+counter;
old=*Adresse;
*Adresse = replace_table[old];
}
}
}
byte Read_pixel_from_backup_screen (word x,word y)
{
return *(Screen_backup + x + Main_image_width * y);
}
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].G = palette[i].G >> 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].G = (palette[i].G << 2)|(palette[i].G >> 4);
palette[i].B = (palette[i].B << 2)|(palette[i].B >> 4);
}
}
byte Effect_interpolated_colorize (word x,word y,byte color)
{
// factor_a = 256*(100-Colorize_opacity)/100
// factor_b = 256*( Colorize_opacity)/100
//
// (Couleur_dessous*factor_a+color*facteur_B)/256
//
// On place dans ESI 3*Couleur_dessous ( = position de cette couleur dans la
// palette des teintes) et dans EDI, 3*color.
byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B;
byte blue=Main_palette[color].B;
byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G;
byte green=Main_palette[color].G;
byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R;
byte red=Main_palette[color].R;
// On récupère les 3 composantes RVB
// blue
blue = (Facteur_B_table[blue]
+ Facteur_A_table[blue_under]) / 256;
green = (Facteur_B_table[green]
+ Facteur_A_table[green_under]) / 256;
red = (Facteur_B_table[red]
+ Facteur_A_table[red_under]) / 256;
return Best_color(red,green,blue);
}
byte Effect_additive_colorize (word x,word y,byte color)
{
byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B;
byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G;
byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R;
byte blue=Main_palette[color].B;
byte green=Main_palette[color].G;
byte red=Main_palette[color].R;
return Best_color(
red>red_under?red:red_under,
green>green_under?green:green_under,
blue>blue_under?blue:blue_under);
}
byte Effect_substractive_colorize(word x,word y,byte color)
{
byte blue_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].B;
byte green_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].G;
byte red_under=Main_palette[*(FX_feedback_screen + y * Main_image_width + x)].R;
byte blue=Main_palette[color].B;
byte green=Main_palette[color].G;
byte red=Main_palette[color].R;
return Best_color(
redTimer_start) Timer_state=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 = Brush ;
byte* EDI = Brush + (Brush_height - 1) *Brush_width;
byte tmp;
word cx;
while(ESI < EDI)
{
// Il faut inverser les lignes pointées par ESI et
// EDI ("Brush_width" octets en tout)
for(cx = Brush_width;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 * Brush_width; // 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 = Brush;
byte* EDI = Brush + Brush_width - 1;
byte* Debut_Ligne;
byte* Fin_Ligne;
byte tmp;
word cx;
while(ESI0;cx--)
{
tmp=*ESI;
*ESI=*EDI;
*EDI=tmp;
EDI+=Brush_width;
ESI+=Brush_width;
}
// 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 = Brush;
byte* EDI = Brush + Brush_height*Brush_width - 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 (Brush_width octets)
// En même temps, on échange les pixels, donc EDI
// pointe sur la FIN de sa ligne
for(cx=Brush_width;cx>0;cx--)
{
tmp = *ESI;
*ESI = *EDI;
*EDI = tmp;
EDI--; // Attention ici on recule !
ESI++;
}
}
}
void Slider_timer(byte speed)
//Boucle d'attente pour faire bouger les scrollbars à une vitesse correcte
{
Uint32 end;
byte original_mouse_k = Mouse_K;
end = SDL_GetTicks() + speed*10;
do
{
if (!Get_input()) Wait_VBL();
} while (Mouse_K == original_mouse_k && SDL_GetTicks()0;dx--)
{
// Pour chaque ligne
memcpy(edi,esi,ax);
memcpy(edi - x_offset,esi+ax,x_offset);
// On passe à la ligne suivante
edi += Main_image_width;
esi += Main_image_width;
}
// On vient de faire le traitement pour otutes les lignes au-dessous de y_offset
// Maintenant on traite celles au dessus
edi = x_offset + Main_screen;
for(dx = y_offset;dx>0;dx--)
{
memcpy(edi,esi,ax);
memcpy(edi - x_offset,esi+ax,x_offset);
edi += Main_image_width;
esi += Main_image_width;
}
Update_rect(0,0,0,0);
}
void Zoom_a_line(byte* original_line, byte* zoomed_line,
word factor, word width
)
{
byte color;
word x;
// Pour chaque pixel
for(x=0;x
#elif defined(__macosx__) || defined(__FreeBSD__)
#include
#elif defined(__BEOS__) || defined(__HAIKU__)
// sysinfo not implemented
#elif defined(__AROS__) || defined(__amigaos4__) || defined(__MORPHOS__)
#include
#elif defined(__SKYOS__)
#include
#else
#include // sysinfo() for free RAM
#endif
// Indique quelle est la mémoire disponible
unsigned long Memory_free(void)
{
// 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.
// However, it is still a good idea to make a proper function if you can...
// If Grafx2 thinks the memory is full, weird things may happen. And if memory
// ever becomes full and you're still saying there are 10MB free here, the
// program will crash without saving any picture backup ! You've been warned...
#if defined(__WIN32__)
MEMORYSTATUS mstt;
mstt.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&mstt);
return mstt.dwAvailPhys;
#elif defined(__macosx__) || defined(__FreeBSD__)
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__) || defined(__SKYOS__) || defined(__amigaos4__)
// No on BeOS or Haiku
// AvailMem is misleading on os4 (os4 caches stuff in memory that you can still allocate)
#warning "There is missing code there for your platform ! please check and correct :)"
return 10*1024*1024;
#elif defined(__AROS__) || defined(__MORPHOS__)
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 number,char * str,byte nb_char)
{
int index;
for (index=nb_char-1;index>=0;index--)
{
str[index]=(number%10)+'0';
number/=10;
if (number==0)
for (index--;index>=0;index--)
str[index]=' ';
}
str[nb_char]='\0';
}
// Transformer une chaîne en un entier naturel (renvoie -1 si ch. invalide)
int Str2num(char * str)
{
int value=0;
for (;*str;str++)
{
if ( (*str>='0') && (*str<='9') )
value=(value*10)+(*str-'0');
else
return -1;
}
return value;
}
// Arrondir un nombre réel à la valeur entière la plus proche
short Round(float value)
{
short temp=value;
if (value>=0)
{ if ((value-temp)>= 0.5) temp++; }
else
{ if ((value-temp)<=-0.5) temp--; }
return temp;
}
// Arrondir le résultat d'une division à la valeur entière supérieure
short Round_div_max(short numerator,short divisor)
{
if (!(numerator % divisor))
return (numerator/divisor);
else
return (numerator/divisor)+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 * Mode_label(int mode)
{
static char str[24];
if (! Video_mode[mode].Fullscreen)
return "window";
sprintf(str, "%dx%d", Video_mode[mode].Width, Video_mode[mode].Height);
return str;
}
// 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 Convert_videomode_arg(const char *argument)
{
// Je suis paresseux alors je vais juste tester les libellés
int mode_index;
for (mode_index=0; mode_index