
; Listing10h1.s		Kollision zwischen BOB und Hintergrund
; mit dem ZERO-Flag des Blitters.
; linke Taste zum Beenden.

	SECTION	BLIT,CODE

;	include	"DaWorkBench.s"	; entferne das ; vor dem Speichern mit "wo"

*****************************************************************************
	include	"/Sources/startup1.s"	; speichern Copperlist etc.
*****************************************************************************

			;5432109876543210
DMASET	equ	%1000001111000000	; Bitplane, Copper, Blitter DMA


Start:
	move.l	#Bitplane,d0		; Zeiger auf die "leeren" Bitplanes
	lea	Bplpointers,a1			; Bitplanepointer
	moveq	#3-1,d1				; Anzahl der Bitplanes (hier sind es 3)
PointBp:
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)
	swap	d0
	add.l	#40*256,d0			; + LÄNGE EINER PLANE !!!!!
	addq.w	#8,a1
	dbra	d1,PointBp

	lea	$dff000,a5				; Custom Register Base in a5
	move.w	#DMASET,$96(a5)		; DMACON - einschalten Bitplane, Copper, Blitter
	move.l	#Copperlist,$80(a5)	; Zeiger Copperlist
	move.w	d0,$88(a5)			; Start Copperlist
	move.w	#0,$1fc(a5)			; AGA "deaktivieren"
	move.w	#$c00,$106(a5)		; AGA "deaktivieren"
	move.w	#$11,$10c(a5)		; AGA "deaktivieren"

Mouse:
	bsr.s	MoveObject			; bewege den Bob
	bsr.w	ControlCollision	; Überprüfen und alle Kollisionen
								; zwischen Bob und Hintergrund melden				
	bsr.w	SaveBackground		; Speichere den Hintergrund
	bsr.w	DesignObject		; zeichne den Bob

	move.l	#$1ff00,d1			; Bit zur Auswahl durch UND
	move.l	#$13000,d2			; Warte auf Zeile $130 (304)
WarteY1:
	move.l	4(a5),d0			; VPOSR und VHPOSR - $dff004/$dff006
	and.l   d1,d0				; Wählen Sie nur die Bits der vertikalen Pos.
	cmp.l   d2,d0				; Warte auf Zeile $130 (304)
	bne.s	WarteY1

	bsr.w	RestoreBackground	; stelle den Hintergrund wieder her

	btst	#6,$bfe001			; linke Maustaste gedrückt?
	bne.s	Mouse				; wenn nicht, gehe zurück zu Mouse:

	rts
	
;****************************************************************************
; Diese Routine bewegt den Bob auf dem Bildschirm.
;****************************************************************************

MoveObject
	addq.w	#1,ObjY				; Verschiebe den Bob nach unten
	cmp.w	#256-11,ObjY		; hat es die untere Kante erreicht?
	bls.s	EndMove				; wenn kein Ende
	clr.w	ObjY				; ansonsten von oben starten
EndMove
	rts

;***************************************************************************
; Diese Routine zeichnet den BOB an die in den Variablen ObjX und ObjY
; angegebenen Koordinaten.
;****************************************************************************

;	 ||||||||
;	 | =  = |
;	@| O  O |@
;	 |  ()  |
;	 ((\__/))
;	  ((()))
;	   ))((
;	    ()

DesignObject:
	lea	Bitplane,a0				; Ziel in a0
	move.w	ObjY(pc),d0			; Koordinate Y
	mulu.w	#40,d0				; Adresse berechnen: Jede Zeile besteht aus
								; 40 Bytes
	add.w	d0,a0				; zur Anfangsadresse hinzufügen

	move.w	ObjX(pc),d0			; Koordinate X
	move.w	d0,d1				; Kopie
	and.w	#$000f,d0			; wir wählen die ersten 4 Bits, weil sie 
								; in den Shifter von Kanal A eingefügt werden
	lsl.w	#8,d0				; Die 4 Bits werden zum High-Nibble 
	lsl.w	#4,d0				; des Wortes bewegt...
	move.w	d0,d2

	or.w	#$0fca,d0			; ... rechts, in das BLTCON0-Register einzugeben
	lsr.w	#3,d1				; (entspricht einer Division durch 8)
								; Runden auf ein Vielfaches von 8 für den Zeiger
								; auf den Bildschirm, also auch auf ungerade Adressen
								; (also zu Bytes)
								; zB: eine 16 als Koordinate wird zu Byte 2
	and.w	#$fffe,d1			; Ich schließe Bit 0 der
	add.w	d1,a0				; addieren zur Adresse der Bitebene, 
								; um die richtige Zieladresse zu finden

	lea	Figur,a1				; Zeiger Quelle
	moveq	#3-1,d7				; wiederhole es für jede Ebene
PlaneLoop:
	btst	#6,2(a5)
WaitBlit:
	btst	#6,2(a5)			; warte auf das Ende des Blitters
	bne.s	WaitBlit

	move.l	#$ffff0000,$44(a5)	; BLTAFWM = $ffff es passiert alles
								; BLTALWM = $0000 setzt das letzte Wort zurück
								
	move.w	d0,$40(a5)			; BLTCON0 (A,B,C,D)
	move.w	d2,$42(a5)			; BLTCON1 (keine Spezialmodi)
	move.l	#$0022fffe,$60(a5)	; BLTCMOD=40-6=34=$22
								; BLTBMOD=$fffe=-2
	move.l	#$fffe0022,$64(a5)	; BLTAMOD=$fffe=-2 komm zurück
								; an den Anfang der Zeile.
								; BLTDMOD=40-6=34=$22 wie immer
	move.l	#Maske,$50(a5)		; BLTAPT (an der Quellfigur fixiert)
	move.l	a0,$54(a5)			; BLTDPT (Bildschirm)
	move.l	a0,$48(a5)			; BLTCPT (Bildschirm)
	move.l	a1,$4c(a5)			; BLTBPT (Quellfigur)
	move.w	#(64*11)+3,$58(a5)	; BLTSIZE (Blitter starten !)

	lea	4*11(a1),a1				; zeigt auf die nächste Quellebene
								; jede Bitplane ist 2 Wörter breit und 
								; 11 Zeilen hoch

	lea	40*256(a0),a0			; zeigt auf die nächste Zielebene
	dbra	d7,PlaneLoop

	rts

;****************************************************************************
; Diese Routine kopiert das Hintergrundrechteck, das mit dem 
; BOB überschrieben wird in einen Puffer
;****************************************************************************

SaveBackground:
	lea	Bitplane,a0				; Ziel in a0
	move.w	ObjY(pc),d0			; Koordinate Y
	mulu.w	#40,d0				; Adresse berechnen: Jede Zeile besteht aus
								; 40 Bytes
	add.w	d0,a0				; zur Anfangsadresse hinzufügen

	move.w	ObjX(pc),d1			; Koordinate X
	lsr.w	#3,d1				; (entspricht einer Division durch 8)
								; Runden auf ein Vielfaches von 8 für den Zeiger
								; auf den Bildschirm, also auch auf ungerade Adressen
								; (also zu Bytes)
								; zB: eine 16 als Koordinate wird zu Byte 2
	and.w	#$fffe,d1			; Ich schließe Bit 0 der
	add.w	d1,a0				; addieren zur Adresse der Bitebene, 
								; um die richtige Zieladresse zu finden

	lea	Buffer,a1				; Zeiger Ziel
	moveq	#3-1,d7				; wiederhole es für jede Ebene
PlaneLoop2:	
	btst	#6,2(a5)			; DMACONR
WaitBlit2:
	btst	#6,2(a5)			; DMACONR - warte auf das Ende des Blitters
	bne.s	WaitBlit2

	move.l	#$ffffffff,$44(a5)	; BLTAFWM = $ffff es passiert alles
								; BLTALWM = $ffff es passiert alles
								
	move.l	#$09f00000,$40(a5)	; BLTCON0 und BLTCON1 Kopie von A nach D
	move.l	#$00220000,$64(a5)	; BLTAMOD=40-6=34=$22
								; BLTDMOD=0 Puffer
	move.l	a0,$50(a5)			; BLTAPT - Adresse Quelle
	move.l	a1,$54(a5)			; BLTDPT - Puffer
	move.w	#(64*11)+3,$58(a5)	; BLTSIZE (Blitter starten !)

	lea	40*256(a0),a0			; zeigt auf die nächste Quellebene
	lea	6*11(a1),a1				; zeigt auf die nächste Zielebene
								; Jeder Blitt ist 3 Wörter breit und 
								; 11 Zeilen hoch
	dbra	d7,PlaneLoop2

	rts

;****************************************************************************
; Diese Routine kopiert den Inhalt des Puffers in das Bildschirmrechteck
; was es vor der BOB-Zeichnung enthielt. Auf diese Weise kommt es auch, das
; das BOB vom alten Standort gelöscht wird.
;****************************************************************************

RestoreBackground:
	lea	Bitplane,a0				; Ziel in a0
	move.w	ObjY(pc),d0			; Koordinate Y
	mulu.w	#40,d0				; Adresse berechnen: Jede Zeile besteht aus
								; 40 Bytes
	add.w	d0,a0				; zur Adresse der Abfahrt hinzufügen

	move.w	ObjX(pc),d1			; Koordinate X
	lsr.w	#3,d1				; (entspricht einer Division durch 8)
								; Runden auf ein Vielfaches von 8 für den Zeiger
								; auf den Bildschirm, also auch auf ungerade Adressen
								; (also zu Bytes)
								; zB: eine 16 als Koordinate wird zu Byte 2
	and.w	#$fffe,d1			; Ich schließe Bit 0 der
	add.w	d1,a0				; addieren zur Adresse der Bitebene, 
								; um die richtige Zieladresse zu finden

	lea	Buffer,a1				; Zeiger Quelle
	moveq	#3-1,d7				; wiederhole es für jede Ebene
PlaneLoop3:
	btst	#6,2(a5)			; DMACONR
WaitBlit3:
	btst	#6,2(a5)			; warte auf das Ende des Blitters
	bne.s	WaitBlit3

	move.l	#$ffffffff,$44(a5)	; BLTAFWM = $ffff es passiert alles
								; BLTALWM = $ffff es passiert alles
								
	move.l	#$09f00000,$40(a5)	; BLTCON0 und BLTCON1 Kopie von A nach D
	move.l	#$00000022,$64(a5)	; BLTAMOD=0 (Puffer)
								; BLTDMOD=40-4=36=$22
	move.l	a1,$50(a5)			; BLTAPT (Puffer)
	move.l	a0,$54(a5)			; BLTDPT (Bildschirm)
	move.w	#(64*11)+3,$58(a5)	; BLTSIZE (Blitter starten!)

	lea	40*256(a0),a0			; zeigt auf die nächste Zielebene
	lea	6*11(a1),a1				; zeigt auf die nächste Quellebene
								; Jeder Blitt ist 3 Wörter breit und 
								; 11 Zeilen hoch
	dbra	d7,PlaneLoop3
	rts

ObjY:		dc.w	0			; hier wird das Y des Objekts gespeichert
ObjX:		dc.w	100			; hier wird das X des Objekts gespeichert


;****************************************************************************
; Diese Routine kontrolliert das Auftreten einer Kollision
;****************************************************************************

ControlCollision:
	lea	Bitplane,a0				; Ziel in a0
	move.w	ObjY(pc),d0			; Koordinate Y
	mulu.w	#40,d0				; Adresse berechnen: Jede Zeile besteht aus
								; 40 Bytes
	add.w	d0,a0				; zur Anfangsadresse hinzufügen

	move.w	ObjX(pc),d0			; Koordinate X
	move.w	d0,d1				; Kopie
	and.w	#$000f,d0			; wir wählen die ersten 4 Bits, weil sie 
								; in den Shifter von Kanal A eingefügt werden
	lsl.w	#8,d0				; Die 4 Bits werden zum High-Nibble 
	lsl.w	#4,d0				; des Wortes bewegt...
	move.w	d0,d2

	or.w	#$0aa0,d0			; ... rechts, in das BLTCON0-Register einzugeben
								; nur Kanäle A und C sind aktiv (kein D)
								; führe ein AND zwischen A und C aus

	lsr.w	#3,d1				; (entspricht einer Division durch 8)
								; Runden auf ein Vielfaches von 8 für den Zeiger
								; auf den Bildschirm, also auch auf ungerade Adressen
								; (also zu Bytes)
								; zB: eine 16 als Koordinate wird zu Byte 2
	and.w	#$fffe,d1			; Ich schließe Bit 0 der
	add.w	d1,a0				; addieren zur Adresse der Bitebene, 
								; um die richtige Zieladresse zu finden

; wartet darauf, dass der Blitter beendet wird, bevor die Register geändert werden
	btst	#6,2(a5)
WaitBlit4:
	btst	#6,2(a5)
	bne.s	WaitBlit4

	lea	Maske,a1				; Zeiger Kollisionsmasken
	moveq	#3-1,d7				; wiederhole es für jede Ebene
CollLoop:
	move.l	#$ffff0000,$44(a5)	; BLTAFWM = $ffff es passiert alles
								; BLTALWM = $0000 setzt das letzte Wort zurück

	move.w	d0,$40(a5)			; BLTCON0 					
								; nur die Kanäle A und C sind aktiv
								; (nicht D). Führt ein UND zwischen A und C aus
	move.w	#$0000,$42(a5)		; BLTCON1 (keine Spezialmodi)
	move.w	#$0022,$60(a5)		; BLTCMOD=40-6=34=$22
	move.w	#$fffe,$64(a5)		; BLTAMOD=$fffe=-2 komm zurück
								; an den Anfang der Zeile.
	move.l	a1,$50(a5)			; BLTAPT (an der Quellfigur fixiert)
	move.l	a0,$48(a5)			; BLTCPT (Bildschirm)
	move.w	#(64*11)+3,$58(a5)	; BLTSIZE (Blitter starten !)

	lea	40*256(a0),a0			; Zeige auf die nächste Ebene auf dem Bildschirm

	btst	#6,2(a5)
WaitBlit5:
	btst	#6,2(a5)			; warte auf das Ende des Blitters
	bne.s	WaitBlit5			; vor dem Testen des Zero-Flag

	btst	#5,2(a5)			; testet das Zero-Flag.
	beq.s	YesColl				; wenn das Flag Null ist, gibt
								; es eine Kollision zu melden.
								; ansonsten überprüfe die nächste Bitplane

	dbra	d7,CollLoop			; wenn für keine Bitplane eine
								; Kollision auftrat, die Schleife verlassen
		
NoColl:
	move.w	#$000,$180(a5)		; keine Kollisionen aufgetreten:
								; schwarzer Bildschirm
	bra.s	EndColl				; springe zum Ende der Routine

YesColl:	
	move	#$f00,$180(a5)		; eine Kollision wurde festgestellt:
								; roter Bildschirm

EndColl:
	rts

;****************************************************************************

	SECTION	GRAPHIC,DATA_C

Copperlist:
	dc.w	$8e,$2c81			; DIWSTRT
	dc.w	$90,$2cc1			; DIWSTOP
	dc.w	$92,$38				; DDFSTRT
	dc.w	$94,$d0				; DDFSTOP
	dc.w	$102,0				; BPLCON1
	dc.w	$104,0				; BPLCON2
	dc.w	$108,0				; WERT MODULO = 0
	dc.w	$10a,0				; BEIDE MODULO MIT GLEICHEN WERT.

	dc.w	$100,$3200			; BPLCON0 - 3 Bitplanes lowres

Bplpointers:
	dc.w	$e0,$0000,$e2,$0000	; erste Bitplane
	dc.w	$e4,$0000,$e6,$0000
	dc.w	$e8,$0000,$ea,$0000

	dc.w	$0182,$475			; COLOR01
	dc.w	$0184,$fff			; COLOR02
	dc.w	$0186,$ccc			; COLOR03
	dc.w	$0188,$999			; COLOR04
	dc.w	$018a,$232			; COLOR05
	dc.w	$018c,$777			; COLOR06
	dc.w	$018e,$444			; COLOR07

	dc.w	$ffff,$fffe			; Ende Copperlist

;****************************************************************************

; Dies sind die Daten, aus denen die Figur des Bobs besteht.
; Der Bob ist im normalen Format, 32 Pixel breit (2 Wörter)
; 11 Zeilen hoch und von 3 Bitplanes gebildet

Figur:
	dc.l	$007fc000			; plane 1
	dc.l	$03fff800
	dc.l	$07fffc00
	dc.l	$0ffffe00
	dc.l	$1fe07f00
	dc.l	$1fe07f00
	dc.l	$1fe07f00
	dc.l	$0ffffe00
	dc.l	$07fffc00
	dc.l	$03fff800
	dc.l	$007fc000

	dc.l	$00000000			; plane 2
	dc.l	$007fc000
	dc.l	$03fff800
	dc.l	$07fffc00
	dc.l	$0fe07e00
	dc.l	$0fe07e00
	dc.l	$0fe07e00
	dc.l	$07fffc00
	dc.l	$03fff800
	dc.l	$007fc000
	dc.l	$00000000

	dc.l	$007fc000			; plane 3
	dc.l	$03803800
	dc.l	$04000400
	dc.l	$081f8200
	dc.l	$10204100
	dc.l	$10204100
	dc.l	$10204100
	dc.l	$081f8200
	dc.l	$04000400
	dc.l	$03803800
	dc.l	$007fc000

Maske:
	dc.l	$007fc000
	dc.l	$03fff800
	dc.l	$07fffc00
	dc.l	$0ffffe00
	dc.l	$1fe07f00
	dc.l	$1fe07f00
	dc.l	$1fe07f00
	dc.l	$0ffffe00
	dc.l	$07fffc00
	dc.l	$03fff800
	dc.l	$007fc000

;****************************************************************************

Bitplane:
	incbin	"/Sources/amiga.raw"	; Hier laden wir die Figur ein
								; mit KEFCON konvertiert.

;****************************************************************************

	SECTION	BUFFER,BSS_C

; Dies ist der Puffer, in dem wir den Hintergrund von Zeit zu Zeit speichern.
; Er hat die gleichen Abmessungen wie ein Blitt: Höhe 11, Breite 3 Wörter
; 3 Bitebenen

Buffer:
	ds.w	11*3*3

	end

;****************************************************************************

In diesem Beispiel wird gezeigt, wie Kollisionen zwischen dem Bob und dem 
Hintergrund erkannt werden. Um Kollision zu erkennen, verwenden Sie das 
Zero-Flag des Blitters. Die Technik ist die Folgende: Wir führen einen Blitt
durch, der ein UND zwischen der Maske des Bobs und der Maske des Hintergrund
macht, aber ohne das Ausgabeergebnis zu schreiben. Wenn die UND-Verknüpfung als
Ergebnis eine Null für alle Bits des Blitts liefert, nimmt das Zero-Flag den
Wert 1 an. Die Tatsache, dass die AND-Operation ein 0-Ergebnis liefert,
bedeutet, dass in keinem Fall ein Teil der Maske mit dem Hintergrund
übereinstimmt, also gibt es keine Kollision.
Wenn stattdessen mindestens ein Bit der Maske mit einem Bit des Hintergrunds 
übereinstimmt, bedeutet dies dass es eine Kollision gab. In diesem Fall wie
beim UND zwischen diesen 2 Bits ist das Ergebnis 1, das ZERO-Flag nimmt den
Wert 0 an und an diesem können wir erkennen, dass es eine Kollision gegeben
hat.
Beachten Sie, dass die Maske für den Bob zwar vorhanden ist, für den 
Hintergrund jedoch nicht. Diese Tatsache zwingt uns, die Kollision zwischen 
der Bobmaske und allen Ebenen der Figur zu überprüfen. Mit einer 
Hintergrundmaske könnten wir die Kollision mit nur einem Blitt zwischen den
Masken testen. Machen Sie es als Übung.
Beachten Sie auch, dass Sie vor dem Testen des Zero-Flags auf das Ende des
Blitts warten müssen.   