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:11257
    Visiteurs aujourd'hui:8
     
     
    Me contacter
    Donnez votre avis
     
    Le site de Steph : Le CPC

    Animation par Sprite


    Pour faire une animation par sprite, le plus compliqué c'est presque de faire les spirtes :-)
    Au niveau du code, il n'y a rien de "très" compliqué, du chargement, de l'affichage... et pour afficher un sprite vous avez l’embarras du choix sur le net au niveau des routines !!
    Dans l'exemple que j'ai pris, j'utilise un "grand" sprite, celui ci fait 40x98, oui quand même, il faut donc trouver une fonction pour afficher le sprite qui soit suffisamment rapide.
    Il faut bien préparé ses sprite, vue l'architecture de la mémoire écran du CPC, on ne peut pas trop faire n'importe comment, il faut faire des fichiers image dit linéaire, en fait on ne crée un fichier avec les sprite les un au dessus des autres, de façon à les placer en mémoire pour pouvoir les trouver rapidement, on y reviendras.
    Pour afficher un sprite, voici une fonction en C, mais je vous dis tout de suite, on ne l’utilisera pas car elle n'est pas suffisamment rapide (du moins pour un gros sprite !) :
    void PutSpriteMode0(unsigned char *pSprite, unsigned char nX, unsigned char nY, unsigned char nWidth, unsigned char nHeight)
    {
      unsigned char nXPos = 0;
      unsigned char nYPos = 0;
      unsigned char *pAddress = 0;
      
      for(nYPos = 0; nYPos < nHeight; nYPos++)
      {
        pAddress = (unsigned char *)(0xC000 + ((nY / 8u) * 80u) + ((nY % 8u) * 2048u) + nX);
    
        for(nXPos = 0; nXPos < nWidth; nXPos++)
          *pAddress++ = *pSprite++;
    
        nY++;
      }
    }
    

    On y passe l'adresse du sprite a copier, la position ou copier le sprite à l'écran, et la taille du sprite, ensuite, c'est une simple copie d'octets en mémoire vidéo ...
    Cette fonction est déjà optimisable, on peut directement passer l'adresse de destination en mémoire vidéo, cela évite de la calculer, pour sauter une ligne il suffiras de décaler d'une ligne cette adresse à chaque boucle.

    Bon, passons directement à ce que j'ai choisi comme exemple, je suis partis de ce GIF animé, il est bien cyclique fait 20 images et à la mode au moment de le faire, effectivement ce "truc" on en bouffe pas mal, c'est à la mode, c'est bien con, ...
    On se fait une anim de GamGamStyle :-) celle ci :



    Bien sur on ne vas pas la garder telle quelle, elle est bien trop grosse pour notre CPC, on ne vas garder que la dense, le reste on retire, et on réduit le nombre de couleur à 16, ce qui donne cela :



    OK, mais la cela ne vas pas encore pour notre CPC, si on la garde comme cela, elle fait 117x194, on ne pourras pas l'afficher facilement. On va donc la réduire encore un peut comme ceci :



    Voile, on a la base pour notre animation, se serai tellement simple si avec le CPC on pouvais lire les GIF animé, mais non, c'est pas trop possible, disons que le dev serais bien prise de tête ;-)
    On vas donc prendre les 20 images et en faire une planche de sprite, mais si l'on fait comme cela :



    On ne vas pas pouvoir les afficher de façon rapide, pourquoi ?
    si on veut afficher le 1er sprite, il nous faut prendre les 40 premier point et pour prendre la ligne suivante du 1er sprite, faire un saut d'une ligne, pas pratique et en plus cela fait un calcule de plus pendant la copie.
    On vas organiser nos sprites les un au dessus des autres.
    Je vous explique comment j'ai procédé, il y a bien sur d'autre méthodes, plus simple, moins simple, plus rapide, moins rapide, le principale c'est d'y arriver !
    J'ai commencé par sauver chaque image de l'animation en un fichier BMP (pourquoi le choix du BMP ? car le soft suivant sais les lire, et que le JPG à une perte de qualité due à la compression !!).
    La il nous faut un logiciel qui vas nous permettre de mettre les 20 images les une au dessus des autres, on pourrait faire cela avec GIMP par exemple, mais le fichier obtenu ferais 40x1960, et je ne connais aucun logiciel pour convertir cette image au format CPC (cela existe peut être !). on vas donc procédé différemment :
    Avec ConvImgCpc on peut faire en sorte de créer pour chaque image un fichier .scr, avec la bonne taille, OK, mais avec cette méthode il faut ensuite charger 20 fichier (bon, ok, on peut en mettre 2 par fichier, cela fait quand même 10 fichier !), une option de ConvImgCpc permet de sauver notre image au forma ASM, on vas utiliser cette fonction pour nos 20 images.



    Donc, on a mis les bonnes valeurs pour la taille de l'image 80x198 (oui 2 fois la taille de notre image de départ) puis pour la taille de l'image sur CPC soit 98 lignes et 10 colonnes, coché les cases "linaire" (oui, on veut que la ligne 2 soit juste après la ligne 1 et non 8 linges plus bas (la il faut chercher comment fonctionne l’affichage sur CPC)) et "Mode asm" pour sauver un fichier .ASM et non .SCR (à ce propos, si vous utiliser la fonction Batch de ConvImgCpc, les fichier sauver auront l'extension .SCR mais seront au format ASM, petit bug de la version 0.16 !), une fois fait cela on se retrouve avec 20 fichiers .ASM.
    Le but est de les assembler (au sans programmation, avec un assembleur) mais on ne vas pas assembler 20 fichier, on vas assembler (au sans mécanique, coller) les 20 fichiers pour n'en faire qu'un seul.
    On va faire cela avec une tit commande dos ! Pour coller les 20 fichiers entre eux, on va fraie la commande suivante sous dos : type *.asm > ggsdata.a
    Explication rapide, la commande type affiche le contenue d'un fichier à l'écran, la *.asm vas afficher TOUT les fichiers d'extension .asm à l'écran. le > permet de rediriger la sortie écran vers un fichier, ce qui nous intéresse car on veut mettre tous les fichier .asm dans un seul. Notez que le fichier résultat n'a pas l'extension .asm, c'est voulu et même il ne faut surtout pas la mettre, sinon votre fichier final ne serais pas bon puisque vous vous retrouveriez avec 2 fois les fichiers dans votre fichier finale ... oui type remettrais le fichier final .asm dan lui même !!!!
    Ensuite renommer ggsdata.a en ggsdata.asm.
    Il faut l'assembler (au sans développement !) maintenant, on va utiliser WinApe, il y a une fonction pour assembler un fichier dans l'émulateur ce qui nous vas bien. Mais il faut pouvoir sauver le fichier sur notre PC, la plusieurs solution, la mienne (une fois de plus il y a plusieurs façon de faire) on ajoute au fichier ggsdata.asm ceci :
    	write "ggsdata0.bin"
    	
    	org &1000
    
    La ligne write "ggsdata0.bin" permet à WinApe de sauver le fichier binaire sur le disque du PC, et org &1000 c'est le début de compilation en mémoire CPC (pour nous pas grand intérêt, ce n'est pas du code mais il faut quand même que WinApe le compile en mémoire CPC !)
    Et c'est fini .... et bien non, la notre fichier binaire est prêt, mais si on l'utilise comme cela, le CPC ne pourras pas le charger, c'est un fichier binaire et sur CPC les fichier binaire on une entête !, On vas donc la créer.
    Pour cela j'utilise le logiciel ManageDsk, on crée une nouvelle disquette, on drag and drop notre fichier et on entre les infos pour l'entête :



    Puis on exporte notre fichier sur le disque du PC. Il n'est pas utile de sauver la disquette !!.

    Notre fichier est bon maintenant, il ne nous reste plus qu'a passer au code :-)

    Je vous met ici juste les fonctions nouvelles et le main, tout le reste est dans le ZIP final.
    La fonction de copie du sprite, j'ai réutilisé celle fait par CPCMANIA dans sont tuto sur les sprite, rien de bien spéciale, on en trouve plein sur le net.
    J'ai ajouter une tit fonction pour récupérer si une touche est pressé sur le clavier, elle fait simplement appel à la fonction 0xBB09 du firmware.
    La fonction WaitVbl permet d'attendre que le signal du balayage de l'écran soit arrivé à sa position de départ, elle sert aussi de tempo pour l'animation.
    Pour le main, on initialise les pointeurs, charge l'image, met les bonne couleur, le mode 0, et on fait l'animation... on se sert juste de WaitVbl pour faire une tempo, on attend 3 images avant de changer le sprite.
    Place au code :

    void WaitVbl()
    {
    __asm
            ld b,#0xF5          ; On selectionne le Port B du PPI
    _Synchro: in a,(c)          ; On pique son contenu
            rra               ; On teste si le Bit0=1
            jp nc,_Synchro    ; Si Bit0=0 alors on attend la fin
                              ; du balayage
    __endasm;
    }
    
    char nGetChar;
    char GetChar()
    {
      __asm
        LD HL, #_nGetChar
        LD (HL), #0
        CALL #0xBB09 ;KM READ CHAR
        JP NC, _end_getchar
        LD (HL), A
        _end_getchar:
      __endasm;
      
      return nGetChar;
    }
    
    void PutSpriteMode0(unsigned char *pAddress, unsigned char nWidth, unsigned char nHeight, unsigned char *pSprite)
    {
    	__asm
    		LD L, 4(IX)   ; adr ecran
    		LD H, 5(IX) 
    		LD C, 6(IX)   ; Largeur
    		LD B, 7(IX)   ; hauteur         
    		LD E, 8(IX)   ; adr du sprite
    		LD D, 9(IX) 
    
    		_loop_alto:
    		   PUSH BC
    		   LD B,C
    		   PUSH HL
    		_loop_ancho:
    		   LD A,(DE)
    		   LD (HL),A
    		   INC DE
    		   INC HL
    		   DJNZ _loop_ancho
    		   POP HL
    		   LD A,H
    		   ADD #0x08
    		   LD H,A
    		   SUB #0xC0
    		   JP NC, _sig_linea
    		   LD BC, #0xC050
    		   ADD HL,BC
    		_sig_linea:
    		   POP BC
    		   DJNZ _loop_alto
    	__endasm;
    }
    
    void main()
    {
    	unsigned char CurSprite = 0;
    	char nChar;
    	unsigned char *TabpAddspr[20];
    	unsigned char i;
    	
    	// l'adresse de dépar sur l'ecan est toujour la même, la on la calcule mais on c'est pas très util !
    	// on l'affiche à peut près centré dans l'écra,n.
    	// le sprite fait 40*98
    	// (160-40) / 2 = 50 en X
    	// (200 - 98) / 2 = 51 en Y
    	unsigned char *pAddress = (unsigned char *)((unsigned int)(0xC000 + ((50 / 8) * 80) + ((50 % 8) * 2048) + (150 / 4)));
    
    	// chargement des data pour images.
    	// Le fichier est de type binaire, data sprite linaire
    	// on les charge à partir de 1000 à bFFF
    	ReadFileBin( "ggsdata.bin", 0x1000);
    
        //SCR_SET_MODE 0
        SCR_SET_MODE0_s;
    	
    	// initalisation du tableau des adresse de sprite
    	for (i = 0; i < 20; i++)
    	{
    		TabpAddspr[i] = (unsigned char *)((unsigned int)(i*(10*98) + 0x1000) );
    	}
    	
    	// on met les couleurs.
    	SetColor_s(0,26);
    	SetColor_s(1,0);
    	SetColor_s(2,13);
    	SetColor_s(3,4);
    	SetColor_s(4,12);
    	SetColor_s(5,16);
    	SetColor_s(6,25);
    	SetColor_s(7,10);
    	SetColor_s(8,3);
    	SetColor_s(9,14);
    	SetColor_s(10,1);
    	SetColor_s(11,23);
    	SetColor_s(12,11);
    	SetColor_s(13,2);
    	SetColor_s(14,5);
    	SetColor_s(15,6);
    	
    	// on fait l'animation.
    	while( 1 )
    	{
    		nChar = GetChar();
    		if ( nChar != 0 )
    			break;
    	
    		if ( CurSprite > 19 )
    			CurSprite = 0;
    		
    		// pous eviter le cliping, on attent la prochaine image		
    		WaitVbl();
    		
    		// on copie le sprite à l'écran
    		// le sprite fait 40*98 donc 10 colonnes et 98 lignes.
    		PutSpriteMode0( pAddress, 10, 98, (unsigned char *)TabpAddspr[CurSprite] );
    
    		CurSprite++;
    
    		// attente de 3 image avant de continuer
    		WaitVbl();
    		WaitVbl();
    		WaitVbl();
    	}
    }
    

    Et voile ce que cela donne :



    Cela ne rend pas trop mal :-)
    Il ya tout de même un petit problème de cliping parfois....

    Voila, comme d'hab, le tout se trouve dans se ZIP, bonne animation :-)
    Je vous met aussi un autre ZIP, avec les fichiers images utilisé pour l'animation.