Obligement - L'Amiga au maximum

Dimanche 25 août 2019 - 18:06  

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
 · Articles en d'autres langues


Twitter

Suivez-nous sur Twitter




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


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
 · Systèmes d'exploitation
 · Trombinoscope Alchimie 7
 · Vidéos


Téléchargement

 · Documents
 · Jeux
 · Logiciels
 · Magazines
 · Divers


Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Logiciels
 · Jeux
 · Scène démo
 · Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Assembleur - Effet de zoom
(Article écrit par Jérôme Étienne et extrait d'Amiga News Tech - mars 1992)


A la demande d'un lecteur, j'ai ce mois-ci programmé une routine de zoom bitmap, telle que l'on peut la voir dans Deluxe Paint par exemple avec l'option "Stretch" (Étirement).

Pour se servir de cette routine, il faut initialiser les coordonnées du rectangle source dans OX1, OY1, OX2 et OY2. (OX1, OY1) sont les coordonnées du point en haut à gauche du rectangle source et (OX2, OY2) celles du point en bas à droite. De plus, il faut initialiser les coordonnées du rectangle destination (DX1, DY1) pour le coin en haut à droite, et (DX2, DY2) pour en bas à gauche. La routine dans sa version actuelle, ne fait qu'afficher une seule fois la fenêtre "étendue", mais en se creusant un peu la tête, il est possible de l'utiliser pour faire des effets vidéo très intéressants.

L'image où l'on prend le rectangle source (disponible sur la disquette n°31) est chargée dans le programme par un INCBIN et est pointée par l'étiquette PIC_BMP. Cette image est au format 320x256 en 16 couleurs et est au format bitmap standard (d'abord le plan 1, puis le plan 2, etc.). Elle est suivie de sa palette de couleurs.

On peut penser qu'il est assez stupide d'avoir choisi ce format, puisqu'une routine dont le seul but est de transformer l'image source en un format où chaque plan de ligne est entrelacé, est appelée en début de programme... Ce choix se justifie par le fait que ce format est celui que l'on obtient par défaut avec IFF_Converter, donc le plus facile à obtenir pour le lecteur.

Fonctionnement du zoom

Le principe de base est très simple et est, en même temps, le plus rapide que je connaisse pour une telle application. Il consiste dans un premier temps à zoomer verticalement la fenêtre source, puis horizontalement le résultat obtenu. Cette technique permettant de ne zoomer que dans une seule direction à la fois (horizontale ou verticale), elle permet également l'utilisation du Blitter. Ceci est bien plus rapide que la technique de base qui vient tout de suite à l'esprit d'une personne n'ayant jamais réfléchi au problème, à savoir tester la couleur de chaque point de la fenêtre source et de dessiner un rectangle de la même couleur dans la fenêtre destination. Le gain de vitesse de l'algorithme vient du fait que l'on traite des ensembles de points, et non les points un par un. Cette méthode présente cependant un certain désavantage : elle nécessite une étape intermédiaire et donc, utilise plus de mémoire.

Voici plus de détails : l'image d'où l'on extrait les premières données (les lignes horizontales) est appelée FIRST_SCR_ADR. On la déforme verticalement et l'on stocke l'étape intermédiaire dans une page appelée LOG_SCRADR. Puis on déforme horizontalement cette étape et on stocke le résultat dans la page PHY_SCR_ADR, qui est celle que l'on voit. C'est pour cette raison que l'on voit l'image se dessiner (rapidement) devant nos yeux quand on lance le programme.

Je vais vous expliquer comment faire un zoom d'une partie d'image en prenant comme exemple le zoom horizontal (qui augmente la hauteur de la fenêtre source). On initialise deux curseurs virtuels : un qui va se balader sur les y de la fenêtre destination du haut vers le bas, par pas de un, et un qui va se balader sur les y de la fenêtre source et dont le pas va varier selon un coefficient prédéfini. A chaque itération, on incrémente chaque y avec le pas qui lui correspond et on copie la ligne du y source sur la ligne du y destination.

C'est très simple, mais cela mérite une petite précision sur la manière de calculer le coefficient : il doit être un nombre réel et non un entier. Or le 68000 ne manipule que les entiers. J'ai donc choisi la technique des bits fractionné : sur un chiffre de 32 bits, on déclare qu'un certain nombre de bits sont considérés comme étant derrière la virgule. Dans mon cas, ce chiffre est de 16 bits car il permet d'extraire plus facilement la partie entière. En effet, quand on utilise un registre, une simple instruction "swap" suffit ; quand on utilise la mémoire, il suffit d'adresser en ".w" au lieu de ".l".

Pourquoi notre coefficient est-il réel, et non entier ? Tout simplement parce qu'il est le résultat de la division de la hauteur de la fenêtre source par la hauteur de la fenêtre destination. Le problème immédiat est donc : comment faire une division de telle sorte que l'on obtienne un résultat sur 32 bits ? J'ai trouvé la réponse dans le livre Mise En Oeuvre Du 68000, paru chez Sybex.

Nous savons maintenant comment fonctionne globalement le zoom et nous allons nous attarder sur les routines appelées copy_horizontal_line et copy_vertical_line. Pour la copie de ligne horizontale, rien de génial en fait : c'est une simple copie de la ligne avec un mintern de A=D. Pour la copie verticale, c'est légèrement plus complexe : dans un premier temps, le mintern doit être différent, car il est nécessaire de ne pas effacer tous les bits du mot destination, mais seulement le bit correspondant à la ligne verticale en cours. Pour cela, on choisit un mintern tel que AB+aC=D, avec A désignant le mask, B l'image et C le fond.

Mais tous les problèmes ne sont pas résolus pour autant, car comme chacun sait, le Blitter décale ses bits vers la droite et uniquement vers la droite, d'où un problème évident. Imaginons que l'on veut copier la ligne qui se trouve sur la colonne 13 sur la colonne 5. Le glissement doit s'effectuer vers la gauche, ce dont le Blitter est incapable. On est forcé de le simuler en utilisant le fait que tout les bits qui sortent à droite au bout de la ligne réapparaissent au début de la ligne suivante. Pour simuler le glissement à gauche, il faut donc remonter le pointeur d'une ligne (pour que les bits aillent bien là où il faut, car l'image sera descendue d'une ligne) puis augmenter "bltsize" d'une ligne pour que l'image soit affichée dans son intégralité et qu'il ne manque pas un point tout en bas de la ligne verticale.

Pour finir, je voudrais préciser que l'on aurait pu être plus rapide en utilisant le fait que bouger une ligne verticale est plus long que pour une ligne horizontale. Il est donc possible de faire une routine qui décide quel zoom faire en premier, afin de gagner du temps. Le test est assez simple : si l'on grossit la fenêtre verticalement, alors on zoome en horizontal en premier, sinon on reste dans l'ordre actuel.

La phrase du mois : On ne manipule pas une marionnette avec un seul fil.

Dernière minute : emporté par mon enthousiasme, j'ai soudain réalisé, mais trop tard, qu'en mode incrémentation, notre cher Blitter travaille complètement à l'envers, c'est-à-dire non seulement du bas vers le haut, mais aussi de la droite vers la gauche ! On gagnerait donc encore du temps en utilisant ce mode ! N'ayez crainte, je vous proposerai une routine de remplacement... dès que je l'aurai programmée.

* AUTEUR: j.etienne
* SUJET: zoom bitmap avec le blt
* ASSEMBLEUR: devpack 2.14

	OPT	C-	* opt case off

	incdir	'include:'
	include	'exec/exec_lib.i'
	include	'hardware/custom.i'
	
custom		=	$dff000
execbase	=	4

BPL_X		=	320
BPL_Y		=	256
BPL_DEPTH	=	4
BPL_WIDTH	=	BPL_X/8
BPL_SIZE	=	BPL_WIDTH*BPL_Y

WAIT_BLT:	macro
	lea	CUSTOM,a5
	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	#(BPL_DEPTH<<12)+$200,bplcon0(a5)
	clr.w	bplcon1(a5)
	clr.w	bplcon2(a5)		
	move.w	#BPL_WIDTH*(BPL_DEPTH-1),bpl1mod(a5)
	move.w	#BPL_WIDTH*(BPL_DEPTH-1),bpl2mod(a5)
	move.w	#$2981,diwstrt(a5)	*\ 
	move.w	#$29c0,diwstop(a5)	* > init un ecran 320*256
	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
 	bsr	PUT_PIC_IN_PHY_SCR
	
* fait le zoom
	bsr	ZOOM


WAIT	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	INIT_END	*/ sort si on press sur esc
	btst	#6,$bfe001
	bne	WAIT
	bra	INIT_END

ZOOM: ***************************************************************
* init coor du rectangle source
	move.l	#120*$10000,OX1
	move.l	#000*$10000,OY1
	move.l	#220*$10000,OX2
	move.l	#100*$10000,OY2
* init coor du rectangle cible
	move.l	#000*$10000,DX1
	move.l	#000*$10000,DY1
	move.l	#319*$10000,DX2
	move.l	#255*$10000,DY2
* fait le zoom vertical puis horizontal
	bsr	ZOOM_VERTICAL
	bsr	ZOOM_HORIZONTAL
	rts	
********************************************************** END_ZOOM


ZOOM_HORIZONTAL: ****************************************************
	moveq	#0,d0 
	move.w	DX2(pc),d0
	sub.w	DX1(pc),d0
	moveq	#0,d1
	move.w	OX2(pc),d1
	sub.w	OX1(pc),d1
	swap	d1
	bsr	DIV_32_BITS

	move.l	d0,COEF_HORIZONTAL


	move.l	DX1,CUR_OX	
	move.l	DX1,CUR_DX	
.LOOP_EACH_LINE
	move.w	CUR_OX(pc),d0
	move.w	DY1(pc),d1
	move.w	DY2(pc),d2
	move.w	CUR_DX(pc),d3
	move.w	DY1(pc),d4
	
	bsr	COPY_VERTICAL_LINE
	
	move.l	COEF_HORIZONTAL(pc),d0
	add.l	d0,CUR_OX
	addq.w	#1,CUR_DX

	move.w	CUR_DX(pc),d0
	cmp.w	DX2(pc),d0
	blt.s	.LOOP_EACH_LINE
	
	rts
************************************************* END_ZOOM_HORIZONTAL





COPY_VERTICAL_LINE: *******************************************
* IN: d0 = CUR_OX    = coor origine
*     d1 = OY1       = coor origine
*     d2 = OY2       = coor origine
*     d3 = CUR_DX    = coor destination
*     d4 = DY1       = coor destination

	sub.w	d1,d2		* d2 = height	

	move.l	LOG_SCR_ADR(pc),a0
	mulu	#BPL_WIDTH*BPL_DEPTH,d1
	add.l	d1,a0

	moveq	#$f,d1
	and.w	d0,d1		* d1 = shift of source
	moveq	#$f,d6
	and.w	d3,d6		* d6 = shift of target
	sub.w	d1,d6		* d6 = shift for blt
	
	move.l	PHY_SCR_ADR(pc),a1
	mulu	#BPL_WIDTH*BPL_DEPTH,d4
	add.l	d4,a1
	and.w	#$fff0,d3
	lsr.w	#3,d3
	lea	(a1,d3.w),a1	* a1 = target adr

	tst.w	d6
	bge.s	.SHIFT_GE_0
	add.w	#16,d6
	lea	-BPL_WIDTH*BPL_DEPTH(a1),a1
	addq.w	#1,d2
.SHIFT_GE_0

	move.w	#$8000,d5
	lsr.w	d1,d5

	and.w	#$fff0,d0
	lsr.w	#3,d0
	lea	(a0,d0.w),a0	* a0 = source adr

	
	lsl.w	#6,d2
	or.w	#1,d2		* d2 = BLTSIZE

	ror.w	#4,d6
	and.w	#$f000,d6
	move.w	d6,d1
	or.w	#$07ca,d1

	lea	CUSTOM,a5
	WAIT_BLT
	move.w	#BPL_WIDTH*BPL_DEPTH-2,BLTBMOD(a5)
	move.w	#BPL_WIDTH*BPL_DEPTH-2,BLTCMOD(a5)
	move.w	#BPL_WIDTH*BPL_DEPTH-2,BLTDMOD(a5)
	move.l	#-1,BLTAFWM(a5)
	moveq	#BPL_DEPTH-1,d7
.LOOP_EACH_BPL	
	WAIT_BLT
	move.w	d5,BLTADAT(a5)
	move.w	d1,BLTCON0(a5)
	move.w	d6,BLTCON1(a5)

	move.l	a0,BLTBPT(a5)
	move.l	a1,BLTCPT(a5)
	move.l	a1,BLTDPT(a5)
	move.w 	d2,BLTSIZE(a5)
	lea	BPL_WIDTH(a0),a0
	lea	BPL_WIDTH(a1),a1
	dbf	d7,.LOOP_EACH_BPL	
		
	rts
**************************************** END_COPY_VERTICAL_LINE

ZOOM_VERTICAL: ****************************************************
	moveq	#0,d0 
	move.w	DY2(pc),d0
	sub.w	DY1(pc),d0
	moveq	#0,d1
	move.w	OY2(pc),d1
	sub.w	OY1(pc),d1
	swap	d1
	bsr	DIV_32_BITS
	move.l	d0,COEF_VERTICAL

	move.l	OY1,CUR_OY	
	move.l	DY1,CUR_DY	
.LOOP_EACH_LINE

	move.w	OX1(pc),d0
	move.w	CUR_OY(pc),d1
	move.w	OX2(pc),d2
	move.w	DX1(pc),d3
	move.w	CUR_DY(pc),d4
	
	bsr	COPY_HORIZONTAL_LINE

	move.l	COEF_VERTICAL(pc),d0
	add.l	d0,CUR_OY
	addq.w	#1,CUR_DY
	
	move.w	CUR_DY,d0
	cmp.w	DY2,d0
	blt.s	.LOOP_EACH_LINE
	
	rts
************************************************* END_ZOOM_HORIZONTAL

COPY_HORIZONTAL_LINE: *******************************************
* IN: d0 = OX1       = coor origine
*     d1 = CUR_OY    = coor origine
*     d2 = OX2       = coor origine
*     d3 = DX1       = coor destination
*     d4 = CUR_DY    = coor destination


	move.l	FIRST_SCR_ADR(pc),a0
	mulu	#BPL_WIDTH*BPL_DEPTH,d1
	add.l	d1,a0

	and.w	#$fff0,d0
	and.w	#$fff0,d2
	lsr.w	#3,d0
	lsr.w	#3,d2
	
	lea	(a0,d0.w),a0

	move.l	LOG_SCR_ADR(pc),a1
	subq.w	#1,d4
	mulu	#BPL_WIDTH*BPL_DEPTH,d4
	add.l	d4,a1

	and.w	#$fff0,d3
	lsr.w	#3,d3
	lea	(a1,d3.w),a1
	
	sub.w	d0,d2
	addq.w	#2,d2		* d2 = largeur de la ligne en octet
	
	move.w	#BPL_WIDTH,d1
	sub.w	d2,d1		* d1 = modulo
	
	lsr.w	#1,d2
	or.w	#BPL_DEPTH<<6,d2	* d2 = BLTSIZE

	lea	CUSTOM,a5
	WAIT_BLT
	move.l	#-1,BLTAFWM(a5)
	move.l	#$09f00000,BLTCON0(a5)
	move.w	d1,BLTAMOD(a5)
	move.w	d1,BLTDMOD(a5)
	move.l	a0,BLTAPT(a5)
	move.l	a1,BLTDPT(a5)
	move.w 	d2,BLTSIZE(a5)
		
	rts
**************************************** END_COPY_HORIZONTAL_LINE

DIV_32_BITS: ***********************************************
* routine de division d'un chiffre 32 bits part un chiffre 16 bit avec un
* resultat 32 bits. Elle est directement tire de mise en oeuvre du 68000
* de sybex (tres bon livre soit dit en passant).
* in: d0 = X   chiffre 16 bits
*     d1 = YZ  chiffre 32 bits
* out: d0 = resultat 32 bits
* d0-d3 sont detruit
	moveq	#0,d3

	divu	d0,d1
	bvc.s	.RESULT 
	move.l	d1,d2
	clr.w	d1
	swap	d1
	divu	d0,d1
	move.w	d1,d3
	move.w	d2,d1
	divu	d0,d1
.RESULT	move.l	d1,d0
	swap	d1
	move.w	d3,d1
	swap	d1
	move.l	d1,d0
	rts
******************************************** END_DIV_32_BITS


PUT_PIC_IN_PHY_SCR: ***************************************************
* Cette routine prend l'image en format bitmap et la met au format
* plan de ligne entrelacee.
 
	lea	PIC_BMP,a0
	move.l	FIRST_SCR_ADR(pc),a2
	move.w	#BPL_DEPTH-1,d0
.LOOP_EACH_BPL
	move.l 	a2,a1
	move.w	#BPL_Y-1,d1
.LOOP_EACH_LINE:
	move.w	#BPL_X/16-1,d2
.LOOP_EACH_WORD:
	move.w	(a0)+,(a1)+
	dbf	d2,.LOOP_EACH_WORD
	lea	BPL_WIDTH*(BPL_DEPTH-1)(a1),a1
	dbf	d1,.LOOP_EACH_LINE
	lea	BPL_WIDTH(a2),a2
	dbf	d0,.LOOP_EACH_BPL
	
	lea	COLOR+CUSTOM,a1
	move.w	#(1<<BPL_DEPTH)-1,d0
.LOOP_EACH_COLOR:
  	move.w	(a0)+,(a1)+
	dbf	d0,.LOOP_EACH_COLOR
	rts
************************************************ END_PUT_PIC_IN_PHY_SCR

INIT_END: *********************************************************
* reactivation de l'ancienne COPLIST
	lea	CUSTOM,a5
	move.l	(EXECBASE).w,a6
	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

* et on retourne d'ou l'on vient.
	moveq	#0,d0	* flag d'erreur desactive
	rts

GfxName:		dc.b	"graphics.library",0
	EVEN
******************************************************* end_INIT_END


BUILD_COPLIST: ********************************************************
	move.l	COPLIST_ADR,a0
	move.l	PHY_SCR_ADR,d2
	moveq	#BPL_DEPTH-1,d0
	move.w	#bplpt,d1

.LOOP_INIT_BPL_IN_CLIST
	move.w	d1,(a0)+
	addq.l	#2,d1
	swap	d2
	move.w	d2,(a0)+
	swap	d2
	move.w	d1,(a0)+
	addq.l	#2,d1
	move.w	d2,(a0)+
	add.l	#BPL_WIDTH,d2
	dbf	d0,.LOOP_INIT_BPL_IN_CLIST
	
	move.l	#$fffffffe,(a0)+	* montre la fin de la clist
	rts
********************************************************* END_BUILD_COPLIST


COEF_VERTICAL:		ds.l	1  
COEF_HORIZONTAL:	ds.l	1
*
CUR_OX:		ds.l	1
CUR_OY:		ds.l	1
CUR_DX:		ds.l	1
CUR_DY:		ds.l	1
*
OX1:	ds.l	1
OY1:	ds.l	1
OX2:	ds.l	1
OY2:	ds.l	1
*
DX1:	ds.l	1
DY1:	ds.l	1
DX2:	ds.l	1
DY2:	ds.l	1


******** datas
*	variables
LOG_SCR_ADR:	dc.l	ECRAN1
PHY_SCR_ADR:	dc.l	ECRAN2
FIRST_SCR_ADR:	dc.l	ECRAN3
COPLIST_ADR:	dc.l	COPLIST
PIC_BMP:	INCBIN	Freddy.raw
		INCBIN	Freddy.pal

	section	ZONE_CHIP,BSS_C
ECRAN3:		ds.l	BPL_WIDTH*BPL_Y*BPL_DEPTH/4
ECRAN1:		ds.l	BPL_WIDTH*BPL_Y*BPL_DEPTH/4
ECRAN2:		ds.l	BPL_WIDTH*BPL_Y*BPL_DEPTH/4
COPLIST:	ds.l	1000*4	* taiile inconnue donc on prevoit gros
	end


[Retour en haut] / [Retour aux articles]