From: larshaug@ifi.uio.no (Lars Haugseth)
Newsgroups: alt.sys.amiga.demos
Subject: Source : Horizontal scroller
Date: 12 Dec 92 19:32:43 GMT
Organization: Dept. of Informatics, University of Oslo, Norway
Originator: larshaug@yrsa.ifi.uio.no




It's time to hit the hardware again, and maybe earn
some more flames. 8)

Ok, here is small program I made that simply scrolls
a 5 bitplane 320x256 pixels picture leftwards, and inserts
new graphics at the right edge of the screen. The graphics are
built up by 16x16 pixel blocks. I have included some example
block-data as a uuencoded LhA-archive. (Separate posting)

The scrolling works as follows:

After smooth-scrolling the picture 16 pixel with the BLTCON1 register,
I add 2 bytes to the bitplane-pointers, and blit new blocks into the
memory which lies off the right edge of the screen. It's as simple as
that. It's very simple to extend the program to scroll in both directions,
but that part you must figure out yourselves.

The memory usage for the graphics are [ SW * (SH + MX) ] bytes,
where SW is the screenwidth in bytes, SH is the screenheight in
pixels, and MX is the maximum number of screenwidths you can scroll.
I have set MX=32, which means you can scroll 352x32 pixels, which
should be more than enough for most vertical scrolling games.

Time usage is about 4 rasterlines pr.frame when scrolling 1 pixel at a time.
If you'd like to scroll more pixel pr.frame, the time increases, but
it's still pretty fast.

+-----------------------------------------------------------+
| Lars Haugseth                                             +-+
| Dept. of Informatics,               <larshaug@ifi.uio.no> | |
| University of Oslo, Norway                                | |
|                                                           | |
|          If idiots could fly, this would be an airport... | |
+-+---------------------------------------------------------+ |
  +-----------------------------------------------------------+





;-------------------------------------------------------------------------
; BLOCK-SCROLLER
;-------------------------------------------------------------------------
; Programmed by Lars Haugseth 9/12-92
;-------------------------------------------------------------------------
; CONSTANTS
;-------------------------------------------------------------------------

EXECBASE	= 4

CUSTOMBASE	= $DFF000		; Custom-chips register offset

OpenLibrary	= -408			; Library function offsets
CloseLibrary	= -414
VBeamPos	= -384

SW		= 44			; Width of screen in bytes
SH		= 256			; Height of screen in pixels
MX		= 32			; Maximum pages of scrolling

;-------------------------------------------------------------------------
; MACROS
;-------------------------------------------------------------------------

WRAST:	MACRO				; Wait for a specific rasterpos.
	movem.l	d0-a6,-(SP)
	move.l	GFXBASE,a6
\@1	jsr	VBeamPos(a6)
	cmp.w	#\1,d0
	bne.s	\@1
	movem.l	(SP)+,d0-a6
	ENDM

WBLIT:	MACRO				; Wait for the blitter to finish
	btst	#6,$02(a5)
	bne.s	\@1
	bra.s	\@2
\@1	nop
	nop
	btst	#6,$02(a5)
	bne.s	\@1
\@2
	ENDM

;-------------------------------------------------------------------------
; PROGRAM
;-------------------------------------------------------------------------

	SECTION	"code",code_p

STARTPROG:

	move.l	EXECBASE,a6		; Open graphics.library
	lea	GFXNAME,a1
	moveq	#0,d0
	jsr	OpenLibrary(a6)
	move.l	d0,GFXBASE
	beq	EXIT

	lea	CUSTOMBASE,a5
	move.l	GFXBASE,a6

	move.l	$26(a6),OLDCOPPERLIST	; Save copperlist
	move.w	$1C(a5),OLDINTERRUPTS	; Save enabled interrupts
	move.w	$02(a5),OLDDMACONTROL	; Save dmacontrol

	move.w	#$87E0,$96(a5)		; Enable some DMAs
	move.w	#$7FFF,$9A(a5)		; Disable all interrupts

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

INITMAP:

	lea	SCROLLMAP,a0
	moveq	#0,d7
IMAP1:	cmp.w	#320,d7
	blt.s	IMAP2
	bsr	GETRANDOM
	bra.s	IMAP3
IMAP2:	move.w	d7,d0
IMAP3:	move.w	d0,(a0)+
	addq	#1,d7
	cmp.w	#[SW*8]*MX,d7
	bne.s	IMAP1

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

INITCOPPER:				; Initialize copperlist

	lea	COLOURS,a0		; Insert palette
	lea	COP1PALETTE+2,a1
	move.w	#31,d7
ICOP1:	move.w	(a0)+,(a1)
	addq.w	#4,a1
	dbf	d7,ICOP1

	move.l	#BLANKS,d0		; Insert blank sprites
	move.w	d0,COP1SPRITES+06
	move.w	d0,COP1SPRITES+14
	move.w	d0,COP1SPRITES+22
	move.w	d0,COP1SPRITES+30
	move.w	d0,COP1SPRITES+38
	move.w	d0,COP1SPRITES+46
	move.w	d0,COP1SPRITES+54
	move.w	d0,COP1SPRITES+62
	swap	d0
	move.w	d0,COP1SPRITES+02
	move.w	d0,COP1SPRITES+10
	move.w	d0,COP1SPRITES+18
	move.w	d0,COP1SPRITES+26
	move.w	d0,COP1SPRITES+34
	move.w	d0,COP1SPRITES+42
	move.w	d0,COP1SPRITES+50
	move.w	d0,COP1SPRITES+58

	move.l	#SCROLLPLANES+[0*SW],d0	; Insert Bitplane pointers
	move.l	#SCROLLPLANES+[1*SW],d1
	move.l	#SCROLLPLANES+[2*SW],d2
	move.l	#SCROLLPLANES+[3*SW],d3
	move.l	#SCROLLPLANES+[4*SW],d4
	add.l	d5,d0
	add.l	d5,d1
	add.l	d5,d2
	add.l	d5,d3
	add.l	d5,d4
	move.w	d0,COP1PLANE1+6
	move.w	d1,COP1PLANE2+6
	move.w	d2,COP1PLANE3+6
	move.w	d3,COP1PLANE4+6
	move.w	d4,COP1PLANE5+6
	swap	d0
	swap	d1
	swap	d2
	swap	d3
	swap	d4
	move.w	d0,COP1PLANE1+2
	move.w	d1,COP1PLANE2+2
	move.w	d2,COP1PLANE3+2
	move.w	d3,COP1PLANE4+2
	move.w	d4,COP1PLANE5+2

	move.l	#COPPERLIST,$80(a5)	; Start copperlist
	clr.w	$88(a5)

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

MAINLOOP:

	WRAST	$110			; Wait for rasterpos $111
	WRAST	$111

	move.w	#$722,$180(a5)		; Scroll screen, and set
	bsr	SCROLLER		; a red background colour
	move.w	#$000,$180(a5)		; to measure time

	btst	#6,$BFE001		; Loop until LMB is pressed
	bne.s	MAINLOOP

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

EXITPROGRAM:

	move.l	EXECBASE,a6		; Close graphics.library
	move.l	GFXBASE,a1
	jsr	CloseLibrary(a6)

EXIT:	lea	CUSTOMBASE,a5		; Restore old values and exit
	or.w	#$8000,OLDDMACONTROL
	or.w	#$8000,OLDINTERRUPTS
	move.w	OLDDMACONTROL,$96(a5)
	move.w	OLDINTERRUPTS,$9A(a5)
	move.l	OLDCOPPERLIST,$80(a5)
	clr.w	$88(a5)
	moveq	#0,d0
	rts

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

GETRANDOM:

	moveq	#0,d0			; Get a 'random' byte
	moveq	#0,d1
	move.b	$DFF007,d0
	move.b	$BFD800,d1
	eor.b	d1,d0
	rts

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

SCROLLER:				; Scrolling routine

	btst	#2,$DFF016		; Skip if RMB is pressed
	beq.w	SCRLX

	move.w	SCROLLPOS,d1		; Lowest 4 bits into BPLCON1
	and.w	#15,d1
	sub.w	#15,d1
	neg	d1
	mulu	#$11,d1
	move.w	d1,COP1SCROLL+2

	move.w	SCROLLPOS,d5		; Add words to Bitplane-pointers
	lsr.w	#4,d5
	add.w	d5,d5
	and.l	#$FFFE,d5

	move.l	#SCROLLPLANES+[0*SW],d0	; Update pointers in
	move.l	#SCROLLPLANES+[1*SW],d1	; copperlist
	move.l	#SCROLLPLANES+[2*SW],d2
	move.l	#SCROLLPLANES+[3*SW],d3
	move.l	#SCROLLPLANES+[4*SW],d4
	add.l	d5,d0
	add.l	d5,d1
	add.l	d5,d2
	add.l	d5,d3
	add.l	d5,d4
	move.l	d0,COPYADR		; Store address where new
	add.l	#SW-2,COPYADR		; blocks are to copied
	move.w	d0,COP1PLANE1+6
	move.w	d1,COP1PLANE2+6
	move.w	d2,COP1PLANE3+6
	move.w	d3,COP1PLANE4+6
	move.w	d4,COP1PLANE5+6
	swap	d0
	swap	d1
	swap	d2
	swap	d3
	swap	d4
	move.w	d0,COP1PLANE1+2
	move.w	d1,COP1PLANE2+2
	move.w	d2,COP1PLANE3+2
	move.w	d3,COP1PLANE4+2
	move.w	d4,COP1PLANE5+2

	bsr	COPYBLOCK			; Copy a block at right edge

	cmp.w	#8*SW*[MX-1],SCROLLPOS		; Scroll 1 pixel left
	bge.s	SCRLX
	addq.w	#1,SCROLLPOS

SCRLX:	rts

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

COPYBLOCK:					; Copy a block onto screen

	lea	SCROLLMAP,a0			; Get block number from
	add.w	SCROLLPOS,a0			; the map
	add.w	SCROLLPOS,a0
	move.w	(a0),d0

	lea	BLOCKS,a0			; Calculate address for
	mulu	#160,d0				; the block data
	add.l	d0,a0

	move.w	SCROLLPOS,d1			; Calculate address that
	and.l	#15,d1				; the block is copied into
	mulu	#5*16*SW,d1
	move.l	COPYADR,a1
	add.l	d1,a1

	lea	CUSTOMBASE,a5			; Blit block onto screen
	WBLIT
	move.l	a0,$50(a5)			; BLTAPTR
	move.l	a1,$54(a5)			; BLTDPTR
	move.l	#$0000002A,$64(a5)		; BLTAMOD BLTDMOD
	move.l	#$09F00000,$40(a5)		; BLTCON0 BLTCON1
	move.w	#$1401,$58(a5)			; BLTSIZE
	WBLIT
	rts

;-------------------------------------------------------------------------
; PUBLICMEM STORAGE
;-------------------------------------------------------------------------

		SECTION "publicdata",data_p

OLDCOPPERLIST:	dc.l	0
OLDINTERRUPTS:	dc.l	0
OLDDMACONTROL:	dc.l	0

SCROLLPOS:	dc.w	0		; Scrollposition in pixels

COPYADR:	dc.l	0		; Where to copy new blocks on screen

COLOURS:	dc.w	$000,$FFF,$EEE,$DDD,$CCC,$BBC,$AAB,$99A	; Palette
		dc.w	$889,$777,$666,$555,$444,$333,$222,$111
		dc.w	$F87,$E65,$C43,$911,$800,$600,$400,$300
		dc.w	$500,$B98,$DB9,$FDC,$846,$956,$A67,$A79

SCROLLMAP:	blk.w	[SW*8]*MX,0	; Block map

GFXBASE:	dc.l	0
GFXNAME:	dc.b	"graphics.library",0

;-------------------------------------------------------------------------
; COPPERLIST
;-------------------------------------------------------------------------

		SECTION "chipdata",data_c

COPPERLIST:	dc.w	$008E,$2C81,$0090,$2CC1	; DisplayWindow
		dc.w	$0092,$0030,$0094,$00D0	; DataFetch
		dc.w	$0108,$00B2,$010A,$00B2	; BitplaneModulo
		dc.w	$0102,$0000,$0104,$0000	; BPLCON1 & BPLCON2

COP1SPRITES:	dc.w	$0120,$0000,$0122,$0000	; Sprite pointers
		dc.w	$0124,$0000,$0126,$0000
		dc.w	$0128,$0000,$012A,$0000
		dc.w	$012C,$0000,$012E,$0000
		dc.w	$0130,$0000,$0132,$0000
		dc.w	$0134,$0000,$0136,$0000
		dc.w	$0138,$0000,$013A,$0000
		dc.w	$013C,$0000,$013E,$0000

COP1PALETTE:	dc.w	$0180,$0000,$0182,$0000	; Palette
		dc.w	$0184,$0000,$0186,$0000
		dc.w	$0188,$0000,$018A,$0000
		dc.w	$018C,$0000,$018E,$0000
		dc.w	$0190,$0000,$0192,$0000
		dc.w	$0194,$0000,$0196,$0000
		dc.w	$0198,$0000,$019A,$0000
		dc.w	$019C,$0000,$019E,$0000
		dc.w	$01A0,$0000,$01A2,$0000
		dc.w	$01A4,$0000,$01A6,$0000
		dc.w	$01A8,$0000,$01AA,$0000
		dc.w	$01AC,$0000,$01AE,$0000
		dc.w	$01B0,$0000,$01B2,$0000
		dc.w	$01B4,$0000,$01B6,$0000
		dc.w	$01B8,$0000,$01BA,$0000
		dc.w	$01BC,$0000,$01BE,$0000

COP1PLANE1:	dc.w	$00E0,$0000,$00E2,$0000	; Bitplane pointers
COP1PLANE2:	dc.w	$00E4,$0000,$00E6,$0000
COP1PLANE3:	dc.w	$00E8,$0000,$00EA,$0000
COP1PLANE4:	dc.w	$00EC,$0000,$00EE,$0000
COP1PLANE5:	dc.w	$00F0,$0000,$00F2,$0000

COP1SCROLL:	dc.w	$0102,$0000		; FineScrolling BPLCON1

		dc.w	$2C07,$FFFE,$0100,$5200	; Turn on bitplanes at line $2C

		dc.w	$FFDF,$FFFE		; Wait below line $100

		dc.w	$2C07,$FFFE,$0100,$0000	; Turn off bitplanes at $12C

		dc.w	$FFFF,$FFFE		; End copperlist

;-------------------------------------------------------------------------
; CHIPMEM STORAGE
;-------------------------------------------------------------------------

SCROLLPLANES:	blk.b	5*SW*[SH+MX],0		; Scroll bitplanes

		incdir "df0:"			; Where to load includes
BLOCKS:		incbin "blocks.raw"		; Block image data

BLANKS:		dc.l	0,0			; Blank sprite

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