
; Listing25c4.s		horizontales Spritemultiplexing mit wait und SPRxPOS
; mit Copper-Move	Folge oder Copper-Wait ("halbautomatischer Modus")

	SECTION ROCK'NROLL,CODE

Start:
	move.l	4.w,a6				; Execbase in a6
	jsr	-$78(a6)				; Disable - verhindert Interrupts
	lea	GfxName(PC),a1			; Libname
	jsr	-$198(a6)				; OldOpenLibrary
	move.l	d0,GfxBase
	move.l	d0,a6
	move.l	$26(a6),OldCop		; wir speichern die alte COP

	move.l	#Bitplane,d0		; Zeiger auf die "leere" Bitplane
	lea	Bplpointers,a1			; Bitplanepointer in der Copperlist
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)

	; Pointen auf den Sprite

	move.l	#MeinSprite,d0		; Adresse des Sprite in d0
	lea	SpritePointers,a1		; Pointer in der Copperlist
	move.w	d0,6(a1)
	move.w	d0,d4				; für InitCopper 2 zurücksetzen
	;add.b	#4,d4				; normalerweise, aber wir nutzen einen kleinen Trick aus	
	swap	d0
	move.w	d0,2(a1)
	
	bsr InitCopper1				; Copperlist vorbereiten

	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:
	btst	#6,$bfe001			; Maustaste 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

	; Variablen

Add8_16:		dc.b	0			; addiere 8 oder 16

	even

*******************************************************************************
* Diese Routine erstellt den horizontalen Spritemultiplex in der Copperliste  *
*******************************************************************************	

InitCopper1:						; alle 32 Pixel	
	move.l	#$2c39fffe,d0			; wait
	move.l	#$01402c40,d1			; SPR0POS V=$2c, H=$40
	moveq #0,d2						; Zeile des Sprites
	move.l	d0,d3					; Kopie wait
	lea CopperSprite,a0

	moveq #13-1,d6					; 13 Zeilen	
Zeile:
	moveq #10,d7					; 10 Anzahl Sprites horizontal nebeneinander
Horiz:
	move.l	d0,(a0)+				; wait
	move.l	d1,(a0)+				; SPR0POS V=$2c, H=$40+16
	add.b	#16,d1					; nächste horizontale Position
	add.l	#$00100000,d0			; nächste horizontale Waitposition +16
	dbf d7,Horiz
	move.l	d3,d0					; wait zurücksetzen
	add.l #$01000000,d2				; nächste Zeile
	add.l d2,d0						; zur Startzeile addieren

	move.b  #$40,d1					; SPR0POS zurücksetzen
	dbf d6,Zeile
	
*******************************************************************************
* Diese Routine erstellt den horizontalen Spritemultiplex in der Copperliste  *
*******************************************************************************

InitCopper2:						; alle 24 Pixel	
	move.l	#$4c39fffe,d0			; wait vorbereiten um anschließend im Raster zu bleiben
	move.l	#$01404c40,d1			; SPR0POS V=$4c, H=$40
	moveq #0,d2						; Zeile des Sprites
	move.l	d0,d3					; Kopie d0
	move.w  #$0122,(a0)+			; SPR0PTL		
	move.w	d4,(a0)+				; low-Anteil Adresse eintragen
									; unten erklärt
	move.l	#$4c01fffe,(a0)+		; am Anfang der Zeile
	move.l	d1,(a0)+				; um den ersten DMA-Abruf zu erhalten
	move.l	#$01425900,(a0)+
	
	moveq #13-1,d6					; 13 Zeilen	
Zeile2:
	moveq #14-1,d7					; 14 Anzahl Sprites horizontal nebeneinander
Horiz2:
	move.l	d0,(a0)+				; wait setzen
	move.l	d1,(a0)+				; SPR0POS V=$1a, H=$40+16 bzw. H=$40+8
	tst.b	Add8_16					; Flag abfragen
	bne Add16
Add8:
	add.b	#8,d1					; nächste horizontale Position +8 
	add.l	#$00080000,d0			; nächste horizontale Waitposition +16
	sne	Add8_16						; Flag nicht setzen
	bra Horiz2b
Add16:
	add.b	#16,d1					; nächste horizontale Position + 16
	add.l	#$00100000,d0			; nächste horizontale Waitposition +16
	seq	Add8_16						; Flag setzen
Horiz2b:	
	dbf d7,Horiz2
	move.l	d3,d0					; wait zurücksetzen
	add.l	#$01000000,d2			; nächste Zeile
	add.l d2,d0						; zur Startzeile addieren

	move.b  #$40,d1					; SPR0POS zurücksetzen
	dbf d6,Zeile2
	
*******************************************************************************
* Diese Routine erstellt den horizontalen Spritemultiplex in der Copperliste  *
*******************************************************************************

InitCopper3:
; einzelnes Sprite mit wait positionieren
	move.w  #$0122,(a0)+			; SPR0PTL		
	move.w	d4,(a0)+				; low-Anteil Adresse eintragen
									; unten erklärt

	move.l	#$6c01fffe,(a0)+		; am Anfang der Zeile
	move.l	#$01406c90,(a0)+		; um den ersten DMA-Abruf zu erhalten
	move.l	#$01427900,(a0)+	
	; wait für den Farbwechsel um genau an der horizontalen Position $90 
	; (horizontale Spriteposition einen Farbwechsel zu erhalten)
	move.l	#$7a8ffffe,(a0)+		; $hpos-1 $90-1=$8f
	move.l	#$01800f00,(a0)+		; Farbe rot setzen
	move.l	#$7b01fffe,(a0)+		; Beginn nächste Zeile
	move.l	#$01800000,(a0)+		; Farbe schwarz zurücksetzen

	move.l	#$7b91fffe,(a0)+		; $hpos-1 $90+1=$91
	move.l	#$01800f00,(a0)+		; Farbe rot setzen
	move.l	#$7c01fffe,(a0)+		; Beginn nächste Zeile
	move.l	#$01800000,(a0)+		; Farbe schwarz zurücksetzen

	move.l	#$fffffffe,(a0)			; Ende der Copperlist
	rts		
	
******************************************************************************

	SECTION GRAPHIC,DATA_C

Copperlist:
SpritePointers:
	dc.w	$120,0,$122,0,$124,0,$126,0,$128,0 ; Sprite
	dc.w	$12a,0,$12c,0,$12e,0,$130,0,$132,0
	dc.w	$134,0,$136,0,$138,0,$13a,0,$13c,0
	dc.w	$13e,0

	dc.w	$8e,$1a5c		; DIWSTRT
	dc.w	$90,$80d4		; DIWSTOP
	dc.w	$92,$20			; DDFSTRT
	dc.w	$94,$d8			; 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 Bitplane Lowres

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

	dc.w	$180,$000		; COLOR00	; Hintergrund Schwarz
	dc.w	$182,$123		; COLOR01	; Farbe 1 der Bitplane, die
							; in diesem Fall leer ist,
							; und deswegen nicht erscheint

	dc.w	$1a2,$f00		; COLOR17, oder COLOR1 des Sprite0 - rot
	dc.w	$1a4,$0f0		; COLOR18, oder COLOR2 des Sprite0 - grün
	dc.w	$1a6,$ff0		; COLOR19, oder COLOR3 des Sprite0 - gelb

CopperSprite:
	blk.l	2000,0
	dc.w	$ffff,$fffe		; Ende der Copperlist


; ************ Hier ist der Sprite: NATÜRLICH muß er in CHIP RAM sein! ************

MeinSprite:		; Länge 13 Zeilen
Vstart:
	dc.b $2c	; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
Hstart:
	dc.b $3f	; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
Vstop:
	dc.b $39	; $2c+13=$39 - Vertikale Endposition des Sprite
	dc.b $00
 dc.w	%0000000000000000,%1000110000110001 ; Binäres Format für ev. Änderungen
 dc.w	%0000000000000000,%0000011001100000
 dc.w	%0000000000000000,%0000001001000000
 dc.w	%0000000110000000,%0011000110001100 ; binär 00=Color 0 (durchsichtig)
 dc.w	%0000011111100000,%0110011111100110 ; binär 10=Color 1 (rot)
 dc.w	%0000011111100000,%1100100110010011 ; binär 01=Color 2 (grün)
 dc.w	%0000110110110000,%1111100110011111 ; binär 11=Color 3 (gelb)
 dc.w	%0000011111100000,%0000011111100000
 dc.w	%0000011111100000,%0001111001111000
 dc.w	%0000001111000000,%0011101111011100
 dc.w	%0000000110000000,%0011000110001100
 dc.w	%0000000000000000,%1111000000001111
 dc.w	%0000000000000000,%1111000000001111
 dc.w	0,0	; 2 word auf NULL definieren das Ende des Sprite.

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

	SECTION LEEREPLANE,BSS_C	

Bitplane:
	ds.b	40*256				; Bitplane auf 0 Lowres

	end
	

Erklärung:

Bedingt durch die Dauer von 16 Pixeln für einen Copper Wait sind horizontale
Wiederholungen nur alle 24 bzw. 32 Pixel möglich. 
(Copper Wait+Copper Move = 16 Pixel + 8 Pixel=24 Pixel)

Hinweis: bis 4 Bitebenen:
Copper-Move benötigt	8 Pixel lores
Copper-wait benötigt	16 Pixel lowres
Bei Verwenung von mehr als 4 Bitebenen würde es die Möglichkeiten weiter 
einschränken.

Variante 1: Abstand 32pixel
Wenn wir horizontales Spritemultiplexing mit vorangestellten Copper-Waits
erzielen wollen können wir dies nur mit einer Lücke von 16Pixeln zueinander
unabhängig voneinader erreichen.

Variante 2: Abstand 24Pixel
Es gibt eine Ausnahme, bei der wir bis zu zwei Sprites ohne Lücke zueinander
direkt nebeneinader platzieren können. Dies könnten wir dann aber ebenso gut
durch folgende Copper-NOP's erzielen.

Um eine Positionierung eines Sprites über ein Copper-Wait zu erreichen wären
folgende Schritte zu tätigen:

1. vertikale und horizontale Startposition des Sprites festlegen 
   SPRxPOS vvhh ; hh auf volle 16Bit abrunden

Mögliche Werte für hh sind: 
 x-Pos. - n
	$30	- 6
	$38
	$40	- 8
	$48
	$50	- 10
	$58
	$60	- 12
	$68
	$70	- 14
	$78
	$80	- 16
	$88
	$90	- 18	- Mitte
	$98
	$a0	- 20
	$a8
	$b0	- 22
	$b8
	$c0	- 24
	$c8
	$d0	- 26
	$d8
	$e0	- 28	- Ende (letzte)
	
Formel: x=(n*8) ; mit n= 6 bis 28

für DDFSTRT = $61 = ($60/2)=$30		$60=96	--> 96/16  ; d.h. n=6
für DDFSTRT = $81 = ($80/2)=$40		$80=128	--> 128/16 ; d.h. n=8
	Theoretisch ($1c0/2)=$e0		$1c0=448	--> 448/16 ; d.h. n=28

2. vs - vertikale Startposition ist vertikale Waitposition vv
3. das passende Wait ist folgendermassen zu wählen:

	dc.w $vvhh,$fffe	; allg. Anweisung
	dc.w $0140,$vshs	; SPR0POS

->  dc.w $2c39,$fffe	; hh 39 bis 3d (z.B. hs-1)
	dc.w $0140,$2c40	; SPR0POS

Das Wait muss in der Zeile direkt (bzw. spätestens) vor dem letzten BPL1-Abruf 
erfolgen. Dies setzt nur die Position.

Ggf. muss das Sprite-DMA in der ersten Zeile gestartet werden.

- Spritepointer zurücksetzen auf Anfang Bilddaten des Sprites
- dc.w $4c01,$fffe		; wait an Anfang der Zeile
- dc.w $0140,$2c40		; SPR0POS
 
Dabei sind maximal 10 Sprites parallel darstellbar.

zum "Trick":
in dem wir den Spritepointer ohne wait und damit noch auf der letzen Zeile des
Sprites ändern wird der Spritepointer mit der nächsten Zeile automatisch nach
dem Abrufen der Spritedaten erhöht und steht nun auf dem ersten Bilddatenpaar.
Durch:
	 move.l	#$4c01fffe,(a0)+		; am Anfang der Zeile
	 move.l	#$01404c40,(a0)+		; um den ersten DMA-Abruf zu erhalten

erfolgt dann der Datenabruf in dieser Zeile.

Bei Initcopper 3 wurde durch den Copper ein Farbwechsel auf der Zeile 
durchgeführt. Es beantwortet wie das wait eingestellt werden muss um genau
an einer gewünschten Position einen Farbwechsel zu erhalten.        