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
★ AMSTRAD CPC ★ A voir aussi sur CPCrulez , les sujets suivants pourront vous intéresser... |
|
|