;+++++ How to move a sprite with 1/4 low res pixel precision
;+++++ How to acces to all sprites modes (resolution and size)
;:+++++ Coded by Yragael (April 1993)

	section prg,code_c
	incdir	work:prog/source4/
	include "registres.s"

;*************** INDEX FONCTIONS ***************

openlibrary=-552
forbid=-132
permit=-138
allocmem=-198
freemem=-210

;*************** PARAMETRES DE L'ECRAN ***************

nbplane=1
sizex=320
sizey=256

startx=129				;depart horizontal du tracé
starty=45				;depart vertical du tracé

tracex=320				;largeur de l'image a tracer à ...
					;... partir de startx

displayx=320				;largeur de l'image a visualiser à ...
					;... partir de startdisplayx
displayy=sizey				;hauteur de l'image a visualiser à ...
					;... partir de starty

startdisplayx=129			;debut horizontal visible de l'image

stopx=displayx+startdisplayx-256	;fin horizontale visible de l'image 
stopy=displayy+starty-256		;fin verticale visible de l'image

ddf_strt=(startx-17)/2 
ddf_stop=ddf_strt+(tracex/2-8)

modulo_pair=(sizex-tracex)/8
modulo_impair=(sizex-tracex)/8

planesize=sizey*sizex/8

;*************** CONSTANTES ***************

ecart=6
memory=$10000+2
copsize=32*4+8+9*4+nbplane*8+8*8+4

;32*4 (couleurs)
;9*4 (parametres screen)
;8*8 (adresses sprites)
;nbplane*8 (adresses bitplanes)
;8 ($01060000, $01FC0000)
;4 ($FFFFFFFE)

;*************** PROGRAMME PRINCIPAL ***************

;+++++ Cette routine de gestion de souris ne prend pas plus d'une raster line.
;+++++ Elle gere le deplacement de la souris au quart de pixel.

	bsr.w init

	move.l plane0adr,bltdpth
	move.w #0,bltdmod
	move.w #$0000,bltcon1
	move.w #%0000000111001100,bltcon0
	move.w #$AAAA,bltbdat
	move.w #sizex/16+64*sizey,bltsize
	bsr waitblit

;----- initialisations des positions -----

	movea.l posadr,a0
	lea sprite0start,a1
	rept 8*ecart
	move.w (a1),(a0)+
	move.w 8(a1),(a0)+
	endr

;----- initialisations -----

	move.w #$0000,joytest

;----- programme principal -----

boucle:
	bsr waitvbl

	move.w #$0000,color00

;----- cycling des positions -----

	move.w #$0002,bltcon1
	move.w #%0000010111001100,bltcon0
	move.w #0,bltdmod
	move.w #0,bltbmod
	movea.l posadr,a1
	lea 8*ecart*4-4(a1),a1
	move.l a1,bltdpth
	lea -4(a1),a1
	move.l a1,bltbpth
	move.w #2+64*(8*ecart-1),bltsize

;----- test de la souris -----

	move.w joy0dat,d0

;+++++ Pour pouvoir proceder aux manipulations sue les coordonnees, Il faut
;+++++ absolument pouvoir manipuler les compteurs X et Y de JOY0DAT sous
;+++++ forme de MOTS signes. Prenons le cas de l'octet de poids fort de
;+++++ JOY0DAT, relatif au deplacement vetical.
;+++++ L'octet de poids fort de JOY0DAT contient un compteur sur les 6 bits
;+++++ de poids forts. Les 2 bits de poids faibles ne nous interessent pas.
;+++++ On procede donc a un AND.W #$FC00 pour ne conserver que le compteur
;+++++ 6 bits. On replace ensuite cet octet dans l'octet de poids faible
;+++++ par un LSR.W #8. Ce compteur, si l'on considere sa valeur sur 6 bits
;+++++ signes, varie entre -31 et 31.
;+++++ Si l'on utilise directement le resultat obtenu apres le decalage de
;+++++ 8 bits, on va tenir compte des 2 bits de poids faible inutilisables
;+++++ (ce sont des bits hardwares de direction). On obtiendra alors
;+++++ une precision aleatoire sur les 2 derniers bits, soit sur 4 pixels.
;+++++ On procede donc a une extension du signe puis a un nouveau decalage
;+++++ de 2 bits vers la droite.
;+++++ La raison pour laquelle on n'a pas procede directement a un decalage
;+++++ de 10 bits vers la droite puis a un extension de signe est que la
;+++++ la valeur qui nous interesse est signee sur 6 bits et non sur 8 bits.
;+++++ Lors de l'extension du bit de signe par EXT.W (qui convertit
;+++++ un OCTET signe en un mot signe), le signe de la valeur signee sur
;+++++ 6 bits ne serait pas comptabilise, seul le signe de l'octet etant
;+++++ pris en compte !

	move.w d0,d1
	and.w #$FC00,d1
	and.w #$00FC,d0
	lsr.w #8,d1
	ext.w d1
	asr.w #2,d1		;d1=DY
	ext.w d0
	asr.w #2,d0		;d0=DX

;+++++ Pour tester s'il y a eu mouvement, verifier si le OR des 2 compteurs
;+++++ est different de 0.

	move.w d0,d2
	or.w d1,d2
	beq mousesuite0

;+++++ On reconstitue le position du sprite (codee sur 9 bits en vertical
;+++++ et 11 bits en horizontal).
;+++++ bit 0 du second mot de controle=bit 2 position horizontale
;+++++ bit 3 du second mot de controle=bit 0 position horizontale
;+++++ bit 4 du second mot de controle=bit 1 position horizontale
;+++++ bit 2 du second mot de controle=bit 8 position verticale

	lea sprite0start,a0
	move.w (a0),d3
	move.w 8(a0),d4

;+++++ d3=Y

	move.w d3,d2
	lsr.w #8,d3
	btst #2,d4
	beq mouseYsuite0
	bset #8,d3
mouseYsuite0:

;+++++ d2=X

	and.w #$FF,d2
	lsl.w #3,d2
	btst #0,d4
	beq mouseXsuite0
	bset #2,d2
mouseXsuite0:
	btst #3,d4
	beq mouseXsuite1
	bset #0,d2
mouseXsuite1:
	btst #4,d4
	beq mouseXsuite2
	bset #1,d2
mouseXsuite2:

;+++++ Controle de la zone de deplacement

	add.w d0,d2
	cmp.w #$80,d2
	bge clipXsuite0
	move.w #$80,d2
clipXsuite0:
	cmp.w #4*($80+sizex),d2
	ble clipXsuite1
	move.w #4*($80+sizex),d2
clipXsuite1:

	add.w d1,d3
	cmp.w #starty,d3
	bge clipYsuite0
	move.w #starty,d3
clipYsuite0:
	cmp.w #starty+sizey,d3
	ble clipYsuite1
	move.w #starty+sizey,d3
clipYsuite1:

;+++++ Modification des mots de controle du sprite (les decalages font un
;+++++ transfert de bit via C, d'ou les tests bcc).

;+++++ On calcule tout d'abord la ligne finale du sprite (L8-L0). On procede
;+++++ pour cela a un decalage de 8 bits vers la gauche et on additionne
;+++++ la taille verticale du sprite decalee de 8 bits vers la gauche elle
;+++++ aussi (ici, $8000=128 lignes).
;+++++ On procede, lors de cette addition, a un test de retenue. Si l'on a une
;+++++ retenue, le bit 1 du second mot de controle (L8) est alors mis a 1.
;+++++ Si l'on a pas de retenue, rien n'est fait concernant le bit L8. Mais
;+++++ l'on pourrait ne pas avoir de retenue et que le bit L8 doive etre
;+++++ a 1, le bit E8 etant deja a 1 (ex: position verticale=%(1)00000000
;+++++ on ajoute $4000 pour obtenir la ligne finale=%(1)10000000. Pas de
;+++++ debordement sur le test bcc setYsuite0 !).
;+++++ Ce cas de figure est gere lors du test du bit E8 qui met a 1 les
;+++++ bits 2 et 1 du second mot de controle si E8 est a 1, la ligne finale
;+++++ du sprite se trouvant forcement a une ligne superieure de la position
;+++++ verticale.
;+++++ On considere ici que la taille verticale du sprite ne depasse pas
;+++++ $FF, ce qui serait tout a fait possible.

	move.w d3,d0
	lsl.w #8,d0
	add.w #$8000,d0
	bcc setYsuite0
	bset #1,d0
setYsuite0:

	lsr.w #1,d2
	bcc setXsuite0
	bset #3,d0
setXsuite0:
	lsr.w #1,d2
	bcc setXsuite1
	bset #4,d0
setXsuite1:
	lsr.w #1,d2
	bcc setXsuite2
	bset #0,d0
setXsuite2:

	lsl.w #8,d3
	bcc setYsuite1
	bset #2,d0
	bset #1,d0
setYsuite1:
	or.w d2,d3
	move.w d3,(a0)
	move.w d0,8(a0)

	move.w #$0000,joytest
mousesuite0:

;----- copies des positions dans les mots de controles -----

	bsr waitblit
	lea sprite0start,a0
	movea.l posadr,a1
	move.w (a0),(a1)
	move.w 8(a0),2(a1)

	lea ecart*4(a1),a1
	lea sprite1start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite2start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite3start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite4start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite5start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite6start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)
	lea ecart*4(a1),a1
	lea sprite7start,a0
	move.w (a1),(a0)
	move.w 2(a1),8(a0)

	move.w #$0ff0,color00
	btst #6,$bfe001
	bne boucle
	bsr fin
	rts

;*************** INITIALISATION ***************

init:
	
;memoire pour copperlist

	move.l $4,a6
	move.l #copsize,d0
	move.l #memory,d1
	jsr allocmem(a6)
	move.l d0,copadr

;memoire pour bitplane 0

	move.l #planesize,d0
	move.l #memory,d1
	jsr allocmem(a6)
	move.l d0,plane0adr

;memoire pour positions curseur

	move.l #8*ecart*4,d0
	move.l #memory,d1
	jsr allocmem(a6)
	move.l d0,posadr

;creation de la copperlist

	move.l copadr,a0

	move.l #$01060000,(a0)+		;bit 7-6:  11 (superhires) 10(hires) 00(lowres)
	move.l #$01FC000C,(a0)+		;bit 3-2:  00(16p) 01(32p) 11(64p)

	move.l #$01820000,(a0)+
	move.l #$01820000,(a0)+
	move.l #$01840000,(a0)+
	move.l #$01860000,(a0)+
	move.l #$01880000,(a0)+
	move.l #$018A0000,(a0)+
	move.l #$018C0000,(a0)+
	move.l #$018E0000,(a0)+
	move.l #$01900000,(a0)+
	move.l #$01920000,(a0)+
	move.l #$01940000,(a0)+
	move.l #$01960000,(a0)+
	move.l #$01980000,(a0)+
	move.l #$019A0000,(a0)+
	move.l #$019C0000,(a0)+
	move.l #$019E0000,(a0)+
	move.l #$01A00000,(a0)+
	move.l #$01A20000,(a0)+
	move.l #$01A40F00,(a0)+
	move.l #$01A60B24,(a0)+
	move.l #$01A80000,(a0)+
	move.l #$01AA0000,(a0)+
	move.l #$01AC0F00,(a0)+
	move.l #$01AE0B24,(a0)+
	move.l #$01B00000,(a0)+
	move.l #$01B20000,(a0)+
	move.l #$01B40F00,(a0)+
	move.l #$01B60B24,(a0)+
	move.l #$01B80000,(a0)+
	move.l #$01BA0000,(a0)+
	move.l #$01BC0F00,(a0)+
	move.l #$01BE0B24,(a0)+

	move.w #$008E,(a0)+		;DIWSTRT
	move.w #starty*256+startdisplayx,(a0)+
	move.w #$0090,(a0)+		;DIWSTOP
	move.w #stopy*256+stopx,(a0)+
	move.w #$0100,(a0)+		;BPLCON0
	move.w #nbplane,d0
	ror.w #4,d0
	bset #9,d0
	move.w d0,(a0)+
	move.w #$0102,(a0)+		;BPLCON1
	move.w #$0000,(a0)+
	move.w #$0104,(a0)+		;BPLCON2
	move.w #$00FF,(a0)+
	move.w #$0092,(a0)+		;DDFSTRT
	move.w #ddf_strt,(a0)+
	move.w #$0094,(a0)+		;DDFSTOP
	move.w #ddf_stop,(a0)+
	move.w #$0108,(a0)+		;BPL1MOD
	move.w #modulo_pair,(a0)+
	move.w #$010A,(a0)+		;BPL2MOD
	move.w #modulo_impair,(a0)+

	move.l plane0adr,d0
	move.w #$E2,(a0)+
	move.w d0,(a0)+
	move.w #$E0,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite0start,d0
	move.w #$0120,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$0122,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite1start,d0
	move.w #$0124,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$0126,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite2start,d0
	move.w #$0128,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$012A,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite3start,d0
	move.w #$012C,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$012E,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite4start,d0
	move.w #$0130,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$0132,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite5start,d0
	move.w #$0134,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$0136,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite6start,d0
	move.w #$0138,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$013A,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #sprite7start,d0
	move.w #$013C,(a0)+
	swap d0
	move.w d0,(a0)+
	move.w #$013E,(a0)+
	swap d0
	move.w d0,(a0)+

	move.l #$FFFFFFFE,(a0)

;modif DMA,...
	
	jsr forbid(a6)
	move.w #$03F0,dmacon		;couper tous les DMA
	move.l copadr,cop1lch		;adresse coplist
	clr.w copjmp1			;copjump1
	move.w #$87E0,dmacon		;BLTEN, COPEN, BPLEN, SPREN et BLTPRI

	rts
	
;*************** FIN PROGRAMME ***************

fin:

;restaurer la copperlist du dos

	move.l $4,a6
	move.l #grname,a1
	clr.l d0
	jsr openlibrary(a6)
	move.l d0,a4
	move.w #$03FF,dmacon
	move.l 38(a4),cop1lch
	clr.w copjmp1
	move.w #$83F0,dmacon
	jsr permit(a6)

;liberation memoire copper

	move.l copadr,a1
	move.l #copsize,d0
	jsr freemem(a6)	

;liberation memoire biplane 0

	move.l plane0adr,a1
	move.l #planesize,d0
	jsr freemem(a6)	

;liberation memoire positions curseur

	move.l posadr,a1
	move.l #8*ecart*4,d0
	jsr freemem(a6)	

	rts
	
;*************** WAITBLIT ***************

waitblit:
	btst #14,dmaconr
	bne waitblit
	rts
	
;*************** LEFTCLICK ***************

leftclick:
	btst #6,$BFE001
	bne leftclick
	rts

;*************** ATTENTE ***************

attente:

attente1:
	cmp.b #$39,$bfec01
	bne attente1
attente2:
	cmp.b #$37,$bfec01
	bne attente2
	rts

;*************** WAITVBL ***************

waitvbl:
	cmp.b #$FF,vhposr
	bne waitvbl	
	rts

;*************** VARIABLES ***************

plane0adr:	dc.l 0
oldirq:		dc.l 0
copadr:		dc.l 0
posadr:		dc.l 0
grname:		dc.b 'graphics.library',0

	cnop 16,16

sprite0start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite0end:
sprite0size=sprite0end-sprite0start

sprite1start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite1end:
sprite1size=sprite1end-sprite1start

sprite2start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite2end:
sprite2size=sprite2end-sprite2start

sprite3start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite3end:
sprite3size=sprite3end-sprite3start

sprite4start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite4end:
sprite4size=sprite4end-sprite4start

sprite5start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite5end:
sprite5size=sprite5end-sprite5start

sprite6start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite6end:
sprite6size=sprite6end-sprite6start

sprite7start:
	dc.w $0040,$0000,$0000,$0000
	dc.w $8000,$0000,$0000,$0000
	rept 128
	dc.w $0000,$FFFF,$0F0F,$0000
	dc.w $0F00,$FF00,$0045,$1245
	endr
	dc.w $0000,$0000,$0000,$0000
sprite7end:
sprite7size=sprite7end-sprite7start
