
; Listing25a.s		Anzeigen eines Sprites mit wait und SPRxPOS, SPRxCTL
; 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)

	; Pointen auf den Sprite wird hier nicht benötigt

	;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	d0,$88(a5)			; Start Copperlist
								; da die Copperlist mit jedem Vertical blank neugestartet 
								; wird, starten wir sie nicht
	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.w	d0,$dff088			; Starten der alten System Copperlist
								; da die Copperlist mit jedem Vertical blank neugestartet 
								; wird, starten wir sie nicht
	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

*******************************************************************************
* In dieser Routine wird das Anzeigen des Sprites durch den halbautomatischen *
* mit wait und SPRxPOS, SPRxCTL	vorbereitet								      *
*******************************************************************************

InitCopper:
	move.l	#$2c01fffe,d0		; 1. wait			
	move.l	#$01402c40,d1		; SPR0POS V=$2c, H=$40 
	move.l	#$01423900,d2		; SPR0CTL V=$39, H=0	$2c+13=$39
	move.l	#MeinSprite+4,d3	; Adresse des Sprite in d3 auf Spritedaten!
								; nicht auf die Steuerwörter!		
	lea	CopperSprite,a0			; Anfang des Spritebereichs in der Copperlist 
	move.l	d0,(a0)+			; setzt das erste wait	
;---------------
; Spritepointer setzen in Copperlist
	move.w	#$0120,(a0)+		; SPR0PTH
	swap d3	
	move.w	d3,(a0)+			; hi-Anteil Adresse eintragen
	move.w  #$0122,(a0)+		; SPR0PTL
	swap d3			
	move.w	d3,(a0)+			; low-Anteil Adresse eintragen
;----------------
    move.l	d1,(a0)+			; SPR0POS
	move.l	d2,(a0)+			; SPR0CTL

	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	5*2,0			; Raum für Spritedaten
	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 $60	; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
Hstart:
	dc.b $d0	; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
Vstop:
	dc.b $6d	; $60+13=$6d - 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	; Eine auf 0 gesetzte Bitplane, wir
								; müssen es verwenden, denn ohne Bitplane
								; ist es nicht möglich, die Sprites
								; zu aktivieren
Bitplane:
	ds.b	40*256				; Bitplane auf 0 Lowres

	end

	
Erklärung:

Bei dieser Variante muss der Spritepointer auf die Spritebilddaten und nicht
auf die Steuerwörter zeigen.

In diesem Beispiel haben wir den Spritepointer zu Beginn nicht auf das Sprite
gerichtet. Wir werden später sehen warum wir es trotzdem machen sollten.

;------------------------------------------------------------------------------
1. Damit das Sprite angezeigt wird, darf zum Zeitpunkt des Schreibens in
SPRxPOS die vertikale Startposition (die Zeile) des Sprites vom 
Elektronenstrahl noch nicht erreicht worden sein. 
Für den Fall, das ein Copper Wait den Zeitpunkt des Schreibens in SPRxPOS 
vorbestimmt, darf dieses Wait nicht "zu spät" erfolgen.

 00030800: 2c01 fffe            ;  Wait for vpos >= 0x2c and hpos >= 0x00
                                ;  VP 2c, VE 7f; HP 00, HE fe; BFD 1
 00030804: 0120 0003            ;  SPR0PTH := 0x0003
 00030808: 0122 0fd8            ;  SPR0PTL := 0x0fd8
 0003080c: 0140 2c40            ;  SPR0POS := 0x2c40
 00030810: 0142 3900            ;  SPR0CTL := 0x3900
 00030814: ffff fffe            ;  Wait for vpos >= 0xff and hpos >= 0xfe
 	
Wird z.B das wait auf $2d01 gesetzt wird kein Sprite angezeigt. 
Wenn allerdings die vertikale Zeile noch richtig ist, aber horizontal zu
spät, wird der Sprite Datafetch erst mit der nächsten Zeile gestartet und
es würde am Ende die letzte Zeile des Sprites fehlen. z.B bei $2c17

1. move.l	#$2c01fffe,d0 ; i.O.
2. move.l	#$2d01fffe,d0 ; kein Sprite zu sehen
3. move.l	#$2c17fffe,d0 ; letzte Zeile des Sprites fehlt, weil Sprite 
						  ; eine Zeile tiefer als gewollt beginnt	

Das Register SPRxCTL erhält das vertikale Sprite-Ende (Startposition + Höhe des
Sprites)

4. move.l	#$01423900,d2

>?$2c+!13
$00000039 = %00000000`00000000`00000000`00111001 = 57 = 57

Es signalisiert der Hardware, dass das Ende dieses Sprites erreicht ist, aber
stoppt das Sprite DMA Fetch damit nicht automatisch, sondern liest mit der
nächsten Zeile die kommenden Wörter automatisch als Steuerwörter ein. Je 
nachdem wie die vertikalen Start- und Stoppwerte nun sind wird das Datafetch
beendet oder neu gestartet. Um das Datafech mit Sicherheit zu beenden sollte
das Wertepaar 0,0 eingegeben werden.

;------------------------------------------------------------------------------
; 2. Zwei Varianten die Spritepointer in die Copperliste einzutragen
; Variante 1:
; 48 cycles
	move.w	#$0120,(a0)+		; SPR0PTH
	swap d4	
	move.w	d4,(a0)+			; hi
	move.w  #$0122,(a0)+		; SPR0PTL
	swap d4			
	move.w	d4,(a0)+			; low
;-------------------
; Variante 2:
; 64 cycles
	move.w	#$0120,(a0)			; SPR0PTH
	move.w	#$0122,4(a0)		; SPR0PTL
	move.w  d4,6(a0)			; low
	swap d4
	move.w  d4,2(a0)			; hi
	lea 8(a0),a0

;------------------------------------------------------------------------------
; 3. WinUAE Debugger - DMA-Debugger - Sprite datafetch

Der DMA-Debugger des WinUAE Debuggers bietet visuell die Möglichkeit sich den
Sprite-Datafetch anzusehen. Hierbei kann man folgendes beobachten:

Wird das Ende des Sprites in SPR0POS zwischen $2d00 und $3800 gesetzt endet das
Sprite und der Datafetch zunächt, aber in einigen Fällen sieht man, das der 
Sprite Datafetch neu gestartet und teilweise sogar vorzeitig beendet wird.

Was passiert also genau? Und warum taucht sprite data fetch unten nochmal auf?

Mit SPRxPOS wird die Startposition und mit SPRxCTL die Endposition festgelegt.
SPRxCTL sollte dabei auf das letzte Bitplanepaar des Sprites zeigen. 
Anschließend erfolgt mindestens noch ein automatischer DMA-Abruf und die Daten
werden wieder als Steuerwörter interpretiert.
Zeigt es auf 0,0 wird Sprite-DMA in jedem Fall beendet.
Ansonsten gilt, dass die Start- und Endwerte allgemein kleiner als die aktuelle
Elektronenstrahlposition sein muss ansonsten würde das Datafetch erneut 
starten.

Z.B.: unser Sprite:
Wäre es ein Wert zwischen $2d00 bis $3800 würde das Sprite vor dem eigentlichen
Ende zunächst beendet, könnte aber mit den dann "ungültigen" Steuerwörtern das 
Datafetch wieder starten und auch wieder beenden.

0000 8C31		  $2c	
0000 0660 SPR0CTL $2d Datafetch endet
0000 0240 SPR0CTL $2e Datafetch endet
0180 318C SPR0CTL $2f Datafetch startet unten neu und auch oben
07E0 67E6 SPR0CTL $30 Datafetch startet unten neu
07E0 C993 SPR0CTL $31 Datafetch endet
0DB0 F99F SPR0CTL $32 Datafetch startet unten neu
07E0 07E0 SPR0CTL $33 Datafetch endet 
07E0 1E78 SPR0CTL $34 Datafetch endet
03C0 3BDC SPR0CTL $35 Datafetch startet unten neu und auch oben
0180 318C SPR0CTL $36 Datafetch startet unten neu
0000 F00F SPR0CTL $37 Datafetch startet unten neu
0000 F00F SPR0CTL $38 Datafetch startet unten neu
0,0				  $39 Datafetch endet mit Sicherheit
                                                                            