
; Listing25c.s		horizontales Spritemultiplexing mit wait und SPRxPOS
; mit Copper-Move ("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)

	move.l	#MeinSprite,d0		; Adresse des Sprite in d0
	lea	SpritePointers,a1		; Pointer in der Copperlist
	move.w	d0,6(a1)
	swap	d0
	move.w	d0,2(a1)

	bsr InitCopper				; 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

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

InitCopper:
	lea CopperSprite,a0
	move.l	#$2c39fffe,(a0)+		; 1. wait			
	move.l	#$01402c40,(a0)+		; SPR0POS V=$2c, H=$40 
	move.l  #$01fe0000,(a0)+		; Copper-NOP
	move.l	#$01402c48,(a0)+		; SPR0POS V=$2c, H=$48 
;---
	move.l	#$2d39fffe,(a0)+		; 2. wait			
	move.l	#$01402c40,(a0)+		; SPR0POS V=$2c, H=$40 
	move.l  #$01fe0000,(a0)+		; Copper-NOP
	move.l	#$01402c48,(a0)+		; SPR0POS V=$2c, H=$48 
;---
	;.... in diesem Schema für alle Zeilen des Sprites wiederholen
;---
	move.l	#$3839fffe,(a0)+		; x. wait			
	move.l	#$01402c40,(a0)+		; SPR0POS V=$2c, H=$40 
	move.l  #$01fe0000,(a0)+		; Copper-NOP
	move.l	#$01402c48,(a0)+		; SPR0POS V=$2c, H=$48 

	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,$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

				; 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:
	dcb.w	3*4*2+2,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:

Beim horizontalen Spritemultiplexing ist die größte Herausvorderung das genaue
Timing zwischen aktueller Elektronenstrahlposition und der Startposition des 
Sprites.

Deswegen zunächst ein Blick in die DMA-Debugger Ausgabe um die Zusammenhänge
besser zu verstehen:


 [38     -]   [39     -]   [3A     -]   [3B     -]   [3C     -]   [3D     -]   [3E     -]   [3F     -]
                                                     COP    08C                COP    140
 0                         W                               0140                      2C40
                                                       00030804                  00030806

                                                      102   084                 103   084

 [40     -]   [41     -]   [42     -]   [43     -]   [44     -]   [45     -]   [46     -]   [47     -]
 COP    08C                COP    1FE   BPL1   110   COP    08C                COP    140
       01FE                      0000         0000         0140                      2C48
   00030808                  0003080A     00030890     0003080C                  0003080E

  104   084                 105   084    148   084    106   084                 107   084

 [48     -]   [49     -]   [4A     -]   [4B     -]   [4C     -]   [4D     -]   [4E     -]   [4F     -]
 COP    08C                COPW   08C   BPL1   110
       FFFF                      FFFE         0000
   00030810                  00030812     00030892

  108   084                 109   084    149   084

Abbildung: DMA-Debugger an $43 bzw. $4B BPL1-Abruf, SPRxPOS Änderung muss vorher erfolgen

Um Sprites anzuzeigen ist die Aktivierung mindestens einer Bitebene 
erforderlich. BPL1 ist dabei in jeder 16 Pixel-Gruppe von Bitplane-DMA Abrufen
immer der letzte Abruf. Somit ist auch vor diesem letzten BPL1-Abruf der 
letztmögliche Zeitpunkt für eine Aktualisierung der Startposition des Sprites
wenn diese mit dem abgeschlossenen BPL1-Abruf auf der nun folgenden Ausgabe 
auf dem Bildschirm erfolgen soll.
Die vertikale und horizontale Startposition des Sprites kann bereits am Anfang
des Frames festgelegt werden, aber hier ist der letztmögliche Zeitpunkt.

Der Sprite-DMA Abruf erfolgt am Anfang der Rasterzeile. Damit der Datenabruf
erfolgt muss allerdings zu diesem Zeitpunkt bereits das Sprite gestartet
wurden sein. Das bedeutet eine "frühere" Startposition muss dafür sorgen, dass
das Sprite zunächst gestartet wird um den Datenabruf zu aktivieren und 
anschließend kann die Startposition nochmal geändert werden.

Wenn Sprite-DMA aktiviert wurde können die ersten Sprite-DMA Abrufe in 
Zeile $19 nicht verhindert werden. Hier liest die Hardware die ersten Wörter
als Steuerwörter in die Sprite-Control-Register SPRxPOS und SPRxCTL ein.
Findet die Hardware als Steuerwörter das Wertepaar 0,0 wird kein Sprite 
angezeigt.
Findet es dagegen eine vertikale und horizontale Startposition wird das Sprite
bei Erreichen dieser Position gestartet. Erfolgt der Start rechtzeitig vor
dem Sprite-DMA Abruf auf der Rasterzeile werden die Sprite-Data Register 
SPRxDATA und SPRxDATB mit den Bitplanedaten des Sprites geladen.

Anschließend kann immer noch die Startposition noch verschoben werden und 
das Sprite wird an einer anderen Stelle angezeigt.

Dieses Verhalten machen wir uns zu Nutze in dem wir die Spritestruktur so
vorbereiten, dass mit dem ersten Datenabruf in Zeile $19 durch die Sprite-
Hardware die Controlregister so voreingestellt werden, dass das Sprite in
Zeile $2c angezeigt würde. Durch diese Voreinstellung erhalten wir in Zeile
$2c die Sprite-DMA Abrufe für die Bilddaten dieser Zeile. Ohne diese
Vorbereitung würden wir diesen Datenabruf verlieren. Die horizontale
Position spielt dabei keine Rolle. Wir sagen hier $3f. Es hätte aber auch
jeder beliebige andere Wert zwischen $00 und $ff sein können.

Um den Unterschied zu sehen:
Vstart:
	dc.b $2c	; Vertikale Anfangsposition des Sprite
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

ändern in

Vstart:
	dc.b $0		; Vertikale Anfangsposition des Sprite
Hstart:
	dc.b $0		; Horizontale Anfangsposition des Sprite
Vstop:
	dc.b $0		; 
	dc.b $0

Dann als nächstes um nun alle 16 Pixel das Sprite neu zu positionieren,
besteht die Möglichkeit für einfache Sprites zwei Copper-Moves im Wechsel
durchzuführen:

	move.l	#$01402c40,(a0)+		; SPR0POS V=$2c, H=$40 
	move.l  #$01fe0000,(a0)+		; Copper-NOP

oder selbstverständlich auch in der getauschten Reihenfolge, jedoch immer vor
dem BPL1-DMA-Abruf oder für Attached-Sprites:
	
	move.l	#$01402c40,(a0)+		; SPR0POS V=$2c, H=$40 
	move.l  #$01422c40,(a0)+		; SPR1POS V=$2c, H=$40

Um das Sprite für alle Zeilen anzuzeigen ist jeweils ein Wait vor dem ersten
SPRxPOS der Zeile notwendig.                 