
; Listing24a2.s	Copper-Positionen
; Anzeigen eines Bildes in 320*256 mit 1 Plane (2 Farben)
; als 16x16-Raster und 'Copper-Pixel' mit Copper-Move an Pixel-Position setzen


SCR_BYTES	= 40				; Anzahl der Bytes für jede horizontale Zeile.
								; Daraus berechnen wir die Bildschirmbreite,
								; Multiplizieren von Bytes mit 8: normaler Bildschirm 320/8 = 40
								; z.B. für einen 336 Pixel breiten Bildschirm 336/8 = 42
								; Beispielbreiten:
								; 264 pixel = 33 / 272 pixel = 34 / 280 pixel = 35
								; 360 pixel = 45 / 368 pixel = 46 / 376 pixel = 47
								; ... 640 pixel = 80 / 648 pixel = 81 ...

SCR_H		= 256				; Bildschirmhöhe in Zeilen
SCR_Y		= $2c				; Startbildschirm, YY-Position (normal $2cxx) (44)
SCR_X		= $81				; Startbildschirm, XX-Position (normal $xx81) (129)
SCR_RES		= 1					; 2 = HighRes (640*xxx) / 1 = LowRes (320*xxx)
SCR_LACE	= 0					; 0 = non interlace (xxx*256) / 1 = interlace (xxx*512)
HAM			= 0					; 0 = non HAM / 1 = HAM
SCR_BPL		= 1					; Anzahl Bitplanes
SCR_XBASE	= $5c				; Startbildschirm, XX-Position (normal $xx5c) 'Basis'

; Parameter automatisch berechnet

SCR_W		= SCR_BYTES*8		; Bildschirmbreite
SCR_SIZE	= SCR_BYTES*SCR_H	; Größe in Bytes des Bildschirms
BPLC0		= ((SCR_RES&2)<<14)+(SCR_BPL<<12)+$200+(SCR_LACE<<2)+(HAM<<11)		; BPLCON0
DIWSTRT		= (SCR_Y<<8)+SCR_X													; DIWSTRT
DIWSTOP		= ((SCR_Y+SCR_H/(SCR_LACE+1))&255)<<8+(SCR_X+SCR_W/SCR_RES)&255		; DIWSTOP
DDFSTRT		= (SCR_X-(16/SCR_RES+1))/2											; DDFSTRT
DDFSTOP		= DDFSTRT+(8/SCR_RES)*(SCR_BYTES/2-SCR_RES)							; DDFSTOP

; konstante Ränder
LEFT		equ	0				; linker Rand
RIGHT		equ 320				; rechter Rand
TOP			equ 0				; oberer Rand
BOTTOM		equ	255				; unterer Rand


 SECTION COPPER,CODE

Start:
	move.l	4.w,a6				; Execbase in a6 in a6
	jsr	-$78(a6) 				; Disable - verhindert Interrupts - stoppt das Multitasking
	lea	GfxName(pc),a1			; Adresse des Namen der zu öffnenden Lib in a1
	jsr	-$198(a6)				; OldOpenLibrary, Routine der EXEC
	move.l	d0,GfxBase			; speichere diese Adresse in GfxBase
	move.l	d0,a6
	move.l	$26(a6),OldCop		; hier speichern wir die Adresse der Copperlist
								; des Betriebssystemes (immer auf $26 nach GfxBase)

	move.l	#Bitplane,d0		; in d0 kommt die Adresse von unserer Bitplane
	lea	Bplpointers,a1			; in a1 kommt die Adresse der Bitplane-Pointer der Copperlist
	moveq	#1-1,d1				; Anzahl der Bitplanes 0 (hier ist es 1)
PointBp:
	move.w	d0,6(a1)			; niederwertige Word der Plane-Adresse
	swap	d0					; vertauscht die 2 Word in d0 (Z.B.: 1234 > 3412)			     
	move.w	d0,2(a1)			; hochwertige Word der Adresse des 			      
	swap	d0					; orginale Adresse wieder hergestellt
	add.l	#40*256,d0			; Zählen 10240 zu d0 dazu, nächste Bitplane
	addq.w	#8,a1				; Adresse der nächsten bplpointers in der Copperlist
	dbra	d1,PointBp			; Wiederhole d1 mal PointBp (d1=num of bitplanes)
	
	lea	$dff000,a5				; Custom Register Base in a5
	move.l	#Copperlist,$80(a5)	; Zeiger Copperlist	
	move.w	#0,$1fc(a5)			; AGA "deaktivieren"
	move.w	#$c00,$106(a5)		; AGA "deaktivieren"
	move.w	#$11,$10c(a5)		; AGA "deaktivieren"
	
Mouse:
	move.l	#$1ff00,d1			; Bit zur Auswahl durch UND
	move.l	#$01000,d2			; warte auf Zeile $010
WarteY1:
	move.l	4(a5),d0			; VPOSR und VHPOSR - $dff004/$dff006
	andi.l	d1,d0				; wählen Sie nur die Bits der vertikalen Pos.
	cmpi.l	d2,d0				; warte auf Zeile $010
	bne.s	WarteY1
WarteY2:
	move.l	4(a5),d0			; VPOSR und VHPOSR - $dff004/$dff006
	andi.l	d1,d0				; wählen Sie nur die Bits der vertikalen Pos.
	cmpi.l	d2,d0				; warte auf Zeile $010
	beq.s	WarteY2

	btst	#2,$dff016			; rechte Maustaste?
	beq NoMove					; nächsten Copperpixel überspringen			

	bsr MoveCopPx				; nächste Copperpixel Position ermitteln
	bsr InitCopper				; Copperlist vorbereiten

NoMove:
	btst	#6,$bfe001			; Maus gedrückt?
	bne.s	Mouse
	
	move.l	OldCop(pc),$dff080	; Pointen auf die alte System Copperlist
	move.l	4.w,a6
	jsr	-$7e(a6)				; Enable
	move.l	GfxBase(pc),a1
	jsr	-$19e(a6)				; Closelibrary
	rts					

;	Daten
GfxName:
	dc.b	"graphics.library",0,0

GfxBase:
	dc.l	0

OldCop:
	dc.l	0

*******************************************************************************
* Umwandlung Pixelposition in Copper-Move-Position							  *
*******************************************************************************

InitCopper:
	move.l	#SCR_X,d0			; Zielposition Copper-Farbänderung	129	(DIWSTRT x-Pos)
	move.l	#SCR_Y,d1			; Zielposition Copper-Farbänderung	44	(DIWSTRT y-Pos)				
	move.l  #SCR_XBASE,d2		; linke Position des Screens - (Basis) Pixelposition=92
	move.l	#$002dfffe,d3		; $2f -horizontale Basis-Copperposistion
								; entspricht Pixelposition $51 und die Wait-Maske
	moveq	#0,d4				; Testbit für Zeile > 255? zurücksetzen	
	move.w	ObjX(pc),d5			; Position X
	move.w	ObjY(pc),d6			; Position Y

XPos:
	sub.w	d2,d0				; DIWSTRT-Anfangsposition (z.B. $81-$5c)/2
	add.w	d5,d0				; gewünschte x-Pixelposition im Screen
	lsr		#1,d0				; Ergebnis dividiert durch zwei	
	btst	#0,d0				; Bit 0 = 0?
	beq 	Ok					; wenn ja, ok			
	and.b	#$fe,d0				; ansonsten gerade machen	
Ok:								; Ergebnis an die richtige Position verschieben
	swap	d0					; 0000.00xx -- 00xx.0000
	add.l	d3,d0				; Copperwait zusammenbauen (horizontaler Teil)

YPos:	
	add.w	d6,d1				; y-Pixelpos. im Screen
	cmp.w	#$100,d1			; VP > 255?
	blo Ok2						; wenn nicht, gehe zu Skip
	moveq	#1,d4				; Testbit setzen
Ok2:							; Ergebnis an die richtige Position verschieben	
	swap	d1					; 0000.00xx -- 00xx.0000
	lsl.l	#8,d1				; xx00.0000
	add.l	d1,d0				; Wait-Anweisung fertig	
	
CopPixel:
	move.l	#$01800ff0,d1		; COLOR00 - gelb
	move.l	#$01800444,d2		; COLOR00 - grau

	lea	CopPos,a0				; Adresse copperlist
	cmp.b	#1,d4				; VP >255
	bne wait
	move.l	#$ffe1fffe,(a0)+	; um unterhalb von Zeile 255 zu kommen
wait:
	move.l	d0,(a0)+			; lädt die erste wait-Anweisung in d0							
    move.l	d1,(a0)+			; COLOR00 - gelb
	move.l	d2,(a0)+			; COLOR00 - grau
	move.l	#$fffffffe,(a0)		; Ende der Copperlist
	rts

*******************************************************************************
* Dynamische Wanderung des Copperpixels	im Screen							  *
*******************************************************************************	

MoveCopPx:
	move.w	ObjX(pc),d0			; Position X
	move.w	ObjY(pc),d1			; Position Y
	move.w	VelX(pc),d2			; dx (Geschwindigkeit X)
	move.w	VelY(pc),d3			; dy (Geschwindigkeit Y)
	add.w	d2,d0				; x = x + dx
	add.w	d3,d1				; y = y + dy
	
ControlXmin:
	cmp.w	#LEFT,d0			; linken Rand überprüfen
	bhi.b	ControlXmax			; wenn es größer ist, überprüfe den rechten Rand
	neg.w	d2					; Bewegungsrichtung X umkehren
	;addq.b	#1,d1				; Variante 2 - Linie für Linie
	bra.s	ControlYmin			; Geh und überprüfe das Y
ControlXmax:
	cmp.w	#RIGHT,d0			; rechten Rand überprüfen
	blo.b	ControlYmax			; wenn es kleiner ist, überprüfe den oberen Rand
	neg.w	d2					; Bewegungsrichtung X umkehren
	;addq.b	#1,d1				; Variante 2 - Linie für Linie
ControlYmin:
	cmp.w	#TOP-1,d1			; oberen Rand überprüfen
	bhi.b	ControlYmax			; wenn es größer ist, überprüfe den unteren Rand	
	neg.w	d3					; Bewegungsrichtung umkehren
	bra.s	EndControl			; Kontrolle fertig
ControlYmax:
	cmp.w	#BOTTOM,d1			; unteren Rand überprüfen
	blo.b	EndControl			; wenn es kleiner ist, sind wir mit der Kontrolle fertig
	neg.w	d3					; Bewegungsrichtung X umkehren

EndControl:
	move.w	d0,ObjX				; Position und Geschwindigkeit aktualisieren
	move.w	d1,ObjY
	move.w	d2,VelX
	move.w	d3,VelY

	;move.w	d0,d5				; Position X
	;move.w	d1,d6				; Position Y

	rts
	
ObjX:	dc.w	20				; Position X
ObjY:	dc.w	1				; Position Y
VelX:	dc.w	1				; Geschwindigkeit X
VelY:	dc.w	1				; Geschwindigkeit Y

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

	SECTION GRAPHIC,DATA_C
	
Copperlist:
	dc.w	$120,$0000,$122,$0000,$124,$0000,$126,$0000,$128,$0000
	dc.w	$12a,$0000,$12c,$0000,$12e,$0000,$130,$0000,$132,$0000
	dc.w	$134,$0000,$136,$0000,$138,$0000,$13a,$0000,$13c,$0000
	dc.w	$13e,$0000
	
	dc.w	$8e,DIWSTRT	; DIWSTRT	
	dc.w	$90,DIWSTOP	; DIWSTOP
	dc.w	$92,DDFSTRT	; DDFSTRT
	dc.w	$94,DDFSTOP	; DDFSTOP
	dc.w	$102,0		; BPLCON1
	dc.w	$104,0		; BPLCON2
	dc.w	$108,0		; BPL1MOD
	dc.w	$10a,0		; BPL2MOD

				; 5432109876543210
	dc.w	$100,%0001001000000000	; bit 12 an!!	(1 = %001)	1 Bitplane: (2 Farben)

Bplpointers:
	dc.w	$e0,$0,$e2,$0		; erste	Bitplane - BPL0PT
	dc.w	$0180,$444			; COLOR00 - grau
	dc.w	$0182,$fff			; COLOR01 - weiß
		
CopPos:							
	dcb.w	10,0				; dieser Bereich wird durch bsr InitCopper geändert

	dc.w	$ffff,$fffe

Bitplane:
	;dcb.b	10240,0
	incbin	"/Sources/320x256x1_raster.raw"	; Bild im RAW 1 Bitplane

	end


Erklärung:

In diesem Listing wird die Ermittlung der Copper-Wait-Position in Bezug zu 
einer Pixelposition in einem LowRes-Screen mit 320x256 Pixeln gezeigt.
Der Lowres-Screen hat dabei die obere linke Ecke an der Position DIWSTRT mit
x=$81 (129) und y=$2c (44). Wie kann die Wait-Position berechnet werden?
Die linke Bildschirmposition kann mit $5c gefunden werden. (DIWSTRT: $2c5c)
Die durch Tests dazugehörende horizontale Copper-Wait-Position wurde mit $2e
ermittelt. Es ist die erste wait-Position die nicht in einer neuen Zeile beginnt.

Achtung: Wenn der Copper-Move auf ein Vielfaches von 16, also dem dargestellten
Raster fällt, wird er durch die Vordergrundfarbe COLOR001 überschrieben.

Die Berechnung des Copper-Wait erfolgt auf folgende Weise:

A = DIWSTRT HH-Position z.B $81
B = linke Bildschirmposition $5c
C = Copper-Wait Offset $yy2f	(oder $yy2d)
D = gewünschte X Pixelposition

Copper-Wait = ((A-B)/2)+C+(D/2)

Copperpixel an Position X=0 bzezogen auf DIWSTRT HH=$81
Bsp.		(($81-$5c)/2)+$yy2f+(0/2)		= dc.w $yy41,$fffe	

Copper-Wait = ($81-$5c)/2 = $12 (18 Pixel)
							($12+$2f=$41) --> auf ungerades Bit 0 achten!
										  --> 41 entspricht der x-Position $81
	
Copperpixel an Position X=80 bzezogen auf DIWSTRT HH=$81
Bsp.		(($81-$5c)/2)+$yy2f+(80/2)		= dc.w $yy69,$fffe	

Copperpixel an Position X=160 bzezogen auf DIWSTRT HH=$81
Bsp.		(($81-$5c)/2)+$yy2f+(160/2)		= dc.w $yy91,$fffe	                                                                                                                                                                                                                                   $ff will be reached, but the horizontal position $fe will never
happen. Thus, the position will never reach $fffe.

You may be tempted to wait for horizontal position $fe (since it will never
happen), and put a smaller number into the vertical position field. This will
not lead to the desired result. The comparison operation is waiting for the
beam position to become greater than or equal to the entered position. If the
vertical position is not $ff, then as soon as the line number becomes higher
than he entered number, the comparison will evaluate to true and the wait will
end.
