Obligement - L'Amiga au maximum

Dimanche 14 septembre 2025 - 01:05  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

Actualité (récente)
Actualité (archive)
Comparatifs
Dossiers
Entrevues
Matériel (tests)
Matériel (bidouilles)
Points de vue
En pratique
Programmation
Reportages
Quizz
Tests de jeux
Tests de logiciels
Tests de compilations
Trucs et astuces
Articles divers

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z,
ALL


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Assembleur - Afficher des sprites et des BOB sur Amiga OCS et AGA (partie 2)
(Article écrit par Yragael et extrait de www.stashofcode.fr - juillet 2018, mis à jour en octobre 2018)


Cet article est le second - et donc dernier - d'une série de deux consacrée à l'affichage de bitmaps sur Amiga. Dans le premier article, nous avons exploré dans le détail les sprites du matériel. A cette occasion, il est apparu que les sprites sont comme les hobbits : pratiques et colorés, mais petits et peu nombreux. Et même si le matériel permet d'en démultiplier apparemment le nombre en les découpant ou en les répétant, recourir à ces astuces reste assez contraignant.

C'est pourquoi une autre solution a souvent été préférée pour afficher des bitmaps : les BOB. Le BOB est un bitmap affiché à l'aide du Blitter, le coprocesseur dont la fonctionnalité la plus notoire est la copie des données d'une ou plusieurs zones de mémoire vers une autre.

Afficher des sprites et des BOB sur Amiga OCS et AGA
Des vector balls (avec quelques droites pour mieux constater la 3D)

Comment afficher un BOB ? Et ne faut-il pas alors assurer soi-même toutes ces tâches qui étaient prises en charge automatiquement par le matériel s'agissant de sprites : transparence, restauration, découpage, détection de collisions, etc. Tout cela et plus encore dans ce qui suit.
  • Mise à jour du 05/08/2018 : précision apportée sur la nécessité d'utiliser b (l'inverse du masque) et non B (le masque) comme source dans la combinaison logique utilisée par le Blitter.
  • Mise à jour du 11/08/2018 : ajout de perfectBob.s dans l'archive, une version améliorée de bobRAWB.s où la partie rectangulaire du décor que le BOB recouvre est précisément ou globalement restaurée au Blitter.
  • Mise à jour du 14/08/2018 : mise à jour de bobRAW.s et bobRAWB.s dans l'archive, car les versions proposées ne mettaient pas en oeuvre le masquage présenté !
  • Mise à jour du 01/10/2018 : tous les sources ont été modifiés pour intégrer une section "StingRay's stuff" qui permet d'assurer le bon fonctionnement sur tous les modèles d'Amiga, notamment dotés d'une carte graphique.
Cliquez ici pour télécharger l'archive contenant le code et les données des programmes présentés dans cet article. Cette archive contient plusieurs sources :
  • bobRAW.s pour le simple affichage d'un BOB en RAW.
  • bobRAWB.s pour le simple affichage d'un BOB en RAWB.
  • unlimitedBobs.s pour l'effet de BOB illimités.
  • vectorBalls.s pour l'effet de vector balls.
NB : cet article se lit mieux en écoutant l'excellent module composé par Spirit/LSD pour le magazine sur disquette Graphevine #14, mais c'est affaire de goût personnel...

Décaler, masquer et combiner au Blitter

Étant pris en charge par le matériel, les sprites présentent de nombreux avantages pour le codeur. En effet, ce dernier n'a pas à gérer la transparence (le masquage) ; la préservation et la restauration du décor sur lequel ils sont affichés (le recover) ; le découpage pouvant aller jusqu'à l'élimination quand ils débordent ou sortent du champ de jeu (le clipping) ; les priorités entre sprites et entre sprites et plans de bits ; la gestion des collisions entre sprites, et entre sprites et plans de bits. Toutefois, les sprites sont comme les hobbits : pratiques et colorés, mais petits et peu nombreux.

Les BOB ne souffrent pas de telles limites. En effet, un BOB étant un bitmap qui sera affiché parce qu'il est dessiné dans les plans de bits, le codeur dispose de toute latitude pour adapter la taille et la profondeur du BOB. Toutefois, si le matériel simplifie le dessin du BOB, il n'offre aucune facilité pour gérer toutes les tâches évoquées à l'instant en présentant les sprites : masquage, restauration, découpage, priorités, collisions. L'affichage du BOB s'effectue au Blitter. Comme expliqué dans un précédent article, ce coprocesseur permet notamment de combiner plusieurs blocs (les sources A, B et C) par des opérations logiques et d'écrire le résultat dans un autre bloc (la destination D), en décalant de 0 à 15 bits A et B sur la droite, et en masquant le premier et le dernier mot de A.

Rappelons qu'un bloc est ni plus ni moins qu'une séquence de mots en mémoire, dont il est possible d'ignorer périodiquement un certain nombre de mots. Le Blitter propose de décrire un bloc à l'aide d'une adresse de départ, d'une largeur (en mots), d'un modulo, et d'une hauteur (en lignes de mots), comme s'il s'agissait d'un rectangle. Par exemple, un bloc de 28 mots, dont deux mots sont ignorés tous les cinq mots, est représenté comme un bloc de cinq mots de large sur quatre lignes de hauteur, avec un modulo de deux mots (la flèche parcourt les mots aux adresses consécutives) :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Un bloc de mémoire tel que vu par le Blitter

Le Blitter offre de nombreuses possibilités pour combiner A, B et C. Dans un premier temps, les bits sont combinés par AND, après avoir été éventuellement inversés. L'ensemble des combinaisons possibles, désignées comme les minterms, sont notées à l'aide des lettres A, B et C (sources non inversées) ou a, b et C (sources inversées). Dans un second temps, les minterms choisis par le codeur sont combinés entre eux par OR :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Phases de la combinaison bit à bit des sources par le Blitter

Tout cela permet de cerner l'intérêt du Blitter pour afficher l'équivalent d'un sprite. Pour cela il faut combiner trois sources :
  • Le bitmap.
  • Le masque.
  • Le décor.
Le masque (B) est combiné par AND avec le décor (C) à l'endroit où le BOB doit être affiché. Cela permet d'effacer les pixels du décor où des pixels non transparents du bitmap doivent être affichés. Le bitmap (A) est alors combiné par OR avec le décor (C), à la même position, si bien que ses pixels non transparents sont affichés à place de ces décors qui viennent d'être effacés.

Un exemple avec une charmante petite fée de 16x16 pixels, dessinée par votre serviteur à l'aide de l'excellent Pro Motion NG :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Les étapes de l'affichage d'un BOB

Avant de déterminer quels minterms le Blitter doit combiner par OR pour parvenir à ce résultat, il faut régler un petit problème. Comme mentionné, le Blitter copie non pas des pixels, mais des mots. Partant, comment afficher le bitmap et le masque à partir d'un pixel du décor dont l'abscisse n'est pas forcément multiple de 16 ?

Bien évidemment, cette nécessité a été anticipée par les concepteurs du matériel. Le Blitter permet de décaler A et B sur la droite, d'un nombre de bits compris entre 0 et 15. Le décalage de A est indépendant de celui de B. Lorsque les lignes d'un bloc sont ainsi décalées, les bits chassés sur la droite de la ligne Y sont réintroduits sur la gauche de la ligne Y+1. La ligne 0 est un cas particulier : comme il n'y a pas de ligne précédente, ce sont des 0 qui sont introduits sur sa gauche :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Décalage de quatre bits d'une source de N lignes d'un mot au Blitter

Comme il est possible de la constater à l'aide de l'exemple d'un décalage de quatre pixels d'un bloc d'un mot de large représenté sur la figure, des bits de poids faible du dernier mot de la dernière ligne se trouvent alors chassés sur la droite et éliminés. En fait, si la largeur du bloc demeure celle du bitmap à afficher, ce bitmap subit une déformation inacceptable. Même exemple de la fée, quand elle subit un décalage de quatre pixels (pour la lisibilité, les pixels de couleur 0, transparente, introduits à gauche de la première ligne sont affichés en rouge) :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Déformation d'un bloc conservant sa largeur à l'occasion d'un décalage

Pour conserver le bitmap entier dans le bloc, il faut augmenter préalablement la largeur du bloc d'un mot sur la droite (pour la lisibilité, les pixels de couleur 0, transparente, introduits à droite des lignes sont affichés en vert). Après le décalage, il faut masquer les bits superflus à gauche et à droite, c'est-à-dire des bits du premier et du dernier mot de chaque ligne du bloc, avant de combiner le bloc avec le bloc correspondant dans le décor. Cela revient à dire que si le bitmap est décalé, son masque doit l'être pareillement :

Afficher des sprites et des BOB sur Amiga OCS et AGA
L'élargissement du bloc impose un masquage

Le cas particulier de A et le cas général de B

A ce stade, il faut préciser que le Blitter peut masquer le premier et le dernier mot de chaque ligne de A. En exploitant cette possibilité, n'est-il pas possible de se dispenser de rajouter une colonne de mots sur la droite du bitmap, et même un masque, dans un cas particulier mais néanmoins fréquent : quand le bitmap est affiché sur un décor où ses pixels opaques ne viennent remplacer que des pixels de couleur 0 ?

De fait, mais pour que cela fonctionne, il ne suffit pas de préciser ces masques. Il faut aussi jouer sur le modulo de A. Modulo ? Quésaco ? Pour comprendre comment de quoi il en retourne, il est nécessaire de rentrer dans le détail du déroulement d'une copie au Blitter.

Comme illustré plus tôt, Le Blitter combine les mots des sources A, B et C et copie le résultat dans un mot de la destination D. Il procède mot à mot, incrémentant les adresses contenues dans les registres BLTxPTH et BLTxPTL, par exemple BLTAPTH et BLTAPTL pour A. De plus, à la fin de chaque ligne, le Blitter rajoute à l'adresse de A, B, C et D la valeur contenue dans BLTxMOD, par exemple BLTAMOD. Ainsi, s'il devait s'agir de A, le bloc de la figure devrait être spécifié ainsi avant une copie qui l'implique :

	move.l #blockA,d0
	move.w d0,BLTAPTL(a5)
	swap d0
	move.w d0,BLTAPTH(a5)
	move.w #2*2,BLTAMOD(a5)	;Le modulo est spécifié en octets
;...
blockA:		BLK.W 7*4,0

Rappelons que c'est au moment de la copie que le Blitter est informé de la largeur et de la hauteur des blocs impliqués. En effet, c'est en écrivant une combinaison ces valeurs dans BLTSIZE qu'on les spécifie, en même temps qu'on déclenche la copie (dont il faut attendre le terme en testant deux fois un bit de DMACONR, ce que fait la macro WAIT_BLITTER mentionnée ici) :

BLOCK_WIDTH=7			;En mots !
BLOCK_HEIGHT=4			;En pixels
	move.w #(BLOCK_HEIGHT<<6)!BLOCK_WIDTH,BLTSIZE(a5)
	WAIT_BLITTER

L'astuce consiste à utiliser un modulo... négatif, de -2 pour être plus précis. Ainsi, au terme de la copie d'une ligne Y de A, le Blitter va commencer la ligne Y+1 non pas au premier mot de cette dernière, mais au dernier mot de la ligne Y.

La figure qui suit montre ce qui se passe dans les deux cas s'il s'agissait de copier un bloc de deux mots de large sur trois lignes : avec ou sans colonne de mots supplémentaire :
  • Dans le premier cas, au terme de la copie de la première ligne, le modulo valant 0, le Blitter pointe sur le premier mot de la deuxième ligne (son premier bit est encadré en rouge). Il copie cette ligne en injectant à gauche des bits du dernier mot qu'il a lu, donc de la fin de la première ligne de la colonne de mots supplémentaire (en gris foncé).

  • Dans le second cas, au terme de la copie de la première ligne, le modulo valant -2, le Blitter pointe au même endroit. Ayant copié deux mots à partir du début de la première ligne, il aurait dû pointer sur le premier mot de la troisième ligne, mais en ajoutant le modulo, il s'est trouvé renvoyé un mot en arrière. Il copie cette ligne en injectant à gauche des bits du dernier mot qu'il a lu, donc de la fin de la deuxième ligne de la colonne de mots supplémentaire (en vert foncé).
Afficher des sprites et des BOB sur Amiga OCS et AGA
Copie dans la deuxième ligne de deux mots d'un bloc avec ou sans colonne de mots supplémentaire

Pour éliminer les bits superflus à gauche comme à droite de ceux de la ligne, il ne reste plus qu'à exploiter la possibilité qu'offre le Blitter de masquer le premier et dernier mot de A. Les masques que le Blitter combine à ces mots doivent être spécifiés dans les registres BLTAFWM et BLTALWM, respectivement. La combinaison s'effectuant par AND, les bits des masques correspondant aux bits superflus doivent être effacés, tandis que les autres bits doivent être positionnés. Ces masques n'ont pas à être décalés, car le Blitter les applique au premier et au dernier mot de chaque ligne AVANT de décaler cette dernière. Bref, quel que soit le décalage dans le contexte de l'affichage d'un BOB, leurs valeurs doivent être $FFFF et $0000, respectivement.

Dans la continuité de la figure précédente, la figure suivante décrit ce qui se déroule lors de la copie de la deuxième ligne. Attention, il faut suivre ! Cette copie implique deux mots : le mot constituant la deuxième ligne (en vert) suivi du mot constituant la troisième (en bleu). A la fin de cette copie, tous les bits du mot du second mot, ont été effacés suite au AND avec BLTALWM. Par ailleurs, ses quatre derniers bits ainsi effacés se trouvent prêts à être injectés sur la gauche du premier mot de la troisième ligne (en bleu) lors de sa copie à venir. C'était déjà ce qui s'était passé lors de la copie de la première ligne (en rouge), et c'est pourquoi les bits à 0 injectés lors de la copie de la deuxième ligne (en vert) figurent en vert sombre : ce sont les quatre derniers bits du mot constituant la deuxième ligne (en vert) qui avaient été effacés suite au AND avec BLTALWM.

Afficher des sprites et des BOB sur Amiga OCS et AGA
Masquage des premier et dernier mots de A

Au final, le code pour afficher un BOB de BOB_DX x BOB_DY pixels, composé d'un seul plan de bits (à l'adresse bob), sur un décor de DISPLAY_DX x DISPLAY_DY pixels composé d'un seul plan de bits (à l'adresse backBuffer), est le suivant :

	lea bob,a0
	move.w #BOB_X,d0
	move.w d0,d1
	and.w #$F,d0
	ror.w #4,d0
	or.w #$0BFA,d0
	move.w d0,BLTCON0(a5)
	lsr.w #3,d1
	and.b #$FE,d1
	move.w #BOB_Y,d0
	mulu #DISPLAY_DX>>3,d0
	add.w d1,d0
	movea.l backBuffer,a1
	lea (a1,d0.w),a1
	move.w #$0000,BLTCON1(a5)
	move.w #$FFFF,BLTAFWM(a5)
	move.w #$0000,BLTALWM(a5)
	move.w #-2,BLTAMOD(a5)
	move.w #(DISPLAY_DX-(BOB_DX+16))>>3,BLTCMOD(a5)
	move.w #(DISPLAY_DX-(BOB_DX+16))>>3,BLTDMOD(a5)
	move.l a0,BLTAPTH(a5)
	move.l a1,BLTCPTH(a5)
	move.l a1,BLTDPTH(a5)
	move.w #(BOB_DY<<6)!((BOB_DX+16)>>4),BLTSIZE(a5)
	WAIT_BLITTER

Le rôle des autres registres utilisé dans ce code sera expliqué plus loin.

La solution qui vient d'être présentée est pratique car elle permet de ne pas avoir à introduire de colonne de mots supplémentaire, mais elle ne fonctionne que pour A. En effet, le Blitter ne sait masquer que le premier et le dernier mot d'une ligne de A, qui correspondrait au bitmap. Rien pour B, qui correspondrait au masque.

Il n'en reste pas moins important de savoir que cette possibilité existe, car elle permet d'afficher un bitmap sans avoir à rajouter une colonne de mots supplémentaire, et sans avoir à fournir son masque :
  • Ne pas avoir à rajouter une colonne de mots supplémentaire est intéressant quand le bitmap est une extraction d'une partie d'une image. Par exemple, quand il s'agit de copier une partie d'un plan de bits quelque part : cette partie peut donc être prélevée directement.

  • Ne pas avoir à fournir de masque est intéressant quand les pixels du bitmap ne viennent remplacer que des pixels de couleur 0. Par exemple, quand il s'agit d'afficher les lettres d'un défilement sur fond de couleur 0, lettres qui ne se chevauchent jamais - une lettre peut être affichée par un simple OR avec le décor, sans utiliser B pour le masque.
Et B, qui sert pour le masque ? Il n'existe pas de registres équivalents à BLTAFWM et BLTALWM pour masquer le premier et le dernier mot de chaque ligne de cette source. Dans ces conditions, l'astuce consistant à utiliser un modulo de -2 pour se dispenser d'avoir à rajouter une colonne supplémentaire de mots à 0 ne peut pas fonctionner.

Comme déjà expliqué, le masque doit être décalé sur la droite, ce qui implique que des bits doivent être injectés sur la gauche et d'autres rejetés sur la droite de chacune de ses lignes, lignes dont la longueur doit être agrandie d'un mot sur la droite.

Or, comment positionner les bits superflus à gauche et à droite avant de combiner par AND le masque avec le décor, afin de préserver les bits du décor correspondant ? Impossible d'appliquer des masques BLTBFWM et BLTBLWM, car ils n'existent pas. Par conséquent, il faut que ces bits soient déjà présents dans le masque, donc qu'ils figurent dans une colonne de mots supplémentaire sur sa droite, dont les bits seraient à 1.

A 1 ? Très logiquement, on souhaiterait que le masque soit combiné par AND avec le décor, ce qui implique que les bits du masque devaient être à 1 là où le décor devrait être préservé, et à 0 là où le décor devrait être effacé.

Or, nous avons vu que le Blitter introduit des bits à gauche de la première ligne du masque pour la décaler, et que ces bits sont nécessairement à 0. Cela signifie qu'un bit à 0 dans le masque doit correspondre à un bit qu'il faut préserver dans le décor, tandis qu'un bit à 1 dans le masque doit correspondre à un bit qu'il faut y effacer. C'est pourquoi c'est b, l'inverse du masque, et non B, le masque, qu'il faut combiner par AND au décor. Fort heureusement, le Blitter permet de combiner indifféremment B ou son inverse, b (pour NOT B), avec C, qui correspond au décor.

En conséquence, les bits de la colonne de mots supplémentaires sur la droite du masque doivent être à 0 et non à 1. Pour récapituler :
  • A correspond au bitmap, qui doit être décalé. Ses données ne comprennent pas de colonne de mot supplémentaires à 0, mais c'est parce que les masques de premier et de dernier mot BLTAFWM et BLTALWM sont appliqués.
  • B correspond au masque, qui doit être décalé. Ses données comprennent une colonne de mots supplémentaires à 0, car il n'existe pas de tels masques pour cette source, qui est par ailleurs inversée avant d'être combinée avec le décor.
  • C correspond au décor, qui ne doit pas être décalé.
Combiner les minterms, lancer le Blitter et l'attendre

Pour comprendre totalement le code d'affichage d'un BOB qui a été présenté (cas spécifique du BOB dont les pixels opaques sont affichés sur des pixels de couleur 0), et comprendre le code qui va suivre (cas général du BOB dont les pixels opaques sont affichés sur des pixels de couleurs quelconques), il reste à comprendre comment ils permettent de spécifier au Blitter la manière dont les sources A, B et C doivent être combinées pour produire la destination D.

Comme expliqué, le Blitter combine les sources en combinant par OR des minterms, qui sont eux même le produit de combinaisons par AND des sources, éventuellement inversées. Or que s'agit-il de faire, sinon la combinaison suivante : D=A+bC.

L'Amiga Hardware Reference Manual explique comment en déduire les minterms qu'il faut activer en positionnant les bits correspondants dans BLTCON0. Il suffit de rajouter des facteurs neutres aux AND (par exemple, c+C qui vaut nécessairement 1) et de développer puis réduire :

D=A(b+B)(c+C)+bC(a+A)
D=Abc+AbC+ABc+ABC+abC+AbC
D=ABC+ABc+AbC+Abc+abC

Les huit bits de BLTCON0 réservés au minterms sont ceux de son octet de poids faible :

Minterm ABC ABc AbC Abc aBC aBc abC abc
Bit 7 6 5 4 3 2 1 0

En l'espèce, cela signifie que l'octet doit prendre la valeur $F2.

Le reste de la configuration du Blitter consiste simplement à spécifier qu'il doit activer A, B, C et D, et à spécifier la valeur du décalage sur la droite de A et celle de celui de B. D'autres bits de BLTCON0 et de BLTCON1 servent à ces usages - se reporter à l'Amiga Hardware Reference Manual, qu'il ne s'agit pas de réécrire ici, pour les identifier.

Maintenant que tout a été présenté, il est possible d'écrire le code d'affichage d'un BOB masqué, dont "bob" est l'adresse du "bitmap" et "bobMask" celle de son masque :

moveq #0,d1 move.w #BOB_X,d0 subi.w #BOB_DX>>1,d0 move.w d0,d1 and.w #$F,d0 ror.w #4,d0 move.w d0,BLTCON1(a5) or.w #$0FF2,d0 move.w d0,BLTCON0(a5) lsr.w #3,d1 and.b #$FE,d1 move.w #BOB_Y,d0 subi.w #BOB_DY>>1,d0 mulu #DISPLAY_DEPTH*(DISPLAY_DX>>3),d0 add.l d1,d0 move.l backBuffer,d1 add.l d1,d0 move.w #$FFFF,BLTAFWM(a5) move.w #$0000,BLTALWM(a5) move.w #-2,BLTAMOD(a5) move.w #0,BLTBMOD(a5) move.w #(DISPLAY_DX-(BOB_DX+16))>>3,BLTCMOD(a5) move.w #(DISPLAY_DX-(BOB_DX+16))>>3,BLTDMOD(a5) move.l #bob,BLTAPTH(a5) move.l #bobMask,BLTBPTH(a5) move.l d0,BLTCPTH(a5) move.l d0,BLTDPTH(a5) move.w #(DISPLAY_DEPTH*(BOB_DY<<6))!((BOB_DX+16)>>4),BLTSIZE(a5) Le lecteur attentif doit encore se gratter la tête. Quelles sont ces valeurs stockées dans les registres BLTCMOD et BLTDMOD ?

Une constante vient de faire son apparition : DISPLAY_DEPTH. Le code permet d'afficher un BOB de DISPLAY_DEPTH plans de bits de profondeur sur un décor de même profondeur. Or, cela soulève un enjeu intéressant.

En effet, si les données du bitmap, du masque et du décor sont organisées comme de coutume, celles du plan de bits 1 sont suivies de celles du plan de bits 2, et ainsi de suite. Cela conduit à afficher les plans de bits du bitmap et du masque un par un dans une boucle, car le modulo utilisé pour passer d'une ligne à l'autre dans D, valant donc (DISPLAY_DX-(BOB_DX+16))>>3 ne peut servir à passer de la dernière ligne utilisée d'un plan de bits à la première ligne utilisée dans le suivant :

;En supposant que a2 pointe sur le mot du premier plan de bits du décor où le BOB doit être affiché,
;et ne rappelant pas les valeurs des autres registres BLTAFWM, BLTALWM, BLTCON0, BLTCON1, BLTAMOD, BLTBMOD,
;BLTCMOD et BLTDMOD...

	lea bob,a0
	lea bobMask,a1
	move.w #DISPLAY_DEPTH-1,d0
_drawBobBitplanes:
	move.l a0,BLTAPTH(a5)
	move.l a1,BLTBPTH(a5)
	move.l a2,BLTCPTH(a5)
	move.l a2,BLTDPTH(a5)
	move.w #(BOB_DY<<6)!((BOB_DX+16)>>4),BLTSIZE(a5)
	addi.l #BOB_DY*(BOB_DX>>3),a0
	addi.l #BOB_DY*((BOB_DX+16)>>3),a1
	addi.l #DISPLAY_Y*(DISPLAY_DX>>3),a2
	WAIT_BLITTER
	dbf d0,_drawBobBitplanes

Cette manière de procéder contraint d'attendre le Blitter après chaque copie dans un plan de bits avant de passer au plan de bits suivant. Cela ne permet pas de tirer parti du fonctionnement en parallèle du Blitter et du processeur, sauf à l'occasion de la dernière copie - il faudrait alors ne pas appeler la macro WAIT_BLITTER, ce qui contraindrait donc à distinguer les premières boucles de la dernière, pour en rajouter.

N'est-il pas possible de copier en un coup les plans de bits du bitmap et du masque dans ceux des plans de bits ? Tout à fait :
  • Après avoir affiché une ligne d'un plan de bits, le matériel ajoute la valeur de BPL1MOD (plan de bits impair) ou BPL2MOD (plan de bits pair) à l'adresse courante dans le plan de bits pour passer à la ligne suivante. La valeur d'un tel registre peut être fixée à (DISPLAY_DEPTH-1)*(DISPLAY_DX>>3) pour entrelacer les lignes des plans de bits (pairs ou impairs, selon le registre) dans les données du décor.

  • Pour sa part, le Blitter permet de fixer la valeur d'un modulo via BLTAMOD, BLTBMOD et BLTCMOD pour A, B et C, et donc ici encore d'entrelacer les lignes des plans de bits (pairs et impairs, sans distinction) dans les données du bitmap, du masque et du décor, donc A, B, C et D.
L'organisation des données est donc très différente selon qu'elle est classique, dite RAW ("brut de fonderie"), ou optimisée, dite RAWB (RAW Blitter). La figure suivante permet de les comparer dans le cas d'un bitmap de 16 pixels de large et de deux lignes de hauteur :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Organisation des données du bitmap d'un BOB en RAW et RAWB

Pour conclure (car c'est enfin terminé !), les programmes "bobRAW.s" et "bobRAWB.s" explorent chacune des solutions pour afficher un BOB de 64x64 pixels sur cinq plans de bits :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Affichage d'un BOB de 64x64 pixels sur cinq plans de bits

Dans ces programmes, la couleur du fond passe au rouge au début des opérations, et au vert à leur terme. Aucune différence n'est observable, mais c'est parce que le Blitter est attendu systématiquement dans les deux programmes à la fin de toute copie.

Le programme "bobRAWB.s" pourrait être modifié pour réaliser des opérations au processeur tandis que le BOB est affiché dans les cinq plans de bits. Le programme "bobRAW.s", pourrait être modifié pareillement, mais pour permettre de réaliser ces opérations au processeur tandis que le BOB est affiché dans le dernier plan de bits seulement. La différence pourrait alors être constatée. Pour cette raison, si le recours au RAW peut s'imposer dans des cas particuliers, c'est généralement c'est le RAWB qu'il convient d'utiliser quand il s'agit d'afficher des BOB.

"Unlimited BOBs" : des BOB à foison, vraiment ?

Les BOB sont utilisés pour produire des effets très variés, dont les plus notoires sont les "unlimited BOBs", et les "vector balls".

"The Amiga possibilities have been burst beyond your imagination. And the result is what you see !!!", proclame fièrement l'auteur d'un défilement de la fameuse Megademo de Dragons. Excessivement vintage, cette démo contient un effet très classique à l'époque, dit "unlimited BOBs". Un BOB est visiblement rajouté à chaque trame, et le compteur semble indiquer que cela ne s'arrêtera jamais. Les performances ne sont aucunement pénalisées par cette multiplication des BOB :

Afficher des sprites et des BOB sur Amiga OCS et AGA
2000 BOB dans la trame, et ce n'est pas fini ! (Megademo par Dragons)

Dans la vie, rien n'est gratuit, et surtout pas les BOB. Il y a donc un truc. Avant de rentrer dans les détails, dotons-nous d'un BOB de 16x16 pixels en quatre couleurs adéquat, toujours dessiné avec l'excellent Pro Motion NG :

Afficher des sprites et des BOB sur Amiga OCS et AGA
BOB, votre pote rondouillard
de 16x16 pixels sur
deux plans de bits


Ce qui est affiché est une animation où le BOB suit une trajectoire, et dont le principe est le suivant. Le nombre d'images est fixé, par exemple à 3. A chaque trame, l'image est remplacée par la suivante, en rebouclant sur la première. Une série de trois images de 0 à 2 constitue une période :
  • Lors de la période 0, un BOB est affiché aux positions P0, P1 et P3 dans les images 0, 1 et 2, respectivement.
  • Lors de la période 1, un BOB est rajouté aux positions P4, P5 et P6 dans les images 0, 1 et 2 respectivement.
  • etc.
Ainsi, lorsque l'image 0 est affichée pour la seconde fois, il semble qu'un BOB a été rajouté à la position initiale du BOB précédent, et qu'il suit ce BOB au fil des images suivantes :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Les deux premières périodes d'une animation en trois images

Puisqu'il ne s'agit jamais que d'afficher un nouveau BOB à chaque trame, l'effet ne consomme presque pas de temps de calcul. C'est donc extrêmement simple, mais bien pensé.

Quant à la trajectoire, elle peut être quelconque. Dans le programme "unlimitedBobs.s", la position du BOB est calculée sur un cercle dont le rayon oscille entre un minimum et un maximum, ce qui permet de rompre la monotonie :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Des BOB tentaculaires

Les vector balls, des BOB en 3D

Plus sophistiqué : les vector balls. Une démo du groupe Impact en fournit une belle illustration. Comme il est possible de le constater, il s'agit d'afficher des BOB figurant des sphères à certaines positions d'un modèle en 3D :

Afficher des sprites et des BOB sur Amiga OCS et AGA
De très jolies vector balls (Vectorballs par Impact)

Le programme "vectorBalls.s" montre, sans chercher en rien à l'optimiser (pour rester simple, il utilise même un tri à bulles sans condition d'arrêt anticipé !), comment produire un effet de ce type. Le fait qu'un seul BOB soit toujours utilisé ne permet pas de bien visualiser l'effet de profondeur sur la capture d'écran, mais tout y est assurément :

Afficher des sprites et des BOB sur Amiga OCS et AGA
Nos vector balls. Si, si ! C'est en 3D !

Même s'il est plus élaboré que celui des "unlimited BOBs", le programme des vector balls reste simple. A chaque trame, il s'agit de calculer une nouvelle image en suivant ces étapes :
  • Effacer les plans de bits.
  • Appliquer quelques rotations aux coordonnées 3D des points du modèle.
  • Projeter ces points pour déterminer leurs coordonnées 2D.
  • Trier ces coordonnées 2D par ordre de profondeur décroissante de la profondeur des coordonnées 3D dont elles découlent.
  • Parcourant la liste des coordonnées 2D dans cet ordre, afficher un BOB dont les coordonnées 2D donnent le centre.
Notez que pour que l'effet soit réussi, il faut éviter qu'une sphère passe devant une autre abruptement, et pour cela bien espacer les points sur le modèle 3D.

Cet effet peut être sophistiqué en utilisant des BOB représentant des sphères de couleurs différentes et/ou dont le diamètre est variable selon la profondeur, et en animant des parties du modèle indépendamment les unes des autres.

Pour en finir avec les BOB...

Ces explications sur la manière d'afficher un BOB et d'utiliser le code pour produire deux effets, les "unlimited BOBs" et les "vector balls", étant données, tout semble avoir été dit au fil des deux articles de cette petite série consacrée à l'affichage de bitmaps animés sur Amiga OCS et AGA.

Il ne faut pas perdre de vue que ce ne sont là que des techniques de base, dont l'emploi nécessite un travail de sophistication et d'optimisation pour produire des effets réussis. Or, entre autres, il serait possible d'imaginer une troisième solution : afficher des bitmaps animés au processeur, par exemple pendant que le Blitter affiche un BOB et que le matériel affiche les sprites. On trouve certainement de nombreux exemples d'un tel mélange de techniques dans les jeux et les démos sur Amiga. Un ordinateur dont le matériel reste décidémment des plus fascinants !


[Retour en haut] / [Retour aux articles] [Article précédent]