
; Listing10v.s		Rotierendes Polygon
; 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 "leere" Bitplane
	lea	Bplpointers,a1			; Bitplanepointer
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)

	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"

	move.w	#$ffff,d0			; durchgehende Linie
	bsr.w	SetPattern			; definiert Muster

Mouse:
	move.l	#$1ff00,d1			; Bit zur Auswahl durch UND
	move.l	#$12c00,d2			; Warte auf Zeile $12c
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 $12c
	bne.s	WarteY1

	bsr.w	ClearScreen			; Bildschirm reinigen
	bsr.w	MovePoints			; Ändern Sie die Koordinaten der Punkte
	bsr.w	InitLine			; line-mode

; Zeichne die Linie zwischen den Punkten 1 und 2

	move.w	Point1(pc),d0
	move.w	Point1+2(pc),d1
	move.w	Point2(pc),d2
	move.w	Point2+2(pc),d3
	lea	Bitplane,a0
	bsr.w	Drawline

; Zeichne die Linie zwischen den Punkten 2 und 3

	move.w	Point2(pc),d0
	move.w	Point2+2(pc),d1
	move.w	Point3(pc),d2
	move.w	Point3+2(pc),d3
	lea	Bitplane,a0
	bsr.w	Drawline

; Zeichne die Linie zwischen den Punkten 3 und 4

	move.w	Point3(pc),d0
	move.w	Point3+2(pc),d1
	move.w	Point4(pc),d2
	move.w	Point4+2(pc),d3
	lea	Bitplane,a0
	bsr.w	Drawline

; Zeichne die Linie zwischen den Punkten 4 und 1

	move.w	Point4(pc),d0
	move.w	Point4+2(pc),d1
	move.w	Point1(pc),d2
	move.w	Point1+2(pc),d3
	lea	Bitplane,a0
	bsr.w	Drawline

	moveq	#0,d0
	moveq	#0,d1
	lea	Bitplane+178*40-2,a0
	bsr.w	Fill

	btst	#6,$bfe001		; linke Maustaste gedrückt?
	bne.w	Mouse
	rts

;***************************************************************************
; Diese Routine liest aus einer Tabelle die Koordinaten der verschiedenen 
; Punkte und speichert sie in den entsprechenden Variablen.
;***************************************************************************

;	          _
;	     _/\/¯/
;	     \___/
;	     /   \
;	    / o O \
;	   (_______)
;	   _| / \ |_
;	  / |(___)| \
;	 /  l_____|  \
;	Y    | U |    Y
;	|  ¦ l___| ¦ .|
;	|  ¡       ¡ :|
;	l__|-------l__|
;	  |        .|
;	  |    ¡   :|
;	  |    ¦   ·|
;	  |    ¦    |
;	.-`----·----'-.
;	¡_____| l_____¡bHe
	
MovePoints:
	addq.l	#2,TabXpoint		; Zeigen Sie auf das nächste Wort
	move.l	TabXpoint(pc),a0	; Adresse in langen TabXpoint enthalten
								; kopiert nach a0
	cmp.l	#EndeTabX-2,a0  	; Sind wir beim letzten Wort der Tabelle?
	bne.s	NobStartX			; noch nicht dann weiter
	move.l	#TabX-2,TabXpoint 	; Beginnen Sie wieder vom ersten Wort-2
NobStartX:
	move.w	(a0),Point1			; kopiere den Wert der Koordinate
								; von Punkt 1 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabX-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartX2			; nein dann lesen
	sub.l	#EndeTabX-TabX,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartX2:
	move.w	(a0),Point2			; kopiere den Wert der Koordinate
								; von Punkt 2 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabX-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartX3			; nein dann lesen
	sub.l	#EndeTabX-TabX,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartX3:
	move.w	(a0),Point3			; kopiere den Wert der Koordinate
								; von Punkt 3 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabX-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartX4			; nein dann lesen
	sub.l	#EndeTabX-TabX,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartX4:
	move.w	(a0),Point4			; kopiere den Wert der Koordinate
								; von Punkt 4 in der entsprechenden Variablen

	addq.l	#2,TabYpoint		; Zeigen Sie auf das nächste Wort
	move.l	TabYpoint(pc),a0	; Adresse in langen TabYpoint enthalten
								; kopiert nach a0
	cmp.l	#EndeTabY-2,a0  	; Sind wir beim letzten Wort der Tabelle?
	bne.s	NobStartY			; noch nicht dann weiter
	move.l	#TabY-2,TabYpoint 	; Beginnen Sie wieder vom ersten Wort-2
NobStartY:
	move.w	(a0),Point1+2		; kopiere den Wert der Koordinate
								; von Punkt 1 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabY-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartY2			; nein dann lesen
	sub.l	#EndeTabY-TabY,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartY2:
	move.w	(a0),Point2+2		; kopiere den Wert der Koordinate
								; von Punkt 2 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabY-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartY3			; nein dann lesen
	sub.l	#EndeTabY-TabY,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartY3:
	move.w	(a0),Point3+2		; kopiere den Wert der Koordinate
								; von Punkt 3 in der entsprechenden Variablen

	lea	50(a0),a0				; Koordinate des folgenden Punktes
	cmp.l	#EndeTabY-2,a0	  	; Sind wir beim letzten Wort der Tabelle?
	ble.s	NobStartY4			; nein dann lesen
	sub.l	#EndeTabY-TabY,a0 	; ansonsten geh zurück in die
								; Tabelle
NobStartY4:
	move.w	(a0),Point4+2		; kopiere den Wert der Koordinate
								; von Punkt 4 in der entsprechenden Variablen
	rts

TabXpoint:
	dc.l	TabX	; Zeiger auf Tabelle X

TabYpoint:
	dc.l	TabY	; Zeiger auf Tabelle Y

; Tabelle Positionen X

TabX:
	dc.w	$00d2,$00d2,$00d1,$00d1,$00d0,$00cf,$00ce,$00cd,$00cb,$00c9
	dc.w	$00c8,$00c6,$00c3,$00c1,$00bf,$00bc,$00b9,$00b7,$00b4,$00b1
	dc.w	$00ae,$00ab,$00a8,$00a5,$00a2,$009e,$009b,$0098,$0095,$0092
	dc.w	$008f,$008c,$0089,$0087,$0084,$0081,$007f,$007d,$007a,$0078
	dc.w	$0077,$0075,$0073,$0072,$0071,$0070,$006f,$006f,$006e,$006e
	dc.w	$006e,$006e,$006f,$006f,$0070,$0071,$0072,$0073,$0075,$0077
	dc.w	$0078,$007a,$007d,$007f,$0081,$0084,$0087,$0089,$008c,$008f
	dc.w	$0092,$0095,$0098,$009b,$009e,$00a2,$00a5,$00a8,$00ab,$00ae
	dc.w	$00b1,$00b4,$00b7,$00b9,$00bc,$00bf,$00c1,$00c3,$00c6,$00c8
	dc.w	$00c9,$00cb,$00cd,$00ce,$00cf,$00d0,$00d1,$00d1,$00d2,$00d2
EndeTabX:

; Tabelle Positionen Y

TabY:
	dc.w	$0081,$0084,$0087,$008a,$008d,$0090,$0093,$0096,$0098,$009b
	dc.w	$009e,$00a0,$00a2,$00a5,$00a7,$00a8,$00aa,$00ac,$00ad,$00ae
	dc.w	$00af,$00b0,$00b0,$00b1,$00b1,$00b1,$00b1,$00b0,$00b0,$00af
	dc.w	$00ae,$00ad,$00ac,$00aa,$00a8,$00a7,$00a5,$00a2,$00a0,$009e
	dc.w	$009b,$0098,$0096,$0093,$0090,$008d,$008a,$0087,$0084,$0081
	dc.w	$007d,$007a,$0077,$0074,$0071,$006e,$006b,$0068,$0066,$0063
	dc.w	$0060,$005e,$005c,$0059,$0057,$0056,$0054,$0052,$0051,$0050
	dc.w	$004f,$004e,$004e,$004d,$004d,$004d,$004d,$004e,$004e,$004f
	dc.w	$0050,$0051,$0052,$0054,$0056,$0057,$0059,$005c,$005e,$0060
	dc.w	$0063,$0066,$0068,$006b,$006e,$0071,$0074,$0077,$007a,$007d
EndeTabY:

; Hier werden die Koordinaten der Punkte des Polygons jedes Mal gespeichert

Point1:	dc.w	100,20
Point2:	dc.w	200,20
Point3:	dc.w	200,40
Point4:	dc.w	100,40


;****************************************************************************
; Diese Routine kopiert ein Bildschirmrechteck von einer festen Position aus
; an eine als Parameter angegebene Adresse. Das Bildschirmrechteck wird 
; komplett kopiert umschließt die 2 Zeilen.
; Das Füllen erfolgt während des Kopiervorgangs. Die Art der Füllung
; wird über Parameter festgelegt.
; Die Parameter sind:
; a0 - Rechteckadresse, die gefüllt werden soll
; d0 - wenn es 0 ist, dann mache inklusive Füllung, andernfalls exklusiv
; d1 - wenn es 0 ist, wird FILL_CARRYIN = 0, andernfalls FILL_CARRYIN = 1
;****************************************************************************

Fill:
	btst	#6,2(a5)			; DMACONR
WaitBlit1:
	btst	#6,2(a5)			; DMACONR - warte auf das Ende des Blitters
	bne.s	WaitBlit1

	move.w	#$09f0,$40(a5)		; BLTCON0 normale Kopie

	tst.w	d0					; test d0, um die Art der Füllung zu bestimmen
	bne.s	FillExclusiv
	move.w	#$000a,d2			; Wert von BLTCON1: setze die Bits für den
								; inklusiven Füll- und Abstiegsmodus
	bra.s	TestFillCarry

FillExclusiv:
	move.w	#$0012,d2			; Wert von BLTCON1: setze die Bits für den
								; exklusiven Füll- und Abstiegsmodus

TestFillCarry:
	tst.w	d1					; test d1, um zu sehen, ob das
								; FILL_CARRYIN-Bit gesetzt werden soll

	beq.s	MakeBltcon1			; wenn d1 = 0 überspringe ..
	bset	#2,d2				; ansonsten setze Bit 2 von d2

MakeBltcon1:
	move.w	d2,$42(a5)			; BLTCON1

	move.w	#0,$64(a5)			; BLTAMOD Breite 20 words (40-40=0)
	move.w	#0,$66(a5)			; BLTDMOD (40-40=0)

	move.l	a0,$50(a5)			; BLTAPT (am Quellrechteck fixiert)
								; das Quellrechteck umschließt
								; die 2 Zeilen ganz.
								; Wir zeigen auf das letzte Wort des Rechtecks
								; wegen des absteigenden Weges

	move.l	a0,$54(a5)			; BLTDPT - Rechteckadresse
	move.w	#(64*100)+20,$58(a5)	; BLTSIZE (Blitter starten!)
								; Breite 20 words
	rts							; Höhe 100 Zeilen (1 plane)


;******************************************************************************
; Diese Routine zeichnet die Linie. Sie benötigt als Parameter die Koordinaten
; der Punkte P1 und P2 und die Adresse der Bitebene, auf der gezeichnet werden soll.
; d0 - X1 (X-Koordinate von P1)
; d1 - Y1 (Y-Koordinate von P1)
; d2 - X2 (X-Koordinate von P2)
; d3 - Y2 (Y-Koordinate von P2)
; a0 - Bitplane Adresse
;******************************************************************************

; Konstanten

DL_FILL		=	1				; 0=NOFILL / 1=Fill

	IFEQ	DL_FILL
DL_MINTERMS	=	$CA
	ELSE
DL_MINTERMS	=	$4a
	ENDC


DrawLine:
	sub.w	d1,d3				; d3=Y2-Y1

	IFNE	DL_FILL
	beq.s	.end				; Für die Füllung werden keine horizontalen Linien benötigt
	ENDC

	bgt.s	.y2gy1				; springen wenn positiv ..
	exg	d0,d2					; .. Ansonsten tauschen Sie Punkte aus
	add.w	d3,d1				; setzt das kleinere Y in d1
	neg.w	d3					; d3=DY
.y2gy1:
	mulu.w	#40,d1				; Offset Y
	add.l	d1,a0
	moveq	#0,d1				; d1-Index in der Oktantentabelle
	sub.w	d0,d2				; d2=X2-X1
	bge.s	.xdpos				; springen wenn positiv ..
	addq.w	#2,d1				; .. andernfalls verschieben Sie den Index
	neg.w	d2					; und machen den Unterschied positiv
.xdpos:
	moveq	#$f,d4				; Maske für die 4 niedrigen Bits
	and.w	d0,d4				; wählen sie d4 aus
		
	IFNE	DL_FILL				; Diese Anweisungen sind zusammengestellt
									; nur wenn DL_FILL = 1
	move.b	d4,d5				; berechnet die Nummer des zu invertierenden Bits
	not.b	d5					; (das BCHG nummeriert die inversen Bits)
	ENDC

	lsr.w	#3,d0				; Offset X:
								; In Bytes ausrichten (dient für BCHG)
	add.w	d0,a0				; zur Adresse hinzufügen
								; Beachten Sie, dass auch wenn die Adresse
								; Es ist seltsam, dass es nichts macht, weil
								; der Blitter berücksichtigt nicht die
								; niedrigstwertiges Bit von BLTxPT
				
	ror.w	#4,d4				; d4 = Wert der Verschiebung A
	or.w	#$b00+DL_MINTERMS,d4	; füge das passende hinzu
								; Minterm (OR oder EOR)
	swap	d4					; Wert von BLTCON0 im High-Word
		
	cmp.w	d2,d3				; vergleiche DiffX und DiffY
	bge.s	.dygdx				; überspringen wenn >=0..
	addq.w	#1,d1				; andernfalls setzen Sie das Bit 0 des Indexes
	exg	d2,d3					; und tausche das Diff
.dygdx:
	add.w	d2,d2				; d2 = 2*DiffX
	move.w	d2,d0				; Kopie in d0
	sub.w	d3,d0				; d0 = 2*DiffX-DiffY
	addx.w	d1,d1				; multiplizieren Sie den Index mit 2 und
								; gleichzeitig fügt er die Flagge hinzu
								; X ist 1, wenn 2 * DiffX-DiffY <0 ist
								; (eingestellt von sub.w)
	move.b	Oktants(pc,d1.w),d4	; liest den Oktanten
	swap	d2					; BLTBMOD-Wert in High-Word
	move.w	d0,d2				; niedriges Word d2=2*DiffX-DiffY
	sub.w	d3,d2				; niedriges Word d2=2*DiffX-2*DiffY
	moveq	#6,d1				; Wert der Verschiebung und Test für
								; die Wartezeit Blitter

	lsl.w	d1,d3				; berechnet den Wert von BLTSIZE
	add.w	#$42,d3

	lea	$52(a5),a1				; a1 = BLTAPTL-Adresse
								; Er schreibt einige Register
								; nacheinander mit
								; MOVE #XX,(Ax)+

	btst	d1,2(a5)			; warte auf den Blitter
.wb:
	btst	d1,2(a5)
	bne.s	.wb

	IFNE	DL_FILL				; Diese Anweisung ist zusammengestellt
								; nur wenn DL_FILL = 1
	bchg	d5,(a0)				; Invertiert das erste Bit der Zeile
	ENDC

	move.l	d4,$40(a5)			; BLTCON0/1
	move.l	d2,$62(a5)			; BLTBMOD und BLTAMOD
	move.l	a0,$48(a5)			; BLTCPT
	move.w	d0,(a1)+			; BLTAPTL
	move.l	a0,(a1)+			; BLTDPT
	move.w	d3,(a1)				; BLTSIZE
.end:
	rts
	
; Wenn wir Zeilen für die Füllung ausführen möchten, setzt der Octant-Code 
; durch die Konstante SML das SING-Bit auf 1

	IFNE	DL_FILL
SML		= 	2
	ELSE
SML		=	0
	ENDC

; Tabelle Oktanten

Oktants:
	dc.b	SML+1,SML+1+$40
	dc.b	SML+17,SML+17+$40
	dc.b	SML+9,SML+9+$40
	dc.b	SML+21,SML+21+$40

;******************************************************************************
; Diese Routine legt die Blitter-Register fest, die sich 
; zwischen einer Zeile und einer anderen nicht ändern
;******************************************************************************

InitLine:
	btst	#6,2(a5) 			; DMACONR
WaitBlit:
	btst	#6,2(a5)			; DMACONR - warte auf das Ende des Blitters
	bne.s	WaitBlit

	moveq	#-1,d5
	move.l	d5,$44(a5)			; BLTAFWM/BLTALWM = $ffff
	move.w	#$8000,$74(a5)		; BLTADAT = $8000
	move.w	#40,$60(a5)			; BLTCMOD = 40
	move.w	#40,$66(a5)			; BLTDMOD = 40
	rts

;******************************************************************************
; Diese Routine definiert das Muster, das zum Zeichnen der Linien verwendet 
; werden soll. In der Praxis setzt man einfach das BLTBDAT-Register.
; d0 - enthält das Linienmuster
;******************************************************************************

SetPattern:
	btst	#6,2(a5)			; DMACONR
WaitBlit2:
	btst	#6,2(a5) 			; DMACONR - warte auf das Ende des Blitters
	bne.s	WaitBlit2

	move.w	d0,$72(a5)			; BLTBDAT = Linienmuster
	rts

;****************************************************************************
; Diese Routine löscht den Bildschirm mit dem Blitter.
;****************************************************************************

ClearScreen:
	move.l	#Bitplane+78*40,a0	; Adresse die gelöscht werden soll

	btst	#6,2(a5)
WaitBlit3:
	btst	#6,2(a5)		 	; warte auf das Ende des Blitters
	bne.s	WaitBlit3

	move.l	#$01000000,$40(a5)	; BLTCON0 und BLTCON1: Löschung
	move.w	#$0000,$66(a5)		; BLTDMOD=0
	move.l	a0,$54(a5)			; BLTDPT
	move.w	#(64*100)+20,$58(a5)	; BLTSIZE (Blitter starten!)
								; lösche 100 Zeilen, 20 Words breit
	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 - 1 Bitplane lowres

Bplpointers:
	dc.w	$e0,$0000,$e2,$0000	; erste Bitplane

	dc.w	$0180,$000			; COLOR00
	dc.w	$0182,$eee			; COLOR01
	dc.w	$ffff,$fffe			; Ende Copperlist

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

	SECTION	LEEREPLANE,BSS_C

Bitplane:
	ds.b	40*256				; Bitplane lowres

	end

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

In diesem Beispiel erstellen wir ein rotierendes Polygon. Das Polygon besteht
aus 4 Punkten, deren Position jeweils bei jedem Frame aus einer vorberechneten
Tabelle gelesen und geändert wird. Diese Technik ist sehr aufwendig und
verschwendet Speicher. Wir werden im Kurs noch sehen, wie man die 
Koordinaten-Punkte mit mathematischen Formeln berechnet. Um das Polygon zu
zeichnen, genügt es, die Seiten zu zeichnen und zu füllen. Bei den
Zeichenoperationen ist es offensichtlich notwendig, zuerst den Bildschirm mit
dem Blitter zu löschen. Der zu löschende Bildschirmbereich und der zu füllende
Bereich wurden berechnet um immer das ganze Polygon zu erstellen.            
