CODING ★ CREATION ANIMATIONS GRAPHIQUES ★

Graphic - 09 - Creation Animations Graphiques - Animation Pixels et Case Par Case|SOS Programmeurs)

Tout d'abord , un certain nombre  de  lettres  nous ont informés que vous  futes  quelque  peu  perturbés  par  les  explications  du  dernier  chapitre concernant les transferts écran , buffer  ,  sprite  . Un traitement de texte  n'est peut-être pas l'outil idéal  pour  montrer  un procédé graphique ! Pour  commencer , nous vous offrons donc 2 pages écran :


 La première vous montre  point  par  point  comment  on recopie les zones  concernées et comment on compose le  buffer  sprite . La seconde vous dévoile  point par point les opérations  à  accomplir  pour  un déplacement à gauche .  (Pour les autres déplacements ,  le  principe  et l'ordre des opérations sont  identiques , seuls  les  calculs  assembleur  changent)  .  Reprenez  donc le  dernier chapitre de SOS5 et relisez le  avec  les images sous les yeux , cela  ira sans doute mieux ! Si  ce  n'est  déjà  fait  , intéréssez vous aussi aux  cours d'assembleur qui  est  essentiellement  dédié  aux  opérations  sur les  masques et rotations que l'on utilise en permanence ici .

Ceci fait , vous comprendrez sans doute mieux ce cours qui n'en reste pas  moins fort complexe . La première notion à  retenir est que l'on ne peut à la  fois faire simple et de bonne qualité  et qu'à l'opposé des animations nulles  mais simples de SOS5 , nous présentons ici 2 versions d'une même routine dont  la qualité professionnelle ne manquera pas de vous surprendre .

A partir de maintenant , nous n'utilisons plus que le mode 0 , c'est plus  joli , plus rapide et  cela  raccourcit  les  listings  ! Tous nos programmes  pourront être aisément adaptés en MODE 1 car les routines de composition , de  rotations , etc ... Sont directement  inspirées voire identiques aux routines  décrites dans SOS5 , il suffit  donc  de modifier en conséquence les sections  concernées .

----------------------------------------------
- ANIMATION PIXELS PAR PIXELS ET CASE PAR CASE -
----------------------------------------------

Le premier procédé est assez lent  et  ne  convient pas vraiment à un jeu  d'arcade rapide . En revanche ,  pour  un  programme  de  DAO , PAO , Etc ...
C'est ce qu'il y-à de mieux et c'est par la que nous commençons .

Ce n'est guère plus compliqué que les principes décrits dans SOS5 , il y- à seulement une variable supplémentaire à prendre en compte : LE MASQUE !

 Il y-à plusieurs pixels dans un octet mémoire (2  , 4 , 8 pour MODE 0 , 1  , 2) . Si l'on désire une animation  pixel  par pixel , on ne changera pas de  case écran à chaque tour de boucle ! Il faudra dans le cas d'un déplacement à  gauche , attendre que le pixel  le  plus  à  gauche  du sprite ait atteint la  dernière position possible dans la case  mémoire en cours et inversement pour  aller à droite . Ex :
 

!   +***!***+***!   +   !
!---+---!---+---!---+---!


Si on considère les *** comme étant un pixel  , on voit que dans ce cas , un mouvement  à  droite  va  vider  la  case  la  plus  à  gauche  et occuper  partiellement la plus a droite pour donner :
 

!   +   !***+***!***+   !
!---+---!---+---!---+---!


L'adresse d'affichage du dessin va donc augmenter d'une case .

En revanche , si on se déplace  à  gauche , le dessin reste à l'intérieur  des me^mes cases mémoire et l'adresse d'affichage n'a pas à être modifiée .
 

!***+***!***+   !   +   !
!---+---!---+---!---+---!


 C'est l'octet MASQUE qui renseignera  en  permanence le programme sur cet  état de choses : En MODE 0 l'octet masque sera : %10101010

On prend comme convention  que  la  valeur  %10101010 correspond au pixel  le plus à gauche du dessin situé dans  la  partie la plus à gauche de la case  mémoire . (Dans ce cas on dit qu'il est en position PAIRE) . Cela nous donne:
 

!***+***!***+   !   +   ! MASQUE = %10101010
!---+---!---+---!---+---!


A CHAQUE déplacement latéral ,  la  première opération consistera à faire  tourner le masque dans  le  sens  du  déplacement  (RLCA  à  gauche et RRCA à  droite) , ce qui nous mettra  ou  non  le  CARRY  une fois sur deux pour deux  pixels . Dans notre exemple , CARRY mis signifie que l'on a besoin de décaler  d'une case écran pour le mouvement et non  mis signifie que l'on se déplace à  l'intérieur des mêmes case (dit position IMPAIRE) .

Si vous voulez obtenir le même résultat em MODE 1 avec les mêmes routines  , comme il y-à 4 pixels par cases  ,  le  CARRY ne devra plus être mis qu'une  fois sur 4 et le MASQUE sera : %10001000

En mode 2 : MASQUE = %10000000 pour 8 pixels .

L'animation pixel par pixel  entraîne  aussi une conséquence fondamentale  sur le buffer ou l'on recopie le sprite !

!***+***!***+***!
!---+---!---+---!

Si le buffer est exactement  de  la  même  taille  que  le sprite , on ne  pourra pas se déplacer pixel par pixel , il manque une case pour y parvenir !  Il faut donc absolument  ajouter  une  case  de  plus  par  ligne de sprite a  'bufferiser' pour  obtenir  le  résultat  voulu  !  Et  on  aura  2  routines différentes : La première dans le cas  ou  le  dessin est bien centré sur les  cases mémoires (PAIR) qui se contente  de  recopier  le sprite tel quel et de  mettre à 0 cette case supplémentaire  ,  la  seconde activée par une position  IMPAIRE qui devra recopier le sprite  en  décalant tous les pixels suivant le  MASQUE . Ceci ne concerne  que  les  déplacements latéraux , les déplacements  verticaux sont invariables quelque soit le mode écran .

Voilà une bonne chose de faite ! Le second point particulier du programme réside dans sa possibilité d'afficher en plan  moyen . Comme nous l'avons dit dans SOS5 , un affichage en plan moyen n'est autre qu'un affichage en arrière plan sélectif . On teste donc les  pixels  interdits 1 par 1 (Pour déterminer  les valeurs de ceux-ci , on aura bien  besoin de PIXELMAP ou PIXANAL) au lieu de tester un pixel <> de PEN 0  .  Une  dernière fois , souvenez vous que les couleurs on s'en tape! On ne s'occupe que des numéros de PEN et rien d'autre!

Au passage , nous avons utilisé  une petite plaisanterie pour initialiser l'adresse d'affichage qui n'est qu'un  simple  prétexte pour montrer l'emploi de la routine système &BC1D : Vous  donnez  dans DE et HL les coordonnées x,y  d'un point écran , et vous recevez  en  retour l'adresse écran de ce point et  aussi l'octet MASQUE . Seul  petit  détail  ,  il  faut  rectifier  x et y en fonction des possibilités physiques de l'écran (Voir SOS5) .

A savoir :

y=y/2 Dans tous les modes pour 200 lignes utilisées sur 400
x=x/4 Pour MODE 0
x=x/2 Pour MODE 1
x ne change pas en MODE 2


     Avant d'appeler &BC1D .
     Ci dessous , extrait du listing d'animation proposé à la fin du cours .
 

 ;
 CONVER  LD HL,(YPOS)  ;Coordonnèes plot basic
         ;LD DE,(XPOS)
 CONV1   SRL H         ;;Diviser HL par 2
         ;RR L
         ;PUSH DE       ;Préserver les registres qui peuvent
         ;PUSH BC       ;servir
         ;LD A,(TABLSP) ;Mode écran en cours
         ;CP 1
         ;JR C,CONVM0   ;Si carry mode < 1
         ;JR Z,CONVM1   ;Si 0 mode = 1
         ;JR CONVM2     ;Sinon mode = 2
 CONVM0  SRL D         ;;Mode 0 diviser registre DE par 2
         ;RR E          ;2 Fois de suite pour DE = DE / 4
 CONVM1  SRL D         ;;Mode 1 DE = DE/2
         ;RR E
 CONVM2  CALL #BC1D    ;Mode 2 DE inchangé
 ;- IMP09
         ;LD A,C
         ;LD (MASK),A
 ;-
         ;LD (VISAD),HL ;Ranger l'adresse écran
         ;POP BC        ;Récupérer registres et retour
         ;POP DE
         ;RET
 ;

Dans la mesure ou le programme utilise  une table de sprites SURGENE dont  chaque dessin est centré d'office  sur  la  case  de  gauche , on pourrait se  contenter de donner une adresse écran et un masque de %10101010 ...

Tiens , parlons en un peu des tables de sprites puisque ce programme doit  aussi les gérer . Plus précisément  ,  parlons des tables utilisables par les  programmes dites 'travail'  ou  'relogées'  qui  sont  les  mêmes  mais à des  adresses différentes .

Vu du point de vue du  CPC  ,  un  sprite n'est autre qu'une interminable  lignes d'octets dont chacun détermine le contenu d'une case mémoire à envoyer  dans l'écran . Du point de vue  du  programmeur , il est préférable de savoir  ou commence et se termine cette zone  !  SURGENE s'occupe de ces détails . La  table contient une série  d'adresses  qui  indiquent  le  1er  octet ou aller  chercher le sprite et chaque sprite  commence  par  une série de 5 octets qui  permettent de connaître entre autre , ses  dimensions . De plus , cette table  contient d'autres informations précieuses : Le  mode  d'écran à utiliser , le  nombre de dessins dans la table et  aussi  la liste des encres à affecter aux stylos .

En détail , nommons TABLSP le 1er  octet  de la table . S'il s'agit d'une  table travail , il sera logé en 21856 . Si vous relogez cette table , il sera à l'adresse donnée comme adresse de  relocation  . Pour notre programme c'est  40000 .
 

TABLSP (40000): Contient le mode d'écran de la table .
TABLSP+1      : Contient le nombre de sprites dans la table .
TABLSP+2      : Contient sur 16bits l'adresse des encres (Toujours en fin
               ; de table) .
TABLSP+4      : Contient sur 16  bits  l'adresse de chaque sprite présent
               ; dans la table , c'est à partir de là  que l'on va les chercher et pour chacun
               ; d'eux , on trouvera dans l'adresse donnée par le pointeur 16 bits :
     3 Octets qui  ne  nous  intéressent  pas  dans  l'immédiat  suivis par la
 hauteur du sprite puis sa longueur  et  juste derrière , le sprite proprement
 dit .
     Le début de la table peut être présenté comme ceci :
  +------------------------- Mode écran
  !  +---------------------- 10 Sprites
  !  !  +------------------- Adresse des encres
  !  !  !     +------------- Adresse du sprite 1
  !  !  !     !     +------- Adresse du sprite 2
  !  !  !     !     !     +- Etc ...
  !  !  !     !     !     !
  !00!0A!42!9C!3A!90!4F!91!.........
  ^
  +--TABLSP
 Et on trouvera en :
         ;+----------------- 3 octets inutilisés pour l'instant
         ;!        +-------- Hauteur en ligne du sprite 1
         ;!        !  +----- Largeur en cases écran du sprite 1
         ;!        !  !  +-- Octets du sprite
         ;!        !  !  !
 &903A : !00!00!00!0A!12!C0!D0!EF ... &0A*&12 octets et à la fin de la série
 &914F : !00!00!00!08!09!55!AA!12 Le 2ème sprite ... et après le dernier :
 -------- Encore 8 sprites --------
 &924C : !01!0A!0C!05!...... Terminée par &FF la table des encres .
         ;!  !  !  !
         ;!  !  !  !
         ;!  !  !  !
         ;!  !  !  +-- Etc... (Si MODE 0)
         ;!  !  +----- Encre pour PEN 3
         ;!  +-------- Encre pour PEN 2
         ;+----------- Encre pour PEN 1
        Voici la routine qui permet de trouver un sprite dans la table :
 ;
 ;- Va chercher et range les paramètres du dessin NUMSP -
 ;
 FINDSP  LD A,(NUMSP)  ;Numéro du sprite demande .
         ;LD B,A        ;A dans B pour DJNZ
         ;LD IY,LASTAD  ;LASTAD = Premier octet de la table d'adresses - 2
 INCREM  INC IY        ;On avance de 16 bits dans la série d'adresse .
         ;INC IY
         ;DJNZ INCREM   ;Tant que B <> 0 .
         ;LD L,(IY+0)   ;IY = Pointe l'adresse qui CONTIENT l'adresse désirée
         ;LD H,(IY+1)   ;(Voir SOS5 modes d'adressages)
 ;
 ;- Passer les paramètres -
 ;
 PARAM   INC HL        ;On ignore les 3 1ers octets du sprite
         ;INC HL
         ;INC HL
         ;LD B,(HL)     ;HL Pointe sur la hauteur du sprite
         ;INC HL        ;Puis sur la longueur
         ;LD C,(HL)     ;Que l'on incrémente pour les raisons décrites
         ;INC C         ;;dans cet article
         ;LD (LSP),BC   ;L'usage de BC permet de charger 2 octets à la fois .
         ;LD A,C        ;L'octet LONGTLA nous servira
         ;LD (LONGLTA),A;pour les transferts .
         ;INC HL        ;Et on mémorise l'adresse du 1er octet des données
         ;LD (ADSP),HL  ;sprite pour l'affichage .
 ;
         ;PUSH BC       ;On à besoin de connai^tre l'adresse écran du point
         ;PUSH BC       ;situe en bas a droite du sprite alors on la calcule
         ;LD B,0        ;Ne pas oublier pour l'addition 16 bits .
         ;DEC C         ;;C'est la VRAIE longueur qu'il faut ici !
         ;LD HL,(VISAD) ;Adresse d'affichage (En haut a gauche)
         ;ADD HL,BC     ;= Longueur sprite = Adresse colonne droite du sprite
         ;POP BC        ;Récupérer nombre de lignes dans B
         ;DEC B         ;;-1 pour rester à l'intérieur du sprite
 COIN    CALL ADINF    ;Et autant de fois ADINF
         ;DJNZ COIN
         ;LD (COINBD),HL;OUF ! On l'a trouvée ...
         ;POP BC        ;Hauteur et longueur incrémentée
         ;LD HL,0       ;Et a partir de ces 2 données on calcule le nombre
         ;LD D,0        ;d'octets que contiendront tables et buffers (Le
         ;LD E,C        ;me^me pour tous) Ce qui est indispensable pour les
 BCLT    ADD HL,DE     ;transferts par LDIR .
         ;DJNZ BCLT
         ;LD (LTABL),HL ;Ranger ce nombre
         ;LD DE,TABLE   ;Adresse du buffer écran et au passage
         ;ADD HL,DE     ;on calcule l'adresse ou se termine le buffer ce qui
         ;DEC HL        ;est indispensable pour les transferts par LDDR .
         ;LD (FINTAB),HL
         ;RET
 ;

------------------------

Voila pour les routines du  programme  qui  ne concernent pas vraiment le  graphisme . A  part  ça  ,  le  programme  est  entièrement  paramétrable les  variables essentielles sont en début de  listings  suivies de leur adresse en  décimal . Si quelques pokes vous tentent ...  Il  y-a au moins une chose à ne  pas faire , c'est  de  donner  un  incrément  de  déplacement (STEPX - STEPY)  supérieur à la taille en pixels ou  lignes  du  sprite  ! Dans ce cas tout va  planter .

Pour présenter ce long listing , nous revenons à la méthode employée dans les cours sur le FDC : Le listing  commenté est interrompu par du texte quant  c'est nécéssaire . Un seul point noir  :  Les transferts décrits dans SOS5 et  que nous avons mis en images  dans  SOS6  ,  utilisent une forêt de PUSH-POP-LDIR-LDDR j'en passe et des  meilleures  .  Cela fonctionne parfaitement mais  n'est pas vraiment clair ... La meilleure  approche consiste à étudier à fond  LDIR et LDDR dans SOS5 puis les  explications  ,  croquis et images de SOS6 ,  cela vous en apprendra peut-être plus que le listing !

SOS PROGRAMMEURS

★ ANNÉE: ???
★ AUTEUR: MICHEL MAIGROT

CPCrulez[Content Management System] v8.7-desktop/cache
Page créée en 132 millisecondes et consultée 2079 fois

L'Amstrad CPC est une machine 8 bits à base d'un Z80 à 4MHz. Le premier de la gamme fut le CPC 464 en 1984, équipé d'un lecteur de cassettes intégré il se plaçait en concurrent  du Commodore C64 beaucoup plus compliqué à utiliser et plus cher. Ce fut un réel succès et sorti cette même années le CPC 664 équipé d'un lecteur de disquettes trois pouces intégré. Sa vie fut de courte durée puisqu'en 1985 il fut remplacé par le CPC 6128 qui était plus compact, plus soigné et surtout qui avait 128Ko de RAM au lieu de 64Ko.