Suivez-nous sur X
|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : Assembleur - triple champ de jeu ("Trial Playfield")
(Article écrit par Jérôme Étienne et extrait d'Amiga News Tech - octobre 1991)
|
|
Voici un titre pour le moins alléchant, qui a été imaginé dans le but d'attirer le lecteur et le forcer à
lire cet article, même contre sa propre volonté.
Un article que j'ai écrit à la sueur de mon front, sous le soleil qui commence à taper si fort qu'il dérègle ces trois
neurones déprimés d'avoir échoué dans mon crâne bouillonnant... Bon, sérieusement, je vais tenter de vous expliquer comment
obtenir un pseudo triple champ de jeu ("Trial Playfield"), c'est-à-dire trois plans totalement indépendants les uns des autres.
Vous connaissez déjà les possibilités de deux de ces trois champs de jeu, qui sont ceux décrits dans toutes les documentations,
au chapître "Dual Playfield". Mais je vais quand même vous en faire un petit résumé.
La gestion de chaque champ de jeu est séparée en ce qui concerne la
taille et le défilement, mais pas la couleur. En effet, l'Amiga n'a, à ma
connaissance, qu'un seul registre permettant d'indiquer à la
machine le nombre de plans de bits de l'écran (il s'agit bien sûr de
BPLCON0). Or, ayant deux plans et un seul compteur de
plans de bits, la machine tranche le problème de la manière suivante :
si le nombre de plans de bits est pair, les deux plans auront la
même quantité de plans. Dans le cas contraire, c'est le plan 1
qui bénéficiera du plan de bits supplémentaire.
Et de trois !
Pour en revenir au fameux troisième plan, celui-ci n'étant pas
"officiel", il est bien moins souple et ne permet que le monochrome. De
plus, les défilements verticaux et horizontaux sont plus compliqués à
programmer que les défilements normaux.
Il est entièrement composé de sprites.
- "Mais... mais... comment fait-il ? Les documentations que nous avons lues affirment
que l'on ne peut pas afficher plus de 8 sprites sur une même ligne de
raster !" crie la foule d'une seule voix. Et moi de surenchérir :
- "J'irais même plus loin, en affirmant qu'il n'est composé que d'un seul
sprite", tout fier d'avoir enfin quelqu'un qui m'écoute, qui me fait
momentanément oublier que je ne suis qu'une poussière au milieu de ce
grand tout que représente l'Univers. La technique est très simple, en fait ;
elle fait beaucoup intervenir le Copper et les sprites.
Voyage au pays des sprites
Comme vous le savez sûrement, le procédé habituel pour se servir des
sprites est de faire pointer les canaux DMA adéquats (SPRxPT) sur une
partie de la mémoire Chip où l'on aura préalablement placé les données du
sprite. Rappel : ces données indiquent sa position (SPRxPOS et
SPRxCTL) ainsi que l'image du sprite elle-même (SPRxDATA et
SPRxDATB).
Pour que le sprite apparaisse à l'écran, il faut aussi autoriser le DMA sprite en mettant à 1
le bit concerné (bit SPREN dans DMACON). Dans le listing qui suit cet article, une chose saute aux yeux
et les mord violemment : le DMA sprite n'est pas autorisé ! En effet, et
c'est là tout le secret, j'utilise le mode dit manuel des sprites, c'est-à-dire
que je charge le Copper de faire le travail du DMA sprite, travail qui
consiste à mettre la position et l'image (ce terme me paraît légèrement
exagéré d'un seul coup car en fait, il s'agit un seul et unique mot de 16 petits bits) la position et l'image
du sprite, disais-je donc, dans les registres prévus à cet effet. Pour obtenir un plan continu, il faut
renouveler le sprite tout les 16 pixels. J'effectue cette operation ô combien délicate avec l'aide précieuse
du Copper. Comme chacun sait, chaque instruction Copper prend un temps machine équivalent à la durée
d'affichage de 8 pixels en basse résolution ; donc, la douloureuse vérité
s'impose : on doit renouveler le sprite en ne changeant que deux registres
au maximum. Ce fut pénible, mais cela devait être écrit.
Le problème vient du fait que d'un côté, les sprites sont caractérisés par
quatre registres (SPRxPOS, SPRxCTL, SPRxDATA et SPRxDATB) et
que de l'autre côté, on ne peut en changer que deux. Pour contourner
cela, on peut facilement arrêter d'utiliser SPRxDATB et donc se
contraindre à avoir un sprite monochrome. On remarque aussi que
SPRxCTL reste le même durant toute la longueur de la ligne de raster.
Donc, si on ne le modifie qu'en début de ligne, il ne nous reste plus, ô
miracle, que deux registres à bidouiller, à savoir SPRxPOS et SPRxDATA.
Concrètement
La routine build_coplist, qui construit - comme son nom l'indique - une liste Copper
capable de réaliser toutes les merveilles dont je viens de vous parler, procède ainsi : à chaque début de ligne, on initialise
SPRxCTL (qui sera constant pendant toute la ligne) avec le numéro de la ligne actuelle plus 1, puis on attend avec un Wait aproprié que
le rayon atteigne le bord gauche de l'écran et on commence la succession de SPRxPOS et SPRxDATA (20 de chaque en tout). Et
ainsi de suite pour toutes les lignes.
Maintenant que vous connaissez le principe du pseudo troisième plan, je vais vous expliquer comment on peut faire des défilements
dessus. Déjà, les techniques simples et habituelles tel que faire bouger un pointeur sur un plan de bits plus grand que l'écran ne sont pas
utilisables, car toutes les positions des sprites (registre : SPRxPOS) sont absolues, donc changer un pointeur ne donnerait rien de très
intéressant. Résultat, l'unique méthode de défilement que je connaisse s'adaptant à ce cas se résume à un grand coup de Blitter, ce qui
permet de faire un défilement vertical très facilement. Pour ce qui est du défilement horizontal, c'est plus ardu.
Dans le cas particulier (et rare) où le pas du défilement est de 16 pixels, on peut encore utiliser un déplacement de mémoire
simple à l'aide du Blitter. Pour le cas d'un pas inférieur à 16 pixels, il faut encore utiliser le Blitter mais cette fois-ci
beaucoup plus finement, en se servant du fait que ce qui, sort d'une ligne, à cause du glissement, reparaît sur le début
de la ligne suivante.
Pour être honnête, je ne suis pas du tout l'inventeur de cette technique, que je connais grâce à une cartouche que je ne nommerais
pas et qui me permet de décoder une liste Copper à n'importe quel moment d'un jeu ou autre, de la modifier et de reprendre le
cours des choses... Elle a été utilisée dans des jeux tels que Turrican 2 ou SwitchBlade 2 pour afficher les scores
en transparent. Le nom de l'auteur de la première routine m'est complètement inconnu, mais je le remercie ici publiquement.
** LISTING DE JÉROME ÉTIENNE POUR L'ANT
** sur le 'triple champ de jeu'
incdir 'include:'
include 'exec/exec_lib.i'
include 'hardware/custom.i'
custom = $dff000
execbase = 4
plane_x = 320
plane_y = 200
plane_width_word = plane_x/16
plane_size = (plane_x/8)*plane_y
vsync: macro
.wait_vsync\@:
move.l vposr(a5),d0
and.l #$1ff00,d0
cmp.l #$03000,d0
bne.s .wait_vsync\@
endm
wait_blt: macro
btst #14,dmaconr(a5)
.loop_wait_blt\@:
btst #14,dmaconr(a5)
bne.s .loop_wait_blt\@
endm
******************************************************
************** programme principal *****************
******************************************************
move.l (execbase).w,a6
lea custom,a5
CALLEXEC Forbid
move.w #$03e0,dmacon(a5) * all dma off except disk
move.w #$1200,bplcon0(a5) * 1 seul plan de bits
clr.w bplcon1(a5)
clr.w bplcon2(a5)
clr.w bpl1mod(a5)
clr.w bpl2mod(a5)
move.w #$2981,diwstrt(a5) * 320*200
move.w #$f1c1,diwstop(a5)
move.w #$0038,ddfstrt(a5)
move.w #$00d0,ddfstop(a5)
bsr build_coplist
move.l coplist_adr,cop1lc(a5) * > run my coplist
clr.w copjmp1(a5) */
move.w #$83c0,dmacon(a5) * dma blitter,copper & bitplane on
main_loop:
vsync
wait_blt *\
clr.w bltadat(a5) * >-efface l'ecran a chaque vbl
clr.w bltamod(a5) * > pour bien montrer que le
move.w #$ffff,bltafwm(a5) * > plan est dans le sprite
move.w #$ffff,bltalwm(a5) * > et non dans le plan de bits
move.w #$01f0,bltcon0(a5) * >
clr.w bltcon1(a5) * >
clr.w bltdmod(a5) * >
move.l plane_adr,bltdpt(a5) */
move.w #plane_y*64+plane_width_word,bltsize(a5)
move.b $bfec01,d0 *\
not d0 * >capture the key wich is pressed
ror.b #1,d0 */ and put is code RAW in d0
cmp.b #$45,d0 *\
beq.s init_end */ sort si on press sur esc
btst #6,$bfe001
bne.s main_loop
******** init end ***********
* reactivation de l'old coplist
init_end:
wait_blt
lea GfxName(pc),a1 * nom de la library ds a1
moveq #0,d0 * version 0 (the last)
CALLEXEC OpenLibrary * lib graphique ouverte
move.l d0,a4 * adr de graphicbase ds a4
move.l 38(a4),cop1lc(a5) * chargement de l'adr de
clr.w copjmp1(a5) * l'old coplist et lancement
move.w #$83e0,dmacon(a5) * activation des canaux dma necessaires
CALLEXEC Permit * multi switching autorise
fin: moveq #0,d0 * flag d'erreur desactive
rts
GfxName: dc.b "graphics.library",0
even
*******************************************
build_coplist:
move.l coplist_adr(pc),a0
move.w #bplpt,(a0)+ *\
move.w plane_adr(pc),(a0)+ * >init les pointeurs plans de bits
move.w #bplpt+2,(a0)+ * >
move.w plane_adr+2(pc),(a0)+ */
lea image,a1
moveq #$29,d0
.loop_chaque_ligne:
move.w #spr+sd_ctl,(a0)+ *\
move.w d0,d1 * >-init spr_ctl a la ligne juste
lsl.w #8,d1 * > superieure a la ligne actuelle
and.w #$ff00,d1 * >
move.w d1,(a0) * >
addq.w #1,(a0)+ */
move.w d0,d1 *\
ror.l #8,d1 * >-init le wait juste sur le bord
and.l #$ff000000,d1 * > gauche de l'ecran
or.l #$0039fffe,d1 * >
move.l d1,(a0)+ */
move.w d0,d1 *\
lsl.w #8,d1 * >-prepare le futur spr_pos
and.w #$ff00,d1 * >
or.w #$0040,d1 */
moveq #20-1,d2 * 20= largeur de l'ecran /16
.loop_each_word:
move.w #spr+sd_pos,(a0)+ *\ init spr_pos
move.w d1,(a0)+ */
move.w #spr+sd_dataa,(a0)+ *\ init spr_data
move.w (a1)+,(a0)+ */
addq.w #8,d1 *\-on calcul le prochain spr_pos et
dbf d2,.loop_each_word */ boucle pour le prochain mot
addq.w #1,d0 *\ -on teste si on est arrive sur la
cmp.w #$f1,d0 * > ligne 200.Si oui, on a fini.
blt.s .loop_chaque_ligne */
move.l #$fffffffe,(a0)+ * montre la fin de la clist
rts
******** datas
* variables
plane_adr: dc.l ecran
coplist_adr: dc.l coplist
image_raw: incbin 'fnt_32.bit'
image = image_raw+64
section ZONE_CHIP,BSS_C
ecran: ds.l plane_size/4
coplist: ds.l 34000/4
end
|
Note : une petite erreur s'est glissée dans le source.
Voir cet article pour plus d'informations.
Le mois prochain, vous aurez dans cette rubrique probablement la technique de défilement la plus rapide possible
(et en plus c'est vrai !). Il est en fait virtuellement impossible de faire mieux. Encore un algorithme
que je n'ai pas trouvé, d'ailleurs. Son auteur est à ma connaissance Dino Dini, le génie qui a pondu Kick Off.
|