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

★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser...

Lien(s):
» Coding Src's » A Very Moving Experience (Sean McManus and Amstrad Computer User)
» Coding Src's » Hot City Lights (Amstrad Computer User)
» Coding Src's » Sternenzeichner (CPC Amstrad International)
» Coding » Graphic - 14 - Animation des Sprites (SOS Programmeurs)
» Coding Src's » 3D Cube (Computing with the Amstrad)
» Coding Src's » Visage
Je participe au site:

» Vous avez remarqué une erreur dans ce texte ?
» Aidez-nous à améliorer cette page : en nous contactant via le forum ou par email.

CPCrulez[Content Management System] v8.7-desktop/c
Page créée en 264 millisecondes et consultée 3545 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.