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 - Texte défilant en rouleau
(Article écrit par Jérôme Étienne et extrait d'Amiga News Tech - janvier 1992)
|
|
Le but de notre programme du mois est de créer l'effet d'un texte s'enroulant autour d'un tube transparent.
Un effet qui commence certes à dater, mais qui reste toujours autant apprécié...
Dans le source ci-dessous, j'en ai même fait un double pour des raisons quelque peu inattendues. On peut
s'imaginer que j'ai agi ainsi pour me compliquer la tâche par plaisir, ou pour rendre l'effet plus efficace encore,
mais en fait il n'en est rien : je n'ai fait cela uniquement que pour gagner du temps-machine. Là, surprise dans
l'auditoire... En effet, comment puis-je gagner du temps en ajoutant des éléments à l'écran ? Eh bien voilà la
substantifique moelle de cet article : je vais, dans un premier temps, vous expliquer comment je procède et vous
en comprendrez les raisons à la fin (suspense insoutenable).
Tout d'abord, je vous conseille de faire chez vous un petit croquis de façon à mieux percevoir la technique utilisée,
car elle est relativement dure à expliquer. Je définis une petite fenêtre dans laquelle on fera défiler
le texte. Le défilement est assez lent, un pixel par VBL. Cela vient du fait qu'à chaque VBL, j'affiche une
colonne d'un pixel de large appartenant à un caractère puis je fais défiler toute la fenêtre d'un pixel vers
le haut et de un pixel vers la gauche. Avant le défilement, on capture la ligne située tout en haut de la
fenêtre et on la mémorise quelque part pour pouvoir ensuite la déposer tout en bas, le vide laissé par le défilement
horizontal étant comblé par le prochain caractère. Au fil des VBL, le texte va défiler à 45 degrés dans la
fenêtre et une fois arrivé en haut, va repasser en dessous grâce à la ligne supérieure, que l'on fait descendre à
chaque fois. Ainsi, avec le temps, on obtient une fenêtre hachurée sur toute sa largeur par du texte orienté à 45
degrés.
La foule haletante s'impatiente, se demandant comment cela peut nous servir à construire un défilement
en rouleau (c'est fou, je viens de m'apercevoir que j'ai raté une vocation d'écrivain a suspense...).
Ensuite, je fais une liste Copper qui définit un petit écran en couleur avec deux
plans. Un plan sera consacré à la partie rouge du tube, c'est-à-dire "l'avant", l'autre sera consacré à la
partie bleue, représentant "l'arrière" du tube. Grâce au Copper, on peut changer à tout moment le pointeur
écran de chaque plan de bits, on va se servir de cet avantage pour déformer le plan avant de manière à donner
l'impression qu'il épouse la forme d'un tube. On fait cela grâce à une belle formule mathématique écrite dans
le programme. Pour embellir et renforcer la crédibilité de l'illusion, on change la couleur du texte sur
le tube en calculant la distance entre le spectateur et le texte. Ainsi, pour la partie avant, plus le texte
est près du centre plus il est clair, et inversement pour la partie arrière.
Le défilement ne s'effectuant que sur un plan et sur une partie d'écran relativement faible, le temps d'exécution
est peu important. On obtient un effet pas trop médiocre pour peu de temps machine. Il est loin d'être suffisant
pour une démo, mais peut sans honte être placé dans un diaporama, par exemple.
La phrase du mois, qui a pour auteur Douglas Adams : "l'infinité est tout bonnement si énorme qu'en comparaison,
l'énormité paraît franchement rikiki".
*******************************************************
*** SCROLL EN ROULEAU DE JEROME ETIENNE POUR L'ANT ***
*******************************************************
; reg circuits specialises
dmacon = $096
dmaconr = $002
vposr = $004
vhposr = $006
; reg color
color00 = $180
; reg blitter
bltcon0 = $040
bltcon1 = $042
bltcpth = $048
bltcptl = $04a
bltbpth = $04c
bltbptl = $04e
bltapth = $050
bltaptl = $052
bltdpth = $054
bltdptl = $056
bltcmod = $060
bltbmod = $062
bltamod = $064
bltdmod = $066
bltsize = $058
bltcdat = $070
bltbdat = $072
bltadat = $074
bltafwm = $044
bltalwm = $046
; reg copper
cop1lc = $080 ; adr de la 1' list
copjmp1 = $088 ; saut de la liste 1
; reg bitplane
bplcon0 = $100 ; reg 0 du controleur de plan de bits
bplcon1 = $102 ; 1 (valeur du scroll)
bplcon2 = $104 ; 2 (priorite entre sprite & champ de jeu)
bpl1pth = $0e0 ; \pointeur sur le
bpl1ptl = $0e2 ; >1er plan de bits
bpl2pth = $0e4 ; pointeur sur le plan de bits 2
bpl1mod = $108 ; valeur modulo pour les plans impairs
bpl2mod = $10a ; valeur modulo pour les plans pairs
diwstrt = $08e ; debut de la fenetre ecran
diwstop = $090 ; fin de la fenetre ecran
ddfstrt = $092 ; debut dma plan de bits
ddfstop = $094 ; fin dma plan de bits
; cia-a (use for mouse's boutton)
ciaapra = $bfe001
; exec library base offset
openlibrary = -30-522 ;nom de la library, version/ a1,d0
forbid = -30-102 ; suppression du multitache
permit = -30-108 ; autorisation du multitache
allocmem = -30-168 ;nb d'octets,specification /d0,d1
freemem = -30-180 ;pointeur mem,nb d'octets /a1,d0
chip = $2 ; for chip ram (cf:allocmem)
clear = $10000 ; for clear the memory (cf:allocmem)
; graphicbase
startlist = 38
; graphic library base offset
ownblitter = -30-426
disownblitter = -30-432
; autres labels
key = $bfec01
custom = $dff000
execbase = 4
coplist_size = 4*2000
char_x = 32
char_y = 32
fnt_width = 40
nb_char_per_fnt = 50
char_width = char_x/8
fnt_size = nb_char_per_fnt*char_y*char_width
nb_char_per_line= fnt_width/char_width
;****** def macros
allocmem: macro
move.l #\1,d0 ; demande l'allocation de $\1 octets
move.l #\2,d1 ; #\2 type de ram sollicitee
jsr allocmem(a6)
move.l d0,\3 ; \3= adr ds la mem recuperee par allocmem
; si erreur d'allocation => MEGA BUG !!!!
endm
***********
freemem: macro
move.l \1,a1 ; liberer #\2 octet a partir
move.l #\2,d0 ; de l'adresse \1
jsr freemem(a6) ; memoire a nouveau libre
endm
***********
vsync: macro
.wait_sync\@:
move.l vposr(a5),d0
and.l #$1ff00,d0
cmp.l #$0c000,d0
bne.s .wait_sync\@
endm
***********
bsr main_init
bsr init_roller
main_loop:
vsync
move.w #$fff,color00(a5)
bsr mobify_roller
bsr wait_blt
clr.w color00(a5)
move.b key,d0 *\
not d0 * >capture the key wich is pressed
ror.b #1,d0 * >and put is code RAW in d0
cmp.b #$45,d0 * tst if esc is pressed
beq init_end *if no loop again
bra main_loop
****************************
roller_x = 352
roller_y = 3*32
plane_width_roller = roller_x/8
roller_plane_size = plane_width_roller*(roller_y+10)
mobify_roller:
bsr wait_blt
clr.w bltcon1(a5) *
move.w #0,bltamod(a5) * modulo in byte
move.w #0,bltdmod(a5) * modulo in byte
move.w #-1,bltafwm(a5)
move.w #-1,bltalwm(a5)
move.l roller_base(pc),a0 *
lea -2(a0),a1 *
move.l a1,bltdpth(a5) *
lea plane_width_roller(a0),a1 *
move.l a1,bltapth(a5) *
move.w #$f9f0,bltcon0(a5) * A = D/ 1 shift
move.w #roller_y*64+plane_width_roller/2+2,bltsize(a5)
move.l roller_base(pc),a0 *
move.l a0,bltapth(a5) *
lea plane_width_roller*roller_y(a0),a0 *
move.l a0,bltdpth(a5) *
move.w #$09f0,bltcon0(a5) * A = D
move.w #64+plane_width_roller/2,bltsize(a5) * only 1 line
move.w #$f,color00(a5)
*** MODIFY CUR_TXT & CUR SLIDE
move.w cur_shift_roller(pc),d0
subq.w #1,d0
tst.w d0
bpl.s no_change_cur_txt_roller *\
moveq #char_x-1,d0 */ & cur_text += 1
addq.l #4,cur_txt_roller * >if new char cur_slide = 0
cmp.l #text_lenght*4,cur_txt_roller * >
bne.s no_change_cur_txt_roller */
move.l #30*4,cur_txt_roller
no_change_cur_txt_roller:
move.w d0,cur_shift_roller * to save d0
lea coded_text(pc),a0 *\
add.l cur_txt_roller,a0 * \
move.l (a0),a0 * >to know the adr of actual char
add.l #picture+64,a0 * /+ 64 to go beyond the color map
move.l roller_base(pc),a1 * a1= adr dest
lea plane_width_roller(a1),a1 * because first line is buffer for last line
add.l #plane_width_roller-1,a1 * a1= adr of last columm
lea plane_width_roller*64(a1),a2
moveq #char_y-1,d0
move.w cur_shift_roller(pc),d1
loop_each_bit_modify_roller:
move.l (a0),d2
lea fnt_width(a0),a0
btst d1,d2
bne.s bit_true_modify_roller
bit_false_modify_roller:
bclr #0,(a1)
bclr #0,plane_width_roller(a1)
bclr #0,(a2)
lea plane_width_roller*2(a1),a1
lea plane_width_roller(a2),a2
dbf d0,loop_each_bit_modify_roller
bra.s end_modify_roller
bit_true_modify_roller:
bset #0,(a1)
bset #0,plane_width_roller(a1)
bclr #0,(a2)
lea plane_width_roller*2(a1),a1
lea plane_width_roller(a2),a2
dbf d0,loop_each_bit_modify_roller
end_modify_roller:
rts
cur_shift_roller: ds.w 1
cur_txt_roller: ds.l 1
****************************
init_roller:
; allocmem for bitplane
allocmem roller_plane_size,chip+clear,roller_plane_adr
*** INIT SOME VARIABLES
move.l roller_plane_adr(pc),roller_base
add.l #plane_width_roller,roller_base
move.w #char_x,cur_shift_roller
move.l #30*4,cur_txt_roller
*** MODIFY ROLLER COPLIST
move.l coplist_adr(pc),a0
lea delta_roller_coplist(a0),a0
clr.w roller_angle
clr.l roller_var
init_roller_coplist:
add.l #$8888,roller_var * $8888 is the result of roller_y*$10000/180
addq.w #1,roller_angle * goto next degr
moveq #0,d1
move.w roller_angle(pc),d1 * d1= angle
cmp.w #180,d1 * >exit if d2=180
beq init_roller_end */ because it is finish
move.l d1,d0 *\
bsr cos * \
muls #30,d0 * > to know if we are on next line
lsl.l #1,d0 * >
swap d0 * > only one modification per line
cmp.w d4,d0 * /
beq.s init_roller_coplist */
move.w d0,d4 * d4= sin(d1)* ray_y
addq.w #4,a0 * to go over wait of line's start
moveq #0,d2 * to modify bpl1pth
move.w roller_var,d2 *\
mulu #plane_width_roller,d2 * >to compute the good target adr
add.l roller_base(pc),d2 */
addq.w #2,a0 *\
swap d2 * \
move.w d2,(a0)+ * >to modify the coplist with
swap d2 * > the good target adr
addq.l #2,a0 * /
move.w d2,(a0)+ */
moveq #0,d0 * to modify color of bpl1pth
move.w roller_angle(pc),d0 *\
bsr sin * \
mulu #13,d0 * \
lsl.l #1,d0 * > to compute the good color
swap d0 * >color is between $3 and $f
addq.w #3,d0 * /
lsl.w #8,d0 */
addq.l #2,a0 *\
move.w d0,(a0)+ * > to modify coplist with the good color
moveq #0,d2 * to modify bpl2pth
move.w roller_var,d2 *\
neg.l d2 * \
add.l #roller_y,d2 * >to compute the good target adr
mulu #plane_width_roller,d2 * /
add.l roller_base(pc),d2 */
addq.w #2,a0 *\
swap d2 * \
move.w d2,(a0)+ * >to modify the coplist with
swap d2 * > the good target adr
addq.l #2,a0 * /
move.w d2,(a0)+ */
moveq #0,d0 * to modify color of bpl2pth
move.w roller_angle(pc),d0 *\
bsr sin * \
mulu #13,d0 * \
lsl.l #1,d0 * > to compute the good color
swap d0 * >color is between $3 and $f
neg.w d0 * /
add.w #13,d0 * /
addq.w #3,d0 */
addq.l #2,a0 *\
move.w d0,(a0)+ * > to modify coplist with the good color
bra init_roller_coplist
init_roller_end:
rts
roller_base: ds.l 1
roller_plane_adr: ds.l 1
roller_angle: ds.w 1
roller_var: ds.l 1
****************************
main_init:
move.l (execbase).w,a6
lea custom,a5
jsr forbid(a6)
move.w #$03e0,dmacon(a5) ; all dma off except disk
bsr init_plane
bsr init_coplist
bsr compute_sin_tab
bsr compute_ascii_table
bsr code_text
move.l coplist_adr,cop1lc(a5) ; > run my own coplist
clr.w copjmp1(a5) ;/
move.w #$87c0,dmacon(a5) ; dma blitter,copper & bitplane on
rts
;****************************
init_plane:
rts
;****************************
init_coplist:
; allocmem for coplist
allocmem coplist_size,chip,coplist_adr
move.l coplist_adr(pc),a0
move.w #dmacon,(a0)+ * > dma blitter,copper & bitplane on
move.w #$87c0,(a0)+ */ bltpri is true
move.w #bpl1mod,(a0)+ * > no modulo
move.w #0,(a0)+ */
move.w #bpl2mod,(a0)+ * > no modulo
move.w #0,(a0)+ */
move.w #bplcon0,(a0)+ * > 2 planes and Dual Playfield
move.w #$2600,(a0)+ */
move.w #bplcon1,(a0)+ * > no shift
move.w #0,(a0)+ */
move.w #bplcon2,(a0)+ * > no sprite priority
move.w #0,(a0)+ */
move.w #ddfstrt,(a0)+ * > init ddfstrt
move.w #$0031,(a0)+ */
move.w #ddfstop,(a0)+ * > init ddfstop
move.w #$00d9,(a0)+ */
move.w #diwstrt,(a0)+ * > init diwstrt
move.w #$2a74,(a0)+ */
move.w #diwstop,(a0)+ * > init diwstop
move.w #$29d4,(a0)+ */
delta_roller_coplist = 40
move.w #61-1,d0 * d0= nbline -1
moveq #$29,d1 * d1= first line
moveq #0,d2 * d2= target is useless buffer but clear
build_roller_coplist:
move.b d1,(a0)+ * wait y
move.b #$03,(a0)+ * wait x
move.w #$fffe,(a0)+ * wait mask
move.w #bpl1pth,(a0)+
swap d2
move.w d2,(a0)+
swap d2
move.w #bpl1pth+2,(a0)+
move.w d2,(a0)+
move.w #color00+2*1,(a0)+
move.w #$f00,(a0)+
move.w #bpl2pth,(a0)+
swap d2
move.w d2,(a0)+
swap d2
move.w #bpl2pth+2,(a0)+
move.w d2,(a0)+
move.w #color00+2*9,(a0)+
move.w #$f,(a0)+
addq.w #1,d1 * 1 ligne traite en +
dbf d0,build_roller_coplist
move.w #bplcon0,(a0)+
move.w #0,(a0)+
move.l #$fffffffe,(a0)+ * 1 cop_instruction
rts
;****************************
; routine inspire de "graphisme en gfa" de Micro Aplication p 642
; in: d0= angle
; out: d0= cos or sin
cos: add.w #90,d0 ; prinsipe: cos(d0) = sin(d0+90)
sin: cmp.w #360,d0 ; angle sup ou equ a 360
blt.s sin1 ; >if true d0=d0-360
sub.w #360,d0 ;/
bra.s sin ; make test again once
sin1: tst.w d0 ; negatif ?
bpl sin2 ; >if true d0=d0+360
add.w #360,d0 ;/
bra.s sin1
sin2: lsl.w #1,d0
move.w sin_tab(pc,d0.w),d0 ; d0 = cos ou sin
rts
********************************************
; tableau tire de "graphisme en gfa" de Micro Aplication p 648
sin_tab: ; valeur des sin* 32768 de 0 a 90 deg
; valeur des sin* 2^15 de 0 a 90 deg
dc.w $0000,$023b,$0477,$06b2,$08ed ; 0-4 degr
dc.w $0b27,$0d61,$0f99,$11d0,$1406 ; 5-9 degr
dc.w $163a,$186c,$1a9c,$1ccb,$1ef7 ; 10-14 degr
dc.w $2120,$2348,$256c,$278d,$29ac ; 15-19 degr
dc.w $2bc7,$2ddf,$2ff3,$3203,$340f
dc.w $3618,$381c,$3a1c,$3c17,$3e0e
dc.w $4000,$41ec,$43d4,$45b6,$4793
dc.w $496a,$4b3c,$4d08,$4ecd,$508d
dc.w $5246,$53f9,$55a6,$574b,$58ea
dc.w $5a82,$5c13,$5d9c,$5f1f,$609a
dc.w $620d,$6379,$64dd,$6639,$678d
dc.w $68d9,$6a1d,$6b59,$6c8c,$6db7
dc.w $6ed9,$6ff3,$7104,$720c,$730b
dc.w $7401,$74ef,$75d3,$761d,$777f
dc.w $7847,$7906,$79bc,$7a68,$7b0a
dc.w $7ba3,$7c32,$7cb8,$7d33,$7da5
dc.w $7e0e,$7e6c,$7ec1,$7f0b,$7f4c ; 80-84 degr
dc.w $7f83,$7fb0,$7fd3,$7fec,$7ffb ; 85-89 degr
tab90: ds.l 3*90/2 ; de 90 a 359 degr calculer par le prg
tab180 = sin_tab+180*2
tab270 = sin_tab+270*2
********************************************
compute_sin_tab:
; compute end of sin_table 90-359
; sintab 90-180
lea sin_tab,a0 ; a1 pointe sur le degr 180
lea (90+90+1)*2(a0),a1 ; +1 => compenser la predecrementation
move.w #$7fff,90*2(a0) ; place degr 90
moveq #90-1,d0 ; 90 deg are copy
copy_90_180: ; principe: sin 0= sin 180
move.w (a0)+,-(a1) ; sin 1= sin 179
dbf d0,copy_90_180 ; sin 2= sin 178 etc...
; sintab 180-270
lea sin_tab,a0 ; a0 pointe sur 0 degr
lea 180*2(a0),a1 ; a1 pointe sur 180 degr
moveq #90-1,d0 ; 90 deg are copy
moveq #0,d2
copy_180_270:
moveq #1,d1 ;\
swap d1 ;/d1=$10000
move.w (a0)+,d2 ;
sub.l d2,d1 ;
move.w d1,(a1)+ ;d1= $10000- d2
dbf d0,copy_180_270
; sintab 270-359
lea sin_tab+180*2,a0 ; a1 pointe sur le degr 360
lea (90+90)*2(a0),a1 ; +1 => compenser la predecrementation
move.w #$8000,90*2(a0) ; place degr 270
lea 2(a0),a0
moveq #89-1,d0 ; 89 deg are copy
copy_270_359: ; principe: sin 360= sin 180
move.w (a0)+,-(a1) ; sin 359= sin 181
dbf d0,copy_270_359 ; sin 358= sin 182 etc...
rts
;****************************
; reactivation de l'old coplist
; restore multitasking & dmacon
init_end:
bsr wait_blt
move.w #$400,dmacon(a5)
lea gfxname(pc),a1
moveq #0,d0
jsr openlibrary(a6)
move.l d0,a4
move.l startlist(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
jsr permit(a6) ; multi switching autorise
freemem coplist_adr(pc),coplist_size
freemem roller_plane_adr(pc),roller_plane_size
moveq #0,d0 ; flag d'erreur desactive
rts
;************* wait for blitter
wait_blt:
btst #14,dmaconr(a5)
bne.s wait_blt
rts
**************
code_text:
lea ascii_table(pc),a0
lea text(pc),a1 * a1= pointer on text
lea coded_text(pc),a2
move.l #text_lenght-1+20,d1 * +20 for the 20 last spaces
loop_code_text:
moveq #0,d0
move.b (a1)+,d0
sub.w #32,d0
lsl.w #2,d0
move.l (a0,d0.w),(a2)+
dbf d1,loop_code_text
rts
************** compute the the adr of each char on picture with ascii code
compute_ascii_table:
moveq #' ',d3
compute_adr_of_each_char:
lea char_on_picture(pc),a0
moveq #nb_char_on_picture-1,d0
move.l d3,d2
search_char_in_ascii_table: *\search the char in ascii table
cmp.b (a0)+,d2 * >if it doesen't exist it will
dbeq d0,search_char_in_ascii_table */be the last char of char_on_picture
sub.l #char_on_picture+1,a0 * +1 for removed the post inc
move.l a0,d0 *
divu #nb_char_per_line,d0 *\
move.w d0,d1 * >d1= adr of line of char
mulu #fnt_width*char_y,d1 */
swap d0 *\
and.l #$ffff,d0 * >isolate the remainder of divu in d0
lsl.w #2,d0 * d0=d0*2 because each char has 4 bytes of width
add.w d1,d0 * d1= adr of line of char
sub.w #32,d2 * because the first char in table is space (ascii code = 32)
lsl.l #2,d2 * d2=4*d2 because the data is long word
lea ascii_table(pc),a0
move.l d0,(a0,d2.w) * put adr of char on picture in ascii_table
addq.w #1,d3 *\d3= ascii code of next char
cmp.b #'Z',d3 * >if d3 sup than 'Z' then it's finish
ble.s compute_adr_of_each_char */
rts
;******* datas
; variables
coplist_adr: ds.l 1
gfxbase: dc.l 1
gfxname: dc.b "graphics.library",0
******* data for text
ascii_table: ds.l 91-32
nb_char_on_picture= 50
char_on_picture:dc.b "ABCDEFGHIJ"
dc.b "KLMNOPQRST"
dc.b "UVWXYZ:;!'"
dc.b "0123456789"
dc.b "()?,-./<> "
text: dcb.b 30,'0'
dc.b "THE FONT WAS DRAWN BY KEFRENS !"
dc.b " THIS SCROLL USE BLITTER AND COPPER ."
text_lenght= *-text
dcb.b 20,' '
even
coded_text: ds.l text_lenght+20 * +20 for the 20 last spaces
picture: incbin 'fnt_32.bit'
end
|
Retrouver le fichier exécutable, la police de caractère et le fichier fnf_32.iff sur
la disquette ANT 29.
|