
; Listing18a.s = Lezione3d-1a.s

	SECTION	DotCube3d,CODE

; Perspektive + Translation X,Y,Z (Dot-Cube)
; rechts / links mit Maus für Auf / Ab: Translation X und Y
; linke / rechte Maustaste = Z bewegen (näher / weiter weg bewegen)

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

			;5432109876543210
DMASET	equ	%1000001111000000	; Copper, Bitplane und blitter
WaitDisk equ	%0				; wegen startup2
Bildschirmbreite	=	320
Bildschirmhoehe		=	256

Start:
	move.w	#DMASET,$96(a5)		; DMACON - aktivieren Bitplane, Copper
	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.l	#0,$108(a5)

	move.b	$dff00a,MouseY		; JOY0DAT vertikale Mausposition
	move.b	$dff00b,MouseX		; horizontale Mausposition

LoopMain:
	lea	$dff000,a5
	move.l	#$1ff00,d1			; Bit zur Auswahl durch UND
	move.l	#$12c00,d2			; warte auf Zeile $12c
WaitY1:
	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	WaitY1

	bsr.w	SwapClean			; Bildschirme im Doppelpuffer tauschen und
								; alten Bildschirm reinigen

	bsr.s	ReadMouse			; Liest die Bewegung der Maus um
								; die X- und Y-Translationswerte zu aktualisieren

; Jetzt mit der rechten und linken Taste der Maus können wir eine Translation
; in Bezug auf die Z-Achse ausführen, die das Objekt näher oder weiter weg bringt.

	btst.b	#6,$bfe001			; linke Maustaste?
	bne.s	NoFurther
	cmp.w	#40*50,Zadd			; sind wir sehr weit weg?
	beq.s	NoFurther		; wenn ja, anhalten
	add.w	#40,Zadd			; Translation von uns weg
NoFurther:
	btst.b	#2,$dff016			; rechte Maustaste?
	bne.s	NoApproach
	cmp.w	#-40,Zadd			; sind wir zu uns sehr nah?
	beq.s	NoApproach			; wenn ja, das reicht!
	sub.w	#40,Zadd			; Translation der Annäherung an uns
	btst.b	#6,$bfe001			; wird auch die linke Taste gedrückt?
	beq.s	Exit				; Wenn ja, dann raus!
NoApproach:

	bsr.w	Translation			; TRANSLATION des Objekts gemäß den Werten
								; der Variablen Xadd, Yadd und Zadd.

	bsr.w	Perspektive			; PERSPEKTIVE PROJEKTION. Die bewegten Punkte
								; werden auf den "Monitor" projiziert.

	bsr.w	DesignObject		; Objekt zeichnen (einfache X-, Y-Punkte)

	bra.s 	LoopMain			; Bereit für den nächsten Frame

Exit:
	rts

******************************************************************************
; Diese Routine liest die Maus und aktualisiert die Werte in den
; Xadd- und Yadd-Variablen, die für die Translation verwendet werden.
******************************************************************************

ReadMouse:
	move.b	$dff00a,d1			; JOY0DAT vertikale Mausposition
	move.b	d1,d0				; Kopie in d0
	sub.b	MouseY(pc),d0		; alte Mausposition subtrahieren
	beq.s	NoVert				; wenn die Differenz = 0 ist, wird die Maus gestoppt
	ext.w	d0					; wandelt das Byte in ein Wort um
	add.w	d0,Yadd				; Würfelposition ändern
NoVert:
  	move.b	d1,MouseY			; speichern der Mausposition für das nächste Mal

	move.b	$dff00b,d1			; horizontale Mausposition
	move.b	d1,d0				; Kopie in d0
	sub.b	MouseX(pc),d0		; alte Position subtrahieren
	beq.s	NoHoriz				; wenn die Differenz = 0 ist, wird die Maus gestoppt
	ext.w	d0					; wandelt das Byte in ein Wort um
	add.w	d0,Xadd				; Würfelposition ändern 
NoHoriz:
  	move.b	d1,MouseX			; speichern der Mausposition für das nächste Mal
	rts

MouseY:	dc.b	0			; hier wird das Y der Maus gespeichert
MouseX:	dc.b	0			; Hier wird das X der Maus gespeichert

****************************************************************************
* ROUTINE, DIE DIE PERSPEKTIVE DER ROTATION DURCHFÜHRT.					   *
*																		   *
* Quelle: Tabelle "PunkteXYZTransl", mit 3 Koordinaten XYZ pro Punkt	   *
*																		   *
* Ziel: Tabelle "PunkteXYPerspek", mit 2 Koordinaten X¹,Y¹				   *
*																		   *
* Die einzige andere Variable ist der Abstand Z des Beobachters vom        *
* Bildschirm, was in diesem Fall 256 ist, so dass Sie eine "ASL #8"        * 
* anstelle von einer zeitintensiven Multiplikation ausführen können.	   *
****************************************************************************

Perspektive:
	lea	PunkteXYZTransl(pc),a0	 ; Adresse Tab. der X,Y,Z aus
								 ; Projektion (bereits bewegt)
	lea	PunkteXYPerspek(pc),a1 ; Tabelle, wo die  projizierten Koordinaten X¹,Y¹
								 ; platziert werden sollen.
	move.w	#Bildschirmbreite/2,d3  ; X Bildschirmmitte (für Mitte)
	move.w 	#Bildschirmhoehe/2,d4   ; Y Bildschirmmitte (für Mitte)

	move.w	#NPunkteObjekt-1,d7	; Anzahl der zu projizierenden Punkte
PerspLoop:
	movem.w	(a0)+,d0-d2			; Koord. X in d0, Y in d1, Z in d2
	asl.l	#8,d0				; (MULS #256) DistZossSchermo*Xogg
	asl.l	#8,d1				; (MULS #256) DistZossSchermo*Yogg
	add.w	#256,d2			    ; Zogg+DistZossSchermo
	divs.w	d2,d0				; (DistZoss_Schermo*Xogg)/(Zogg+DistZossSchermo)
	divs.w	d2,d1				; (DistZoss_Schermo*Yogg)/(Zogg+DistZossSchermo)
	add.w	d3,d0				; + Koordinate X Mitte des Bildschirms (zur Mitte)
	add.w 	d4,d1				; + Koordinate Y Mitte des Bildschirms (zur Mitte)
	movem.w	d0-d1,(a1)			; speichern der projizierten und bewegten X¹- und Y¹-Werte
	addq.w	#2+2,a1				; zu den nächsten 2 Werten springen
	dbra 	d7,PerspLoop		; Wiederholen Sie NumberPoints-Zeiten für alle Punkte.
	rts							; bis alle gescreent sind

****************************************************************************
* Translationsroutine, die einfach den Wert der Variablen Xadd, Yadd, Zadd * 
* zu den Objektkoordinaten addiert, wodurch die "Verschiebung" im Raum     *
* verursacht wird.														   * 
****************************************************************************

Translation:
	lea	Objekt1(pc),a0			; Koord x,y,z Objekt (Quelle)
	lea	PunkteXYZTransl(pc),a1	; Tabelle für gedrehte Punkte X,
								; das ist das Ziel!
	move.w	#NPunkteObjekt-1,d7	; Anzahl der zu bewegenden Punkte
TrLoop:
	movem.w	(a0)+,d0/d1/d2		; X in d0, Y in d1, Z in d2
	add.w	Xadd(pc),d0			; X Translation (+ = rechts, - = links)
	add.w	Yadd(pc),d1			; Y Translation (+ = unten, - = oben)
	add.w	Zadd(pc),d2			; Z Translation (+ = zurück, - = vorwärts)
	move.w	d0,(a1)+			; speichern X in PunkteXYZTransl
	move.w	d1,(a1)+			; speichern Y in PunkteXYZTransl
	move.w	d2,(a1)+			; speichern Z in PunkteXYZTransl
	dbra 	d7,TrLoop			; Führen Sie NumberPoints-Male aus, um alle
	rts							; Punkte zu drehen.

Xadd:
	dc.w	0
Yadd:
	dc.w	0
Zadd:
	dc.w	0

******************************************************************************
**	ROUTINE ZUM ZEICNEN DES 3D OBJEKTES AUF DER Bitplane (mit Punkten!)	    **
******************************************************************************

DesignObject:
	lea	PunkteXYPerspek(pc),a4	; Puffer Koordinate X¹ und Y¹
	moveq	#NPunkteObjekt-1,d7	; Anzahl der zu zeichnenden Punkte
	move.l	DrawPlane(pc),a0	; aktuelle Bildschirmadresse in a0
PlotLoop:
	movem.w	(a4)+,d0-d1			; Koord X¹ in d0 und Koord Y¹ in d1
	bsr.s	PlotPix				; Punkt drucken auf Koordinate X=d0, Y=d1
	dbra	d7,PlotLoop			; alle Punkte drucken
	rts

*****************************************************************************
;			Routine zur Darstellung von Punkten (dots)
*****************************************************************************

;	Eingabeparameter PlotPix:
;
;	a0 = Adresse Bitplane Ziel
;	d0.w = Koordinate X (0-319)
;	d1.w = Koordinate Y (0-255)

DISPLAYWIDTH	equ	40			; Bildschirmbreite in Bytes

PlotPix:
	cmp.w	#320,d0				; sind wir raus?
	blo.s	Ok1
	rts
Ok1:
	cmp.w	#256,d1				; sind wir raus?
	blo.s	Ok2
	rts
Ok2:
	move.w	d0,d2				; Kopie der X Koordinate in d2
	lsr.w	#3,d0				; In der Zwischenzeit finden Sie den horizontalen Versatz,
								; durch Teilen der X-Koordinate durch 8.
	mulu.w	#DISPLAYWIDTH,d1
	add.w	d1,d0				; Summenversatz vertikal bis horizontal

	and.w	#%111,d2			; Wählen Sie nur die ersten 3 Bits von X.
								; (Eigentlich wäre es der Rest der Division
								; für 8 früher gemacht)
	not.w	d2

	bset.b	d2,(a0,d0.w)		; Setzt das d2-Bit des entfernten Bytes d0 Bytes
								; vom Anfang des Bildschirms.
	rts

*************************************************
*	Swap Logical and Physical Screens			*
*************************************************

SwapClean:
	move.l 	Screen(pc),d0
	cmp.l 	DrawPlane(pc),d0	; Is current screen=screen1
	bne.s	SwapIt				; No then branch
	move.l 	Screen(pc),d0		; Display Screen1
	bsr.s	PointPlaneInCop		; Insert it Into Copper
	move.l 	Screen1(pc),DrawPlane	; Screen2 = Logical 
	move.l 	Screen1(pc),a1		; Address to Clear
	bsr.w	CpuClearScreen		; Do it !!!
  	rts
  	
SwapIt:
	move.l 	Screen1(pc),d0		; Use screen2
	bsr.s	PointPlaneInCop		; Insert screen
	move.l 	Screen(pc),DrawPlane	; screen1=logical
	move.l 	Screen(pc),a1		; address to clear
	bsr.w	CpuClearScreen
	rts
	
PointPlaneInCop:
	lea	BplPointer,a0			; Zeiger Copperlist
	move 	d0,6(a0)			; auf die plane zeigen 
	swap 	d0
	move 	d0,2(a0)
	rts


DrawPlane:
	dc.l	Bitplane

; Zeiger auf die 2 Bildschirme für das Double Buffering

Screen:
	dc.l Bitplane0
Screen1:
	dc.l Bitplane

******************************************************************************
*	Bildschirm CLEAR-Routine über den Prozessor
*
*	a1 = Adresse des zu reinigenden Bildschirms
******************************************************************************

CpuClearScreen:
	movem.l	d0-d7/a0-a6,-(sp)	; alle Register speichern
	move.l	SP,OldSp			; Speichern des STACK POINTER, um ihn zu verwenden
	lea	40*Bildschirmhoehe(a1),sp	; Laden Sie die hohe Adresse, also
								; das Ende des Bildschirms, da Movems
								; "rückwärts" reinigen.
	movem.l	ClReg(pc),d0-d7/a0-a6	; Wir setzen alle Register mit nur
								; einem Movem aus einem Puffer von Nullen zurück.

; Lassen Sie uns nun den Speicher mit vielen ausgeführten "movem.l d0-d7/a0-a6,-(sp)" 
; nacheinander löschen. Jeder Befehl setzt 60 Bytes zurück (15 Register long, das
; macht 15*4=60 Bytes) und schreibe in -(sp). Passen Sie auf, dass es vom Ende des
; Bildschirms (unten) beginnt und "nach oben geht" und so den Speicher zurückgeht.
; In hex wird das Movem als "$48E7FFFE" zusammengesetzt, es ist also genug
; eine "dcb.l number_instructions, $48e7fffe" einzugeben.

	dcb.l	170,$48e7fffe		; 60*170=10200 bytes löschen

	movem.l	d0-d7/a0-a1,-(sp)	; die Letzten 40 bytes... (total 10240)

	move.l	OldSp(pc),sp		; den alten SP zurücksetzen
	movem.l	(sp)+,d0-d7/a0-a6	; Wert der Register zurücksetzen
	rts

; 15 Longs gelöscht, um in die Register geladen zu werden, um sie zu löschen

ClReg:
	dcb.l	15,0

OldSp:
	dc.l	0

******************************************************************************
* Definition des 3D-Volumenkörpers durch die X-, Y-, Z-Koordinaten seiner Punkte.  *
******************************************************************************

;	WENIGER< X >MEHR'		WENIGER			MEHR'
;							 ^				/|
;							 Y		       Z
;							 v		     |/
;							MEHR'		   WENIGER

;	      (P4) -50,-50,+50______________+50,-50,+50 (P5)
;					     /|			   /|
;					    / |		      / |
;					   /  |			 /  |
;					  /   |			/   |
;	 (P0) -50,-50,-50/____|________/+50,-50,-50 (P1)
;					|     |       |     |
;				    |     |_______|_____|+50,+50,+50 (P6)
;					|    /-50,+50,+50 (P7)
;					|   /	      |   /
;					|  /	      |  /
;					| /			  | /
;					|/____________|/+50,+50,-50 (P2)
;	 (P3) -50,+50,-50

Objekt1:  ; Hier sind die 8 durch die Koordinate  X, Y, Z definierten Punkte.
	dc.w	-50,-50,-50	; P0 (X,Y,Z)
	dc.w	+50,-50,-50	; P1 (X,Y,Z)
	dc.w	+50,+50,-50	; P2 (X,Y,Z)
	dc.w	-50,+50,-50	; P3 (X,Y,Z)
	dc.w	-50,-50,+50	; P4 (X,Y,Z)
	dc.w	+50,-50,+50	; P5 (X,Y,Z)
	dc.w	+50,+50,+50	; P6 (X,Y,Z)
	dc.w	-50,+50,+50	; P7 (X,Y,Z)

NPunkteObjekt	= 8

******************************************************************************
;		    Daten und Variablen der Routine									 *
******************************************************************************

; Puffer für geänderte Punkte (gedreht und / oder bewegt im 3D-Raum).

PunkteXYZTransl:
	ds.w	NPunkteObjekt*3

; --------------------------------------------------------------------------

; Koordinaten X¹ und Y¹ projiziert, dh perspektivisch, bereit gezeichnet zu
; werden. Die Koordinaten werden paarweise im Puffer gespeichert
; Aufeinanderfolgende X¹ und Y¹: XY, XY, XY, XY, XY ..., ein Wort für jede Koordinate.

PunkteXYPerspek:
	ds.w	NPunkteObjekt*2

; --------------------------------------------------------------------------

	SECTION	GRAPHIC,DATA_C

Copperlist:
	dc.w	$120,0
	dc.w	$122,0
	dc.w	$008e,$2c81
	dc.w	$0090,$20C1
	dc.w	$0092,$0038
	dc.w	$0094,$00d0
	dc.w	$0108,0
	dc.w	$010a,0
	dc.w	$0102,0
	dc.w	$100,%0001001000000000
	dc.w	$180,0,$182,$ffff,$184,$ffff
BplPointer:
	dc.w	$e0,0,$e2,0
	dc.w	$ffff,$fffe

	SECTION	LEEREPLANE,BSS_C

Bitplane0:
	ds.b	40*Bildschirmhoehe

Bitplane:
	ds.b	40*Bildschirmhoehe

	end

; Xogg, Yogg, Zogg			- X,Y,Z des Objekts
; DistZossSchermo			- Entfernung (Distanz) vom Auge zum Bildschirm
