Accueil

CPC


 Dev C sur CPC :

  • le C sur CPC
  • SDCC débuter
  • fichier BAT pour compiler
  • Dessiner Sur CPC
  • Optimiser le dessin
  • Ecrire du texte
  • Lire un fichier
  • Ecrire un fichier
  • Swap d'écran
  • CLS ultra rapide
  • H line
  • Attaquer le CRTC
  • Full Overscan
  • Put pixel très rapide
  • Afficher une image
  • Slide show 1
  • Bézier
  • faire un fichier pour Bézier

  • Quelque fonctions utile

  • Animation
  • 3D
  • Raster
  • Manche a balais

    Le plan du Site

  •  
      Ici les nouvelle du site  
     
    Recherche ?
    Saissisez un mot clé

     
      Quelques chiffres
    Visiteurs:4526
    Visiteurs aujourd'hui:2
     
     
    Me contacter
    Donnez votre avis
     
    Le site de Steph : Le CPC

    Bézier


    Mais pourquoi les courbe de bézier, en fait c'est en regardans une vidéo sur Youtube que je me suis demadé comment réaliser cela sur CPC, une vidéo c'est pas la peinne d'y pensé, des sprites c'est bien trop compliqué, en fait comme se sont des dessins, c'est une suite de trais, donc de courbe ...
    Bézier, a ne pas confondre avec une belle ville de l'Hérault, ici on vas parler de courbes, les courbes de Bézier, c'est Pierre Bézier ingénieur français en mécanique et électricité qui les inventa les courbes et surfaces de Bézier.
    Donc pour tout savoire sur ces courbes (et surface) allez faire un tour sur wikipedia. Du restre le début de ce code commence avec un code récupéré sur wikibooks (Courbe de Bézier en C) donc voici le source :
    typedef struct {
            float x, y;
     } point;
    
     typedef struct {
           point P[4];
     } Bezier;
    
     /* Variables globales */
     Bezier Global_Bezier;
     int level=1;
    
     // Draw a line with color (r,v,b)
     void DrawLine(int x1, int y1, int x2, int y2,float r, float v, float b)
     {
    	ICI LE CODE POUR DESSINER UNE LIGNE !
     }
    
     void DrawBezierBase(Bezier p,float r,float v,float b)
     {
       DrawLine(p.P[0].x,p.P[0].y,p.P[1].x,p.P[1].y,r,v,b);
       DrawLine(p.P[1].x,p.P[1].y,p.P[2].x,p.P[2].y,r,v,b);
       DrawLine(p.P[2].x,p.P[2].y,p.P[3].x,p.P[3].y,r,v,b);
     }
    
     void DrawBezierRecursive (Bezier b, int level) 
     {
             if (level <= 0) {
              /* draw a line segment */
                   DrawLine((int) (b.P[0].x + 0.5), (int) (b.P[0].y + 0.5),
                                   (int) (b.P[3].x + 0.5), (int) (b.P[3].y + 0.5),1,1,1);
             } else {
                     Bezier left, right;                 
                     /* subdivide into 2 Bezier segments */
                     left.P[0].x = b.P[0].x;
                     left.P[0].y = b.P[0].y;
                     left.P[1].x = (b.P[0].x + b.P[1].x) / 2;
                     left.P[1].y = (b.P[0].y + b.P[1].y) / 2;
                     left.P[2].x = (b.P[0].x + 2*b.P[1].x + b.P[2].x) / 4;
                     left.P[2].y = (b.P[0].y + 2*b.P[1].y + b.P[2].y) / 4;
                     left.P[3].x = (b.P[0].x + 3*b.P[1].x + 3*b.P[2].x + b.P[3].x) / 8;
                     left.P[3].y = (b.P[0].y + 3*b.P[1].y + 3*b.P[2].y + b.P[3].y) / 8;
                     DrawBezierBase(left,0,1,0);
                     right.P[0].x = left.P[3].x;
                     right.P[0].y = left.P[3].y;
                     right.P[1].x = (b.P[1].x + 2*b.P[2].x + b.P[3].x) / 4;
                     right.P[1].y = (b.P[1].y + 2*b.P[2].y + b.P[3].y) / 4;
                     right.P[2].x = (b.P[2].x + b.P[3].x) / 2;
                     right.P[2].y = (b.P[2].y + b.P[3].y) / 2;
                     right.P[3].x = b.P[3].x;
                     right.P[3].y = b.P[3].y;
                     DrawBezierBase(right,0,0,1);
                     /* draw the 2 segments recursively */
                     DrawBezierRecursive (left, level -1);
                     DrawBezierRecursive (right, level -1);
             }
     }
    
     void DrawBezier()
     {
           DrawBezierBase(Global_Bezier,1,0,0);
           DrawBezierRecursive(Global_Bezier,level);
     }
    

    On pourrais prendre se source presque tel quel pour notre programme sur CPC, la seule choses c'est qu'il ne serais pas bien rapide, en effet il utilise les float, et sur CPC (8 bit en plus) leur utilisation est très, très voire même très lante...
    On vas les remplacer par un int qui vas bien plus vite. J'en voie déja qui vont me dire que l'on vas perdre en présision, oui c'est sur, mais bon pas temps que cela en fait, avec la résolution du CPC on peut se le permettre sans grande perte.
    La fonction DrawBezierBase ne nous intérese pas, elle permet de dessiner les droite de construction de la courbe, donc on retir.
    Autre "optimisation" on va changer tous les division par 2,4 ou 8 par des décalages, cela nous est possible car nous travaillon avec des entier désormé. Du reste au moment de l'appel de la fonction DrawLine il y a une addition de 0.5, on la retir, on travaille avec des entier !
    Donc voici le code que l'on auras pour le CPC :
    typedef struct
    {
    	int x;
    	int y;
    } point;
    
    typedef struct
    {
    	point P[4];
    } Bezier; 
    
    
    // Variables globales
    Bezier* Global_Bezier;
    int level;
    
    
    void DrawBezierRecursive (Bezier* b, int level) 
    {
    	if (level <= 0)
    	{
    		// draw a line segment
    		lineBresenham ((unsigned int) (b->P[0].x), (unsigned char) (b->P[0].y), (unsigned int) (b->P[3].x), (unsigned char) (b->P[3].y), 1);
    	}
    	else
    	{
    		Bezier left;
    		Bezier right;
    		
    		// subdivide into 2 Bezier segments
    		left.P[0].x = b->P[0].x;
    		left.P[0].y = b->P[0].y;
    		left.P[1].x = (b->P[0].x + b->P[1].x) >> 1;
    		left.P[1].y = (b->P[0].y + b->P[1].y) >> 1;
    		left.P[2].x = (b->P[0].x + 2*b->P[1].x + b->P[2].x) >> 2;
    		left.P[2].y = (b->P[0].y + 2*b->P[1].y + b->P[2].y) >> 2;
    		left.P[3].x = (b->P[0].x + 3*b->P[1].x + 3*b->P[2].x + b->P[3].x) >> 3;
    		left.P[3].y = (b->P[0].y + 3*b->P[1].y + 3*b->P[2].y + b->P[3].y) >> 3;
    		
    		right.P[0].x = left.P[3].x;
    		right.P[0].y = left.P[3].y;
    		right.P[1].x = (b->P[1].x + 2*b->P[2].x + b->P[3].x) >> 2;
    		right.P[1].y = (b->P[1].y + 2*b->P[2].y + b->P[3].y) >> 2;
    		right.P[2].x = (b->P[2].x + b->P[3].x) >> 1;
    		right.P[2].y = (b->P[2].y + b->P[3].y) >> 1;
    		right.P[3].x = b->P[3].x;
    		right.P[3].y = b->P[3].y;
    
    		// Dessin les deux segment de facon recurcive
    		DrawBezierRecursive (&left, level -1);
    		DrawBezierRecursive (&right, level -1);
    	}
    }
    

    Il nous suffit de rajouter les fonctions lineBresenham, PutPixelFastMode1 et SetPenM1 pour que notre programme soit bon.
    Il ne nous suffit plus que de remplir une structure Bezier avec le point de départ, les 2 points de controle et le point d'arrivé et cela se desineras à l'écran.
    C'est le sources que vous trouverez nomé Bezier0.C (et .BIN), a vous de tester, voici ce que cela donne :

    Cela fonctionne, maintenent pour faire des dessin un peut plus sofistiqué c'est pas pratique, le mieux serais de mettre les point dans un fichier...
    Ok, on y vas alors. J'ai choisi en fait de faire un fichier qui mapais la structure Bezier, donc on trouveras une suite de 8 word qui représentent une structure, puis une autre, puis ...
    Comme cela il n'y a plus qu'a mettre se fichier en mémoire décaler un pointeur, ce qui demade aucune modification du code, on a même plus besion (pour le moment) de la déclaration de la structure Bezier, mais il nous faut ajouter le fonction de lecture d'un fichier et modifier le main :

    void main()
    {
    	int i;
    	
    	SCR_SET_MODE1_s;
    	level = 3;
    
    	gotoxy(1,1);printf("Ligne de Bezier en MODE 1");
    	gotoxy(1,2);printf("Petite demo de presentation");
    	gotoxy(1,15);printf("Une touche pour commancer...");
    	KM_WAIT_CHAR_s;
    	SCR_SET_MODE1_s; // pour effacer l'ecran...
    	
    	ReadFileBin("D2data.bin", 0x4000);
    
    	for (i = 0; i < 89; i++)
    	{
    		DrawBezierRecursive( (0x4000 + (i * 16)), level);
    	}	
    
    	gotoxy(1,24);printf("FIN (une touche)");KM_WAIT_CHAR_s;
    
    }
    

    On charge le fichier en 0x4000 puis on cacile l'adresse de chaque structure en mémoire et on affiche.
    Le tout se trouve dans le fichier Bezier1.c Voila ce que cela donne :

    L'animation est fidèle en temps vis à vis d'un CPC


    Pour faire les fichiers que l'on chargeras, c'est a la mano, je vous propose cette article pour les faires.

    Cela donne déja pas mal, mais en premier j'aimerais bien faire une petite pause à un moment du dessin, voire changer de couleur, ou d'autre choses. En second, il faut en fait pour chaque fichier faire un code spécial pour le nombre de courbe a dessiner, on vas donc mette une petite entête (a nous) au fichier, qui contiendras le nombre de point, le mode écran (la pour la suite on contiue avec le mode 1, il faut mettre les autres fonctions de dessin pour les autres mode). Et pour le 1er point je vais ajouter une structure pour des commandes (changement de couleurs, ...).

    // Entête du fichier de data ...
    // !!!!!!!!!!!!!!!!!!!!!
    // Attention, elle doit avoir la même longueur que la structure Bezier !!!
    typedef struct
    {
    	int NbPoint;	// nombre de points dans le fichier, c'est le nombre de structure Bezier présente dans le fichier
    					// s'il y a des commandes, elle compte pour une structure Bezier !!
    					// mais l'entête ne compte pas !!!
    	int Mode;   	// mode graphique 0, 1, 2
    	int Ver;		// version (pour le moment 1)
    	int Empty4;
    	int Empty3;		// Word d'ont on ne tien pas compte pour le moment
    	int Empty2;		// cela permet d'avoir la même taille que la structure Bezier
    	int Empty1;
    	int Empty0;
    } FileHeader; 
    
    // structure pour les commandes
    // !!!!!!!!!!!!!!!!!!!!!
    // Attention, elle doit avoir la même longeur que la structure Bezier !!!
    typedef struct
    {
    	int IndicCmd;	// indique que c'est une commande, toujours 0xFFFF comme valeur
    	int CmdVersion;	// pour le moment valeur 1
    	int CMD;		//  commande en elle même
    	int CmdVal;		// valeur asocié à la commande
    	int Empty3;		// Word d'ont on ne tien pas compte pour le moment
    	int Empty2;		// cela permet d'avoir la même taille que la structure Bezier
    	int Empty1;
    	int Empty0;
    	
    } Commande; 
    

    Ces deux structures n'ont rien de bien spéciale, sauf qu'elles ont à la même longreur que la structure Bezier. A se sujet, j'aurais put ajouter simplement à la structure bezier un octer ou un word pour la couleur, je n'est pas choisi cette solution, car on ne vas pas changer de couleur pour chaque ligne (quoi que) mais surtout cela prend un peut plus de place en méoire !

    Vous verrez leur utilisation dans le fichier bezier2.c
    Il y a un petit soucie dans se fichier, pour effacer l'ecran j'utilise la fonction système 0xBBDB, ce qui peut entrainer des problèmes, cela fait repartir la boucle FOR à 0 une fois ce vecteur système appelé. J'ai corrigé se problème dans le fichier bezier3.c en utilisant ma fonction CLS_WithPile().

    Voila, dans le ZIP il y a une disquette (Bezier3) avec une petite demos de 9 dessins, se sont les dessin de la vidéo du début d'article, plus une autre image, comme d'habitude je vous rapelle que je ne suis pas un graphiste super calé, donc mes dessins sont ce qu'il son ;-)
    Si vous souhaitez faire des dessins, n'ésitez pas ... :-)

    Voila, comme d'hab, le tout se trouve dans se ZIP, bonne écriture ;-)