grafX2/sdlscreen.c
Yves Rizoud 45f1dfeb7b TEXT Tool, first work-in-progress commit.
Truetype only, compile with "make NOTTF=1" if you don't want to bother with it.
Only TTF is done, aliased (ok) and non-aliased (backgound color is
currently stuck to color index 0)
The Clear button doesn't update the window.
Only one font (certified to be public domain).
Preview not done.
Font selector not done.
SFont support not done.
Limit 30 characters.


git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@305 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2008-10-23 22:13:53 +00:00

609 lines
18 KiB
C

/* 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 <http://www.gnu.org/licenses/> or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <SDL/SDL.h>
#include "global.h"
#include "sdlscreen.h"
#include "divers.h"
#include "erreurs.h"
#include "graph.h"
// Mise à jour minimaliste en nombre de pixels
#define METHODE_UPDATE_MULTI_RECTANGLE 1
// Mise à jour intermédiaire, par rectangle inclusif.
#define METHODE_UPDATE_PAR_CUMUL 2
// Mise à jour totale, pour les plate-formes qui imposent un Vsync à chaque mise à jour écran.
#define METHODE_UPDATE_PLEINE_PAGE 3
// METHODE_UPDATE peut être fixé depuis le makefile, sinon c'est ici:
#ifndef METHODE_UPDATE
#ifdef __macosx__
#define METHODE_UPDATE METHODE_UPDATE_PLEINE_PAGE
#else
#define METHODE_UPDATE METHODE_UPDATE_MULTI_RECTANGLE
#endif
#endif
void Pixel_SDL (word X,word Y,byte Couleur)
/* Affiche un pixel de la Couleur aux coords X;Y à l'écran */
{
*(Ecran + X + Y * Largeur_ecran)=Couleur;
}
byte Lit_Pixel_SDL (word X,word Y)
/* On retourne la couleur du pixel aux coords données */
{
return *( Ecran + Y * Largeur_ecran + X );
}
void Afficher_partie_de_l_ecran_SDL (word Largeur,word Hauteur,word Largeur_image)
/* Afficher une partie de l'image telle quelle sur l'écran */
{
byte* Dest=Ecran; //On va se mettre en 0,0 dans l'écran (EDI)
byte* Src=Principal_Decalage_Y*Largeur_image+Principal_Decalage_X+Principal_Ecran; //Coords de départ ds la source (ESI)
int dx;
for(dx=Hauteur;dx!=0;dx--)
// Pour chaque ligne
{
// On fait une copie de la ligne
memcpy(Dest,Src,Largeur);
// On passe à la ligne suivante
Src+=Largeur_image;
Dest+=Largeur_ecran;
}
UpdateRect(0,0,Largeur,Hauteur);
}
void Block_SDL (word Debut_X,word Debut_Y,word Largeur,word Hauteur,byte Couleur)
/* On affiche un rectangle de la couleur donnée */
{
SDL_Rect rectangle;
rectangle.x=Debut_X;
rectangle.y=Debut_Y;
rectangle.w=Largeur;
rectangle.h=Hauteur;
SDL_FillRect(Ecran_SDL,&rectangle,Couleur);
// UpdateRect(Debut_X,Debut_Y,Largeur,Hauteur);
}
void Pixel_Preview_Normal_SDL (word X,word Y,byte Couleur)
/* Affichage d'un pixel dans l'écran, par rapport au décalage de l'image
* dans l'écran, en mode normal (pas en mode loupe)
* Note: si on modifie cette procédure, il faudra penser à faire également
* la modif dans la procédure Pixel_Preview_Loupe_SDL. */
{
// if(X-Principal_Decalage_X >= 0 && Y - Principal_Decalage_Y >= 0)
Pixel_SDL(X-Principal_Decalage_X,Y-Principal_Decalage_Y,Couleur);
}
void Pixel_Preview_Loupe_SDL (word X,word Y,byte Couleur)
{
// Affiche le pixel dans la partie non zoomée
Pixel_SDL(X-Principal_Decalage_X,Y-Principal_Decalage_Y,Couleur);
// Regarde si on doit aussi l'afficher dans la partie zoomée
if (Y >= Limite_Haut_Zoom && Y <= Limite_visible_Bas_Zoom
&& X >= Limite_Gauche_Zoom && X <= Limite_visible_Droite_Zoom)
{
// On est dedans
int hauteur;
int Y_Zoom = Table_mul_facteur_zoom[Y-Loupe_Decalage_Y];
if (Menu_Ordonnee - Y_Zoom < Loupe_Facteur)
// On ne doit dessiner qu'un morceau du pixel
// sinon on dépasse sur le menu
hauteur = Menu_Ordonnee - Y_Zoom;
else
hauteur = Loupe_Facteur;
Block_SDL(
Table_mul_facteur_zoom[X-Loupe_Decalage_X]
+ Principal_X_Zoom,
Y_Zoom, Loupe_Facteur, hauteur, Couleur
);
}
}
void Ligne_horizontale_XOR_SDL(word Pos_X,word Pos_Y,word Largeur)
{
//On calcule la valeur initiale de EDI:
byte* edi=Pos_Y*Largeur_ecran+Pos_X+Ecran;
int ecx;
for (ecx=0;ecx<Largeur;ecx++)
*(edi+ecx)=~*(edi+ecx);
}
void Ligne_verticale_XOR_SDL (word Pos_X,word Pos_Y,word Hauteur)
{
int i;
byte color;
for (i=Pos_Y;i<Pos_Y+Hauteur;i++)
{
color=*(Ecran+Pos_X+i*Largeur_ecran);
*(Ecran+Pos_X+i*Largeur_ecran)=~color;
}
}
void Display_brush_Color_SDL (word Pos_X,word Pos_Y,word Decalage_X,word Decalage_Y,word Largeur,word Hauteur,byte Couleur_de_transparence,word Largeur_brosse)
{
// EDI = Position à l'écran
byte* EDI = Ecran + Pos_Y * Largeur_ecran + Pos_X;
// ESI = Position dans la brosse
byte* ESI = Brosse + Decalage_Y * Largeur_brosse + Decalage_X;
word DX,CX;
// Pour chaque ligne
for(DX = Hauteur;DX > 0; DX--)
{
// Pour chaque pixel
for(CX = Largeur;CX > 0; CX--)
{
// On vérifie que ce n'est pas la transparence
if(*ESI != Couleur_de_transparence)
{
*EDI = *ESI;
}
// Pixel suivant
ESI++; EDI++;
}
// On passe à la ligne suivante
EDI = EDI + Largeur_ecran - Largeur;
ESI = ESI + Largeur_brosse - Largeur;
}
UpdateRect(Pos_X,Pos_Y,Largeur,Hauteur);
}
void Display_brush_Mono_SDL (word Pos_X, word Pos_Y,
word Decalage_X, word Decalage_Y, word Largeur, word Hauteur,
byte Couleur_de_transparence, byte Couleur, word Largeur_brosse)
/* On affiche la brosse en monochrome */
{
byte* Dest=Pos_Y*Largeur_ecran+Pos_X+Ecran; // EDI = adr destination à
// l'écran
byte* Src=Largeur_brosse*Decalage_Y+Decalage_X+Brosse; // ESI = adr ds
// la brosse
int dx,cx;
for(dx=Hauteur;dx!=0;dx--)
//Pour chaque ligne
{
for(cx=Largeur;cx!=0;cx--)
//Pour chaque pixel
{
if (*Src!=Couleur_de_transparence)
*Dest=Couleur;
// On passe au pixel suivant
Src++;
Dest++;
}
// On passe à la ligne suivante
Src+=Largeur_brosse-Largeur;
Dest+=Largeur_ecran-Largeur;
}
UpdateRect(Pos_X,Pos_Y,Largeur,Hauteur);
}
void Clear_brush_SDL (word Pos_X,word Pos_Y,word Decalage_X,word Decalage_Y,word Largeur,word Hauteur,byte Couleur_de_transparence,word Largeur_image)
{
byte* Dest=Ecran+Pos_X+Pos_Y*Largeur_ecran; //On va se mettre en 0,0 dans l'écran (EDI)
byte* Src = ( Pos_Y + Principal_Decalage_Y ) * Largeur_image + Pos_X + Principal_Decalage_X + Principal_Ecran; //Coords de départ ds la source (ESI)
int dx;
for(dx=Hauteur;dx!=0;dx--)
// Pour chaque ligne
{
// On fait une copie de la ligne
memcpy(Dest,Src,Largeur);
// On passe à la ligne suivante
Src+=Largeur_image;
Dest+=Largeur_ecran;
}
UpdateRect(Pos_X,Pos_Y,Largeur,Hauteur);
}
void Remap_screen_SDL (word Pos_X,word Pos_Y,word Largeur,word Hauteur,byte * Table_de_conversion)
{
// EDI = coords a l'écran
byte* EDI = Ecran + Pos_Y * Largeur_ecran + Pos_X;
int dx,cx;
// Pour chaque ligne
for(dx=Hauteur;dx>0;dx--)
{
// Pour chaque pixel
for(cx=Largeur;cx>0;cx--)
{
*EDI = Table_de_conversion[*EDI];
EDI ++;
}
EDI = EDI + Largeur_ecran - Largeur;
}
UpdateRect(Pos_X,Pos_Y,Largeur,Hauteur);
}
void Afficher_une_ligne_ecran_SDL (word Pos_X,word Pos_Y,word Largeur,byte * Ligne)
/* On affiche toute une ligne de pixels. Utilisé pour les textes. */
{
memcpy(Ecran+Pos_X+Pos_Y*Largeur_ecran,Ligne,Largeur);
//UpdateRect(Pos_X,Pos_Y,Largeur,1);
}
void Afficher_une_ligne_transparente_mono_a_l_ecran_SDL(
word Pos_X, word Pos_Y, word Largeur, byte* Ligne,
byte Couleur_transparence, byte Couleur)
// Affiche une ligne à l'écran avec une couleur + transparence.
// Utilisé par les brosses en mode zoom
{
byte* Dest = Ecran+ Pos_Y * Largeur_ecran + Pos_X;
int Compteur;
// Pour chaque pixel
for(Compteur=0;Compteur<Largeur;Compteur++)
{
if (Couleur_transparence!=*Ligne)
*Dest = Couleur;
Ligne ++; // Pixel suivant
Dest++;
}
}
void Lire_une_ligne_ecran_SDL (word Pos_X,word Pos_Y,word Largeur,byte * Ligne)
{
memcpy(Ligne,Largeur_ecran * Pos_Y + Pos_X + Ecran,Largeur);
}
void Afficher_partie_de_l_ecran_zoomee_SDL(
word Largeur, // Largeur non zoomée
word Hauteur, // Hauteur zoomée
word Largeur_image,byte * Buffer)
{
byte* ESI = Principal_Ecran + Loupe_Decalage_Y * Largeur_image
+ Loupe_Decalage_X;
int EDX = 0; // Ligne en cours de traitement
// Pour chaque ligne à zoomer
while(1)
{
int CX;
// On éclate la ligne
Zoomer_une_ligne(ESI,Buffer,Loupe_Facteur,Largeur);
// On l'affiche Facteur fois, sur des lignes consécutives
CX = Loupe_Facteur;
// Pour chaque ligne
do{
// On affiche la ligne zoomée
Afficher_une_ligne_ecran_SDL(
Principal_X_Zoom, EDX, Largeur*Loupe_Facteur,
Buffer
);
// On passe à la suivante
EDX++;
if(EDX==Hauteur)
{
UpdateRect(Principal_X_Zoom,0,
Largeur*Loupe_Facteur,Hauteur);
return;
}
CX--;
}while (CX > 0);
ESI += Largeur_image;
}
// ATTENTION on n'arrive jamais ici !
}
void Afficher_une_ligne_transparente_a_l_ecran_SDL(word Pos_X,word Pos_Y,word Largeur,byte* Ligne,byte Couleur_transparence)
{
byte* ESI = Ligne;
byte* EDI = Ecran + Pos_Y * Largeur_ecran + Pos_X;
word cx;
// Pour chaque pixel de la ligne
for(cx = Largeur;cx > 0;cx--)
{
if(*ESI!=Couleur_transparence)
*EDI = *ESI;
ESI++;
EDI++;
}
}
// Affiche une partie de la brosse couleur zoomée
void Display_brush_Color_zoom_SDL (word Pos_X,word Pos_Y,
word Decalage_X,word Decalage_Y,
word Largeur, // Largeur non zoomée
word Pos_Y_Fin,byte Couleur_de_transparence,
word Largeur_brosse, // Largeur réelle de la brosse
byte * Buffer)
{
byte* ESI = Brosse+Decalage_Y*Largeur_brosse + Decalage_X;
word DX = Pos_Y;
byte bx;
// Pour chaque ligne
while(1)
{
Zoomer_une_ligne(ESI,Buffer,Loupe_Facteur,Largeur);
// On affiche facteur fois la ligne zoomée
for(bx=Loupe_Facteur;bx>0;bx--)
{
Afficher_une_ligne_transparente_a_l_ecran_SDL(Pos_X,DX,Largeur*Loupe_Facteur,Buffer,Couleur_de_transparence);
DX++;
if(DX==Pos_Y_Fin)
{
return;
}
}
ESI += Largeur_brosse;
}
// ATTENTION zone jamais atteinte
}
void Display_brush_Mono_zoom_SDL (word Pos_X, word Pos_Y,
word Decalage_X, word Decalage_Y,
word Largeur, // Largeur non zoomée
word Pos_Y_Fin,
byte Couleur_de_transparence, byte Couleur,
word Largeur_brosse, // Largeur réelle de la brosse
byte * Buffer
)
{
byte* ESI = Brosse + Decalage_Y * Largeur_brosse + Decalage_X;
int DX=Pos_Y;
//Pour chaque ligne à zoomer :
while(1)
{
int BX;
// ESI = Ligne originale
// On éclate la ligne
Zoomer_une_ligne(ESI,Buffer,Loupe_Facteur,Largeur);
// On affiche la ligne Facteur fois à l'écran (sur des
// lignes consécutives)
BX = Loupe_Facteur;
// Pour chaque ligne écran
do
{
// On affiche la ligne zoomée
Afficher_une_ligne_transparente_mono_a_l_ecran_SDL(
Pos_X, DX, Largeur * Loupe_Facteur,
Buffer, Couleur_de_transparence, Couleur
);
// On passe à la ligne suivante
DX++;
// On vérifie qu'on est pas à la ligne finale
if(DX == Pos_Y_Fin)
{
UpdateRect( Pos_X, Pos_Y,
Largeur * Loupe_Facteur, Pos_Y_Fin - Pos_Y );
return;
}
BX --;
}
while (BX > 0);
// Passage à la ligne suivante dans la brosse aussi
ESI+=Largeur_brosse;
}
}
void Clear_brush_zoom_SDL (word Pos_X,word Pos_Y,word Decalage_X,word Decalage_Y,word Largeur,word Pos_Y_Fin,__attribute__((unused)) byte Couleur_de_transparence,word Largeur_image,byte * Buffer)
{
// En fait on va recopier l'image non zoomée dans la partie zoomée !
byte* ESI = Principal_Ecran + Decalage_Y * Largeur_image + Decalage_X;
int DX = Pos_Y;
int bx;
// Pour chaque ligne à zoomer
while(1){
Zoomer_une_ligne(ESI,Buffer,Loupe_Facteur,Largeur);
bx=Loupe_Facteur;
// Pour chaque ligne
do{
Afficher_une_ligne_ecran_SDL(Pos_X,DX,
Largeur * Loupe_Facteur,Buffer);
// Ligne suivante
DX++;
if(DX==Pos_Y_Fin)
{
UpdateRect(Pos_X,Pos_Y,
Largeur*Loupe_Facteur,Pos_Y_Fin-Pos_Y);
return;
}
bx--;
}while(bx!=0);
ESI+= Largeur_image;
}
}
void Set_Mode_SDL()
/* On règle la résolution de l'écran */
{
Ecran_SDL=SDL_SetVideoMode(Largeur_ecran,Hauteur_ecran,8,SDL_FULLSCREEN*Plein_ecran|SDL_RESIZABLE);
if(Ecran_SDL != NULL)
{
// Vérification du mode obtenu (ce n'est pas toujours celui demandé)
if (Ecran_SDL->w != Largeur_ecran || Ecran_SDL->h != Hauteur_ecran)
{
DEBUG("Erreur mode video obtenu différent de celui demandé !!",0);
Largeur_ecran = Ecran_SDL->w;
Hauteur_ecran = Ecran_SDL->h;
}
Ecran=Ecran_SDL->pixels;
}
else
DEBUG("Erreur changement de mode video !!",0);
SDL_ShowCursor(0); // Cache le curseur SDL, on le gère en soft
}
// Fonction qui filtre les evenements génériques.
void Gere_Evenement_SDL(SDL_Event * event)
{
// Redimensionnement fenetre
if (event->type == SDL_VIDEORESIZE )
{
Resize_Largeur = event->resize.w;
Resize_Hauteur = event->resize.h;
}
// Fermeture
if (event->type == SDL_QUIT )
{
Quit_demande=1;
}
}
#if (METHODE_UPDATE == METHODE_UPDATE_PAR_CUMUL)
short Min_X=0;
short Min_Y=0;
short Max_X=10000;
short Max_Y=10000;
#endif
#if (METHODE_UPDATE == METHODE_UPDATE_PLEINE_PAGE)
int Update_necessaire=0;
#endif
void Flush_update(void)
{
#if (METHODE_UPDATE == METHODE_UPDATE_PLEINE_PAGE)
// Mise à jour de la totalité de l'écran
if (Update_necessaire)
{
SDL_UpdateRect(Ecran_SDL, 0, 0, 0, 0);
Update_necessaire=0;
}
#endif
#if (METHODE_UPDATE == METHODE_UPDATE_PAR_CUMUL)
if (Min_X>=Max_X || Min_Y>=Max_Y)
{
; // Rien a faire
}
else
{
SDL_UpdateRect(Ecran_SDL, Max(Min_X,0), Max(Min_Y,0), Min(Largeur_ecran, Max_X-Min_X), Min(Hauteur_ecran, Max_Y-Min_Y));
Min_X=Min_Y=10000;
Max_X=Max_Y=0;
}
#endif
}
void UpdateRect(short X, short Y, unsigned short Largeur, unsigned short Hauteur)
{
#if (METHODE_UPDATE == METHODE_UPDATE_MULTI_RECTANGLE)
SDL_UpdateRect(Ecran_SDL, (X), (Y), (Largeur), (Hauteur));
#endif
#if (METHODE_UPDATE == METHODE_UPDATE_PAR_CUMUL)
if (Largeur==0 || Hauteur==0)
{
Min_X=Min_Y=0;
Max_X=Max_Y=10000;
}
else
{
if (X < Min_X)
Min_X = X;
if (Y < Min_Y)
Min_Y = Y;
if (X+Largeur>Max_X)
Max_X=X+Largeur;
if (Y+Hauteur>Max_Y)
Max_Y=Y+Hauteur;
}
#endif
#if (METHODE_UPDATE == METHODE_UPDATE_PLEINE_PAGE)
Update_necessaire=1;
#endif
}
// Convertit une SDL_Surface (couleurs indexées ou RGB) en tableau de bytes (couleurs indexées)
// Si on passe NULL comme destination, elle est allouée par malloc(). Sinon,
// attention aux dimensions!
byte * Surface_en_bytefield(SDL_Surface *Source, byte * Destination)
{
byte *Src;
byte *Dst;
int Y;
int Reste;
// Support seulement des images 256 couleurs
if (Source->format->BytesPerPixel != 1)
return NULL;
if (Source->w & 3)
Reste=4-(Source->w&3);
else
Reste=0;
if (Destination==NULL)
Destination=(byte *)malloc(Source->w*Source->h);
Dst=Destination;
Src=(byte *)(Source->pixels);
for(Y=0; Y < Source->h; Y++)
{
memcpy(Dst, Src,Source->w);
Dst += Source->w;
Src += Source->w + Reste;
}
return Destination;
}
// Convertit un index de palette en couleur RGB 24 bits
SDL_Color Conversion_couleur_SDL(byte Index)
{
SDL_Color Couleur;
Couleur.r = (Principal_Palette[Index].R<<2) + (Principal_Palette[Index].R>>4);
Couleur.g = (Principal_Palette[Index].V<<2) + (Principal_Palette[Index].V>>4);
Couleur.b = (Principal_Palette[Index].B<<2) + (Principal_Palette[Index].B>>4);
Couleur.unused = 255;
return Couleur;
}