
; Listing9i5.s		Bob schneidet nach rechts ab. (von Erra Ugo)
; der Bob wird mit dem Joystick (Port2) bewegt
; Linke Taste zum Verlassen.

	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


; Wir definieren in diesen Gleichungen die Konstanten relativ zu unserem Bob...

XBob	equ	16*8				; Dimension X des Bobs
YBob	equ	29					; Dimension Y des Bobs
XWord	equ	8					; Anzahl der Wörter des Bobs

; Wir definieren die Grenzen des Bildschirms

XMax	=	320-64				; rechte horizontale Grenze des Bildschirms
XMin	=	0					; Linke horizontale Grenze des Bildschirms
YMax	=	200-YBob			; Untere vertikale Grenze des Bildschirms
YMin	=	0					; Obere vertikale Grenze des Bildschirms


Start:
	lea	Screen,a0				; Zeiger Screen
	move.l	a0,d0				; Bitplane
	move.w	d0,BPLPointer1+6
	swap	d0
	move.w	d0,BPLPointer1+2

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

	moveq	#100,d0				; d0 ist die x-Koordinate
	move.w	#100,d1				; d1 ist die y-Koordinate
	moveq	#0,d2				; Wir setzen den Rest der Datenregister zurück
	moveq	#0,d3				; bla bla bla
	moveq	#0,d4				; bla bla
	moveq	#0,d5				; bla
	moveq	#0,d6		
	moveq	#0,d7

Loop:
	cmpi.b	#$ff,$6(a6)
	bne.s	Loop

	bsr.w	ReadJoyst			; Die Routine liest den Joystick-Status
								; und aktualisiert x und y direkt in den 
								; Registern d0 und d1.
	bsr.w	CheckLimit			; Überprüfen, ob die Routine in den Grenzen liegt
	bsr.w	ClearScreen			; den Bildschirm reinigen
	Bsr.s	ClipBobRight		; legt den Bob auf den Bildschirm
	btst	#6,$bfe001			; Warten, bis die linke Maustaste gedrückt wird
	bne.s	Loop				; ...
	rts

; ****************************************************************************
; Die entschlüsselte Technik wird wie folgt implementiert:
; 1) Wenn die obere rechte Koordinate außerhalb der Maximalgrenze liegt, dann
;   nichts blitten.
; 2) Berechnen Sie auf folgende Weise, wie viele Pixel der Bob herausgekommen 
;   ist Xout=(x+xdim)-XMax
; 3) Es wird dann genau berechnet, aus wie vielen Wörtern der Bob kam und
;   wie viele Pixel, auf folgende Weise XOut / 16 und XOut mod 16.
; 4) An dieser Stelle übernehmen wir den Wert aus der maskright-Tabelle
;   des BLTLWM-Registers durch den XOut-Wert mod 16
; 5) Wir bereiten das A-Modulo des Blitters durch die Operation 
;   (XBob-XOut) / 16 vor
; ****************************************************************************

;	       . . . .
;	      :¦:¦:¦:¦:¦       
;	      ¦    ____l___    
;	      |__  '______/    
;	     _!\____,---.|     
;	.---/___ (¯°) °_||----.
;	|   \ \/\ ¯¯¯¯T  l_   |
;	|  _ \ \/\___,_)__ \  |
;	|  |  \ \/ /| | l/ /  |
;	|  |   \ \/¯T¯T¯/ /T  |
;	|  |    \_¯¯¯¯¯¯_/ |  |
;	|  |     `------'  |  |
;	|  l_______/¯¯)¯¯\_|  |
;	l_______l__  _(_  (___|
;	.. .  .   \___)___/ xCz

ClipBobRight:
	movem.l	d0-d7/a0,-(a7)
	cmpi.w	#XMax,d0			; Vergleichen Sie die Koordinate oben links
								; mit XMax
	bge.w	ExitClipRight		; Wenn es größer ist, ist der Bob komplett
								; raus, also machen wir nichts

	move.w	#XBob,d7			; d7=Dimension des Bobs
	add.w	d0,d7				; Die x-Koordinate ist ähnlich wie d7, also
								; entspricht d7 der Koordinate oben rechts.
	subi.w	#XMax,d7			; Berechnung, aus wie vielen Pixeln der Bob herauskam
	ble.w	IsInLeft			; Wenn das Ergebnis kleiner als Null ist, dann
								; kam der Bob komplett raus.

	move.w	d7,d6				; d7=d6=Anzahl der Pixel aus
	lsr.w	#4,d6				; d6=d6/16 Wort Nummer
	move.w	#XWord,d2			; d2=Wortnummer des Bob ursprünglich
	andi.w	#15,d7				; d7=Anzahl der Pixel aus

								; Jetzt berechne ich den neuen Wert von BLTSIZE
	move.w	d2,d5				; d5=Wortnummer des Bob ursprünglich
	sub.w	d6,d2				; d2 Anzahl der Wörter in
	move.w	#YBob,d3			; Dimension vertikal in d3
	lsl.w	#6,d3				; Multiplizieren Sie d3 mit 64
	add.w	d2,d3				; d3=BLTSIZE reduziert

								; Wir berechnen das neue Zielmodulo
	moveq	#40,d4				; Berechnung der neuen Form des
								; Ziels. Wir machen nichts als subtrahieren
								; die restlichen Abmessungen des Bobs bei 40.
	add.w	d5,d5				; d5=d5*2 Anzahl der Bytes des ursprünglichen Bob.
	add.w	d6,d6				; d6=d6*2 Modulo vonA in byte
	sub.w	d6,d5				; d5=Anzahl der Bytes aus
	sub.w	d5,d4				; d4=Modulo von D

	moveq	#-1,d5
	add.w	d7,d7				; mit d7 nehmen wir den Wert der Maske
	lea	MaskRight,a0			; in a0 die Adresse der Tabelle
	move.w	(a0,d7.w),d5		; d5=Maske	

	mulu	#40,d1				; Ab hier normales Blitting...
	move.w	d0,d2
	lsr.w	#3,d0	
	add.w	d0,d1	
	lea	Screen,a0
	adda.l	d1,a0
	andi.w	#$000f,d2
	ror.w	#4,d2				; effizienter als LSL #4,d2 und
								; dann LSL #8,d2
	ori.w	#$09f0,d2		

	btst	#6,2(a6)
WaitBlit1b:
	btst	#6,2(a6)			; DMACONR - Warten Sie, bis der Blitter frei ist
	bne.s	WaitBlit1b

	move.w	d2,$40(a6)			; BLTCON0
	move.l	d5,$44(a6)			; BLTAFWM
	move.l	#Bob,$50(a6)		; BLTAPT
	move.l	a0,$54(a6)			; BLTDPT
	move.w	d6,$64(a6)			; BLTAMOD
	move.w	d4,$66(a6)			; BLTDMOD
	move.w	d3,$58(a6)			; BLTSIZE
	movem.l	(a7)+,d0-d7/a0
	rts

IsInLeft:
	mulu.w	#40,d1				; In diesem Fall verwenden wir den Blitter
	move.w	d0,d2				; normalerweise ist da der bob drin
	lsr.w	#3,d0				; die eingestellten Grenzen.
	add.w	d0,d1	
	lea	Screen,a0
	add.l	d1,a0
	andi.w	#$000f,d2
	ror.w	#4,d2
	ori.w	#$09f0,d2		

	moveq	#-1,d7
	clr.w	d7

	btst	#6,2(a6)
WaitBlit1a:
	btst	#6,2(a6)			; DMACONR - Warten Sie, bis der Blitter frei ist
	bne.s	WaitBlit1a

	move.w	d2,$40(a6)			; BLTCON0
	move.w	#0,$42(a6)			; BLTCON1
	move.l	d7,$44(a6)			; BLTAFWM
	move.l	#Bob,$50(a6)		; BLTAPT
	move.l	a0,$54(a6)			; BLTDPT
	move.w	#-2,$64(a6)			; BLTAMOD
	move.w	#40-18,$66(a6)		; BLTDMOD
	move.w	#(29*64)+(144/16),$58(a6)	; BLTSIZE
ExitClipRight:
	movem.l	(a7)+,d0-d7/a0
	rts

; ****************************************************************************
; Diese Routine prüft, dass der Bob die physikalischen Grenzen des Bildschirms 
; nicht verlässt. In der Tat haben wir eine Routine erstellt, die die Teile 
; herausschneidet die rechts herauskommen, aber wir haben nichts getan für 
; die anderen Grenzen des Bildschirms. Diese Routine prüft also, ob die
; Koordinaten immer im richtigen Bereich sind.
; ****************************************************************************

CheckLimit:
	cmpi.w	#XMin,d0			; Ist es von links gekommen?
	bge.s	Limit2				; nein, dann siehe oben und unten
	move.w	#XMin,d0			; ja, dann stecke es wieder in unsere Grenzen
Limit2:
	cmpi.w	#YMin,d1			; Ist es von oben gekommen?
	bge.s	Limit3				; ein, dann siehe unten
	move.w	#YMin,d1			; ja, dann setze es wieder in Grenzen
	bra.s	EndLimit			; und dann kommst du raus weil unser bob nicht
								; gleichzeitig oben und unten stehen kann.
Limit3:
	cmpi.w	#YMax,d1			; Wie oben, aber wir überprüfen das Limit
	blt.s	EndLimit			; vertikal unten.
	move.w	#YMax,d1
EndLimit
	rts
	
; ****************************************************************************
; Diese Routine liest den Joystick und (aktualisiert die in den 
; sprite_x und sprite_y Variablen enthaltenen Werte)
; aktualisiert x und y direkt in den Registern d0 und d1.
; ****************************************************************************

ReadJoyst:
	move.w	$dff00c,d3			; JOY1DAT
	btst.l	#1,d3				; Bit 1 sagt uns, ob wir nach rechts gehen
	beq.s	NotRight			; Wenn es Null ist, gehe nicht rechts
	addq.w	#1,d0				; Wenn es 1 ist, verschieben Sie das Sprite um ein Pixel
	bra.s	CheckY				; Gehe zur Y-Steuerung
NotRight:
	btst	#9,d3				; Bit 9 sagt uns, ob wir nach links gehen
	beq.s	CheckY				; Wenn es Null ist, gehe nicht nach links
	subq.w	#1,d0				; Wenn es 1 ist, bewege das Sprite
CheckY:
	move.w	d3,d2				; Kopieren Sie den Wert des Registers
	lsr.w	#1,d2				; scrollt die Bits eines Ortes nach rechts
	eor.w	d2,d3				; führt das Exklusive OR. Jetzt können wir testen
	btst	#8,d3				; Lass uns testen, ob es hoch geht
	beq.s	NotDown				; Wenn nicht, überprüfen Sie, ob es sinkt
	subq.w	#1,d1				; wenn Sie das Sprite bewegen
	bra.s	EndJoyst
NotDown:
	btst	#0,d3				; Lass uns testen, ob es runter geht
	beq.s	EndJoyst			; wenn nicht fertig
	addq.w	#1,d1				; wenn Sie das Sprite bewegen
EndJoyst:
	rts

;****************************************************************************
; Diese Routine löscht den Bildschirm über den Blitter.
;****************************************************************************

ClearScreen:
	btst	#6,2(a6)
WaitBlit3:
	btst	#6,2(a6)			; Warten Sie, bis der Blitter fertig ist
	bne.s	WaitBlit3

	move.l	#$01000000,$40(a6)	; BLTCON0 und BLTCON1: Löschung
	move.w	#$0000,$66(a6)		; BLTDMOD=0
	move.l	#Screen,$54(a6)		; BLTDPT - Adresse Bildschirm
	move.w	#(64*256)+20,$58(a6)	; BLTSIZE (starte Blitter !)
								; Löscht den gesamten Bildschirm
	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				; BPL1MOD
	dc.w	$10a,0				; BPL2MOD

	dc.w	$100,$1200			; BPLCON0 - 2 Bitplanes lowres

	dc.w	$180,$000			; COLOR00
	dc.w	$182,$aaa			; COLOR01

Bplpointer1:
	dc.w	$e0,0,$e2,0			; erste Bitplane

	dc.l	$ffff,$fffe			; Ende Copperlist

******************************************************************************

; Der Bob ist eine Bitebene, 128 Pixel breit und 29 Zeilen hoch

Bob:
	Incbin	"/Sources/Amiga.bmp"

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

; Dies ist die Tabelle, die wir benötigen, um die unerwünschten Pixel "auszuschneiden".

MaskRight:
	dc.w	%1111111111111111
	dc.w	%1111111111111110
	dc.w	%1111111111111100
	dc.w	%1111111111111000
	dc.w	%1111111111110000
	dc.w	%1111111111100000
	dc.w	%1111111111000000
	dc.w	%1111111110000000
	dc.w	%1111111100000000
	dc.w	%1111111000000000
	dc.w	%1111110000000000
	dc.w	%1111100000000000
	dc.w	%1111000000000000
	dc.w	%1110000000000000
	dc.w	%1100000000000000
	dc.w	%1000000000000000

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

	SECTION LEEREPLANE,BSS_C

Screen:
		ds.b	(320*256)/8

	end

Dieses kurze Programm zeigt, wie durch den Blitter Bob Clipping möglich ist.
Dies ist in vielen Videospielen nützlich. Wir sehen das erste mal überhaupt was
Clipping ist. Clipping-Routinen sind vor allem in der 2D Grafik bekannt, aber
auch in 3D muss es natürlich oft gemacht werden.
Es geht um das Verfolgen von Zeilen, die aus dem verfügbaren Videospeicher
kommen. Stellen Sie sich zum Beispiel eine Linie mit einer Koordinate (300,450)
vor, die wird in einem Bildschirm von 320x256 in Luft gezeichnet. Das merken
wir sofort.

Wenn die Linie mit irgendeinem Algorithmus gezeichnet wird, könnte letzterer in
einen reservierten Speicherbereich schreiben, zum Beispiel für den Code und
dann die Maschine zum Absturz bringen. Gleiches gilt für die Bobs.
Nehmen wir an, wir haben einen Videobereich von 320x256 und einen Bob von
64x20 Pixel. Unser Videobild ist aufbauend platziert, d.h. die Koordinaten in
der oberen linken Ecke (es kann auch eine andere Koordinate sein) sind x und y.
Durch den Blitter können wir diesen Bob an jeden Punkt der Fläche der zur 
Verfügung steht platzieren. Aber was passiert, wenn wir unseren Bob am
Koordinatenpunkt zum Beispiel (300,120) platzieren. Schauen wir uns die
Zeichnung an:


  (0x0) _______________________
	|			|
	|			|
	|	   (300x120) ___|___
	|		    |	|   |
	|		    | A	| B |
	|		    |___|___|
	|			|
	|			|
	|			|
	|			|
	|_______________________|(320x256)



Wie zu sehen ist, betritt der Bob "B" den Videobereich nicht und verlässt ihn
draußen. Die Frage ist "Aber wo genau geht er hin?", Die Antwort lautet "hängt
von den Fällen ab". Tatsächlich nehmen wir immer an, dass wir einen
Videobereich von 320x256 auf 1 Bitplane haben. Solange wir uns in diesem
Bereich bewegen besteht keine Gefahr, dass der Blitter die Speicherbereiche
ruiniert. In der Tat, der Teil des Bobs, der herauskommt, wird nach links
fallen, aber ein Pixel niedriger, also wird so etwas passieren.



  (0x0) _______________________
	|			|
	|			|
	|	   (300x120) ___|
	|___		    |	|
	|   |		    | A	|
	| B |		    |___|
	|___|			|
	|			|
	|			|
	|			|
	|_______________________|(320x256)


Man denke nur an die Tatsache, dass der Speicher sequentiell ist. Also
angekommen am letzten Wort einer Zeile, dann ist das nächste Wort das erste der
nächsten Zeile. In diesem Fall sehen wir also, dass ein Risiko für unsere Daten
oder unseren Code besteht, aber nehmen wir an, die Koordinate ist in der Nähe
von (320,256). In diesem Fall riskieren wir wirklich viel! Es bleibt jedoch
eine Tatsache, dass die Portion Bob unansehnlich ist.
Haben Sie jemals ein Spiel gesehen, bei dem die von rechts kommenden Bobs aus
dem Spiel kommen? Sinvan zu Silvan? Es gibt verschiedene Lösungen, um diesen
Teil des Bobs der nutzlos und gefährlich wird zu beseitigen. Man könnte
folgendes tun:
Ein größerer Videobereich, dh Hinzufügen von Sicherheitszonen rechts und links
vom Videospeicher. Ich meine so etwas:



  	 _______________________________________
	|\\\\\\\|			|\\\\\\\|	
	|\\\\\\\|			|\\\\\\\|
	|\\\\\\\|	   		|\\\\\\\|
	|\\\\\\\|		    	|\\\\\\\|
	|\\\\\\\|		    	|\\\\\\\|
	|\\\\\\\|		    	|\\\\\\\|  
	|\\\\\\\|			|\\\\\\\|
	|\\\\\\\|			|\\\\\\\|
	|\\\\\\\|			|\\\\\\\|
	|\\\\\\\|			|\\\\\\\|
	|\\\\\\\|_______________________|\\\\\\\|
       

       |\\\|
       |\\\| <- Sicherheitsspeicherbereich
       |\\\|


Wie aus der Zeichnung hervorgeht, garantiert uns diese Lösung zwei Dinge: die
erste ist, dass die überflüssigen Bob-Teile unsere Daten nicht beeinflussen und
zweitens, dass diese Teile nicht auf die linke Seite passen. Aber lassen sie
uns einen bisschen die Kanten machen.... 
Die Dimensionen dieser Bereiche dürfen höchstens gleich sein wie die maximale 
horizontale Abmessung der Bobs. Wenn wir also einen Bob haben, mit einer
maximalen horizontalen Abmessung von 128 Pixel und wir verwenden es auch in
einem 5-Bitebenen-Kontext benötigen wir 2 Bereiche von
((256x128) / 8) * 5 = 20480 Bytes, dh insgesamt 40960 müssen wir auch für die
Sicherheitsbereiche berücksichtigen, die am oberen und unteren Rand unserer 
Videofläche platziert werden sollte. Das wäre für die Speicherbelegung zu viel.
Die Lösung muss daher in einem Algorithmus gesucht werden, der nur die Teile
vom Bob in die richtigen Speicherbereiche schreibt und den Rest weglässt. Alles
kann mit dem Blitter gemacht werden. 
Das Programm zeigt also, wie es möglich ist, von hier aus zu arbeiten. Einige
Überlegungen. Zuallererst, wenn unser Bob an einer Koordinate platziert werden
soll, so dass sich dann der ganze Bob im Videospeicher befindet.
Dies kann mit einer klassischen Routine durchgeführt werden, bei der ein Bob
mit dem Blitter bewegt wird. Variationen treten auf, wenn die xb-Koordinate in
der rechten unteren Ecke liegt und mit der maximalen Begrenzung des
Videospeichers zusammenfällt und übersteigt sie total.
Bereiten wir uns auf ein recht komplexes Argument vor.
Sei XM von nun an die Grenzkoordinate unseres Videobereichs, und nehmen Sie
auch an, dass XM ein Vielfaches von 16 Pixeln ist (der Einfachheit halber).
Machen wir also Beobachtungen. Unser Bob, wenn es mit XM zusammenfällt, dann
ist die x-Koordinate oben links ebenfalls ein Vielfaches von 16 Pixeln. Da der
Bob mehrere horizontale Abmessungen von 16 Pixel hat. Tatsächlich, wenn wir
einen 64-Pixel-Bob und XM = 320 haben, fällt xb mit XM zusammen.
Wir werden das xa = 320-64 = 256 haben, was immer noch ein Vielfaches von 16
ist, das heißt, wenn sich unser Bob nur zu einem anderen Pixel xb bewegt, das
es dasselbe sein wird zu XM + 1, aber das Wichtigste ist, dass wir im ersten
Teil Wortfolgen (XM / 16) in unserem Beispiel ist XM = 320 das Wort schreiben
werden. Wenn Sie das verstehen, haben Sie bestanden.
Einige von Ihnen die vielleicht schon viel mit dem Blitter erlebt haben, sehen
schon die Lösung für das Problem. 
Tatsächlich müssen wir jetzt verhindern, dass der Blitter in das eingedrungene
Wort schreibt. Das habe ich ganz einfach mit dem BLTLWM-Blitterregister auf
"1111111111111110" getan. Auf diese Weise werden die letzten Bits des letzten
Wortes vom Bob von uns nicht kopiert. Wenn sich unser Bob zu einem anderen
Pixel bewegt dann wird das Wort auf "1111111111111100" gesetzt.
Aber was passiert, wenn unser Bob aus 16 Pixel mehr aus dem Videofenster kommt?
Es ist offensichtlich, dass Wir das BLTLWM-Register nicht mehr verwenden
können, aber wir müssen auch die Form verwenden. Wenn wir einen Nicht-RAW-Bob
haben, liegen die Informationen nacheinander im Speicher. Dann setzen wir das
Modulo der Quelle auf Null wenn unser Bob jetzt 16 Pixel raus ist, dann müssen
wir unserem Blitter so etwas sagen: Mein Bob hat jetzt die Dimension x-16 und
die Höhe y, also lese x-16 Bit und sofort danach überspringen sie 16 (die
außerhalb des Videofensters). Schreiben Sie stattdessen, wenn Sie schreiben
x-16 und springe dann auf 320-(x-16) Pixel. Es ist offensichtlich, dass wir
nicht mit dem Blitter auf diese Weise und in Punkto Pixel sprechen aber ich
hoffe ich habe es geschafft das sie mich verstehen. Kombinieren Sie also die
beiden Techniken zum Maskieren unerwünschter Bits und der Sprung von nutzlosen
Informationen durch das Modulo, das wir tun können ein Bob schnell.
Logischerweise dauert es weniger Zeit, nichts zu tun es aber denken wir auch
daran, dass auf diese Weise mehr Teile vom Bob herauskommen und der Blitter
beendet den Kopiervorgang.
Mit dem Joystick kannst du einen 128x29 Pixel großen Bob bewegen und versuchen,
ihn zu ändern. Die XMax-Koordinate (muss ein Vielfaches von 16 sein). In
diesem Beispiel beschränken wir uns darauf, die Technik des "Schneidens" des
Bobs zu veranschaulichen ohne sich um den Hintergrund zu sorgen. Tatsächlich
gestalten wir unseren Bob mit einer einfachen Kopie. Um das Listing nicht 
schwieriger zu machen, führen wir bei jeder Ausführung jedes Mal  eine Löschung
des gesamten Bildschirms statt nur des Rechtecks, das den Bob umschließt durch.
Sie können versuchen, diese Technik auf das Beispiel des gesamten Bobs zu
erweitern (dh mit Wiederherstellung des Hintergrunds). In diesem Fall müssen
Sie bedenken dass, wenn der Bob nach rechts "abgeschnitten" wird, dass das
Modulo, die Größe des Blitts nicht nur in der Bob - Design - Routine (wie
in diesem Beispiel geschehen), aber auch in den Rettungs- und
Wiederherstellungsroutinen des Hintergrunds gewechselt werden müssen.

