***********************************************************
* 1991 Epsilon
* Writen by the Dancing Fool.  Use it, abuse it, but don't
* release it and say you wrote it! :^)
* This isn't the world's best sine scroll, but it works
* and it'll give you an idea how to write your own.
*
* Here's basically how a sine scroll works:
*
* You set up an off screen area, a scroll_pad, where you will scroll your
* text.  Every frame you point to the bottom right hand corner of the pad
* and blit it to itself in decending mode with a shift value equal to however
* fast you want to scroll it.  This is a plain scroller and is done by my
* 'Scroller' routine.  If you do this on screen you will see an old C64
* demo! :^)
*
* Now comes the tricky part.  Every frame you have to take each group of
* pixels, depending on how big your splits are (mine are two pixels), and
* copy them to the screen, each time at a different horizontal position.
* You of course know that the blitter will only handle words, so how do you
* do this?  Easy.  You just set up a mask with the correct number of bits
* set (for two pixel splits I use 3) for your splits.  You blit each word
* of your scroll pad a set number of times (for 2 pixel splits, you do it
* 8 times), each time rotating your mask and getting a new horizontal position.
* You repeat this for every word and wa-la!  You have a sine-scroller!
*
* Enjoy!
***********************************************************

WaitBlit	MACRO
		tst.b	2(a5)		; test it once and ignore
.\@:		btst.b	#6,2(a5)	; test blit busy bit in DMACON
		bne.b	.\@		; not done yet...
		ENDM
		
***********************************************************

FROM_RIGHT	EQU	1			; try this as a 0

NUM_STARS	EQU	13			; number of stars at each speed
STAR_START	EQU	$2c			; raster for stars to start at
SKIP		EQU	35*40			; number of bytes to skip in
						;   bpl to get desired raster
						;   position.

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

		bsr.w	TakeSystem
MouseWait:	btst.b	#6,$bfe001		; wait for left mouse button
		bne.s	MouseWait

		bsr.w	RestoreSystem
		rts

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

MyLevel3:
		move.l	ActiveBmap,d0
		move.l	VisualBmap,a6		; load for later...
		move.l	a6,ActiveBmap
		move.l	d0,VisualBmap

		lea	bmapptrs+2,a0		; install new bit map
		move.w	d0,4(a0)		;   in my copper list
		swap	d0
		move.w	d0,(a0)

		adda.l	#SKIP,a6		; see above (in with EQU's)

		bsr.b	Put_Scroll		; write text to screen
		bsr.w	Scroller		; move text
		bsr.w	Up_Date_Stars		; move star field

		addq.l	#2,sin_ptr		; update sine pointer for
		move.l	sin_ptr,a3		;   next time.
		tst.w	(a3)			; end of list?
		bpl.b	ret_ml31		; no
		move.l	#sin_table,sin_ptr	; reset

ret_ml31:	move.w	#$20,$dff09c	; set bit in interrupt request reg.
		rte

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

Put_Scroll:	WaitBlit
		
	; This nutty routine is the fastest way to clear a chunk of memory!
		move.w	#-1,$44(a5)	; this is for later...
		move.l	a6,$54(a5)	; a6 is pre loaded with addr. of bpl
		move.l	#0,$66(a5)	; no modulo
		move.l	#$01000000,$40(a5) ; set only the dest. bit in bltcon
	 	move.w	#(64*65)+40,$58(a5); size to clear

 IFNE	FROM_RIGHT
		adda.l	#38,a6			; right edge of bpl
		lea	scroll_pad+38,a2	; edge of scroll text
		moveq	#$0003,d4		; initial blt. mask
 ELSE
		lea	scroll_pad,a2		; edge of scroll text
		move.w	#$3000,d4		; initial blt. mask
 ENDIF

		move.l	sin_ptr,a3		; pointer to sine wave table

		moveq	#19,d6			; (width of bpl in words) - 1

	; pre-write modulos and minterms to save time in the loop
		WaitBlit
		move.w	#$0027,$62(a5)		; modulo
		move.l	#$00280027,$64(a5)	; modulo
		move.w	#$0dfc,$40(a5)		; A + B = D

.loop:		tst.w	(a3)			; end of sine table?
		bpl.b	.ret_value		; no
		lea	sin_table,a3		; reset to start
.ret_value:	move.w	(a3)+,d1		; get sine value

		lea	(a6,d1.w),a0		; find the correct row
		move.l	a0,a4
		
		WaitBlit
		movem.l	a0/a2/a4,$4c(a5)	; dest, src, dest
		move.w	d4,$46(a5)		; mask
 		move.w	#(64*12)+1,$58(a5)	; bltsize

 IFNE	FROM_RIGHT
		rol.w	#2,d4			; get new blit mask
 ELSE
		ror.w	#2,d4			; get new blit mask
 ENDIF
		bcc.b	.loop			; if no bits were rotated out,
						;   then we're on the same char

 IFNE	FROM_RIGHT
		subq.w	#2,a6			; get next spot on screen
		subq.w	#2,a2			; get next spot in scroll pad
 ELSE
		addq.w	#2,a6			; get next spot on screen
		addq.w	#2,a2			; get next spot in scroll pad
 ENDIF
 
		dbf	d6,.loop		; loop
		rts

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

Scroller:	tst.l	stop			; is stop value 0?
		beq.b	scrl			; yes
		subq.l	#1,stop			; dec. by one
		rts				; return to caller

scrl:		cmpi.w	#8,scrolls		; is it time for another char?
		blt.w	move_it			; no
		clr.w	scrolls			; set to 0

		move.l	ScrollTextPtr,a3	; get pointer to next chr. in text
		tst.b	(a3)			; is it end of text?
		bpl.b	nextchar		; no
		lea	ScrollText,a3		; reset to start

nextchar:	moveq	#0,d0			; clear upper 3 bytes
		move.b	(a3)+,d0		; get char
		move.l	a3,ScrollTextPtr	; save new pos. in text
	
		cmpi.b	#'a',d0			; is it speed change?
		bne.s	b			; no
		move.l	#$10000000,scroll_speed ; new speed
		move.w	#1,scroll_add		;  "    "
		bra.s	nextchar		; get a REAL char!

b:		cmpi.b	#'b',d0			; same as above
		bne.s	c
		move.l	#$20000000,scroll_speed
		move.w	#2,scroll_add
		bra.s	nextchar

c:		cmpi.b	#'c',d0			; same as above
		bne.s	d
		move.l	#$40000000,scroll_speed
		move.w	#4,scroll_add
		bra.s	nextchar

d:		cmpi.b	#'s',d0			; is it the stop char?
		bne.s	do_char			; no
		add.l	#150,stop		; add to wait value
		bra.s	nextchar		; get a real char!

do_char:	bsr.b	PutChar			; stamp char. down

move_it:	lea	scroll_pad+(11*42),a0	; dest.
		move.l	scroll_speed,d2		; shift value
		move.w	scroll_add,d4		; 
		or.l	#$09f00002,d2		; bltcon + shift value

		moveq	#0,d0			; modulo
		moveq	#-1,d3			; mask
		move.l	a0,a1

		WaitBlit

		movem.l	d2/d3,$40(a5)
		movem.l	a0/a1,$50(a5)
		move.l	d0,$64(a5)
 		move.w	#(64*12)+20,$58(a5)	
 	
		add.w	d4,scrolls
		rts
		
***********************************************************	
*d0:character

PutChar:	lea	scroll_pad+40,a0 ; dest.
		lea	Font,a1		; pointer to font gfx.

		moveq	#40,d1

		subi.b	#32,d0		; 0 is now for ' '
		cmp.b	d1,d0		; the font has 40 chars. in the first
		blt.b	BelowG		;   line.
		add.w	#400,a1		; add to get to next line of font
BelowG:		add.l	d0,a1		; addr. in font gfx of desired char.
	
		rept	10
		move.b	(a1),(a0)
		add.w	d1,a1
		add.w	#$2a,a0
		endr

		move.b	(a1),(a0)
		rts

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

Up_Date_Stars:
		move.l	#NUM_STARS,d0	; how many stars?
		lea	stars1+1,a1	; addr. of first star's x pos.

stars_top:	addq.b	#5,(a1)		; move the stars to the left at
		addq.w	#8,a1		;   four different speeds
		addq.b	#2,(a1)
		addq.w	#8,a1
		addq.b	#3,(a1)
		addq.w	#8,a1
		addq.b	#5,(a1)
		addq.w	#8,a1
		addq.b	#1,(a1)
		addq.w	#8,a1
		dbra	d0,stars_top	; loop
		rts

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

init_stars:
		move.l	#NUM_STARS,d0
		move.b	#STAR_START,d1
		lea	stars1,a0
makestars:
		move.b	d1,(a0)+		; y coord
		move.b	$5a(a5),d2
		mulu	$6(a5),d2
		eor.b	#$34,d2
		move.b	d2,(a0)+		; random x coord
		addq.b	#1,d1
		move.b	d1,(a0)+		; y stop
		addq.b	#2,d1
		move.b	#0,(a0)+
		moveq.l	#0,d2
		move.l	#$00010001,(a0)+	; star bit map
		move.b	d1,(a0)+		; y coord
		move.b	$7(a5),d2
		mulu	$6(a5),d2
		eor.b	d0,d2
		move.b	d2,(a0)+		; random x coord
		addq.b	#1,d1
		move.b	d1,(a0)+		; y stop
		addq.b	#1,d1
		move.b	#0,(a0)+
		moveq.l	#0,d2
		move.l	#$00010000,(a0)+	; star bit map
		move.b	d1,(a0)+		; y coord
		move.b	$7(a5),d2
		mulu	d0,d2
		eor.b	d0,d2
		move.b	d2,(a0)+		; random x coord
		addq.b	#1,d1
		move.b	d1,(a0)+		; y stop
		addq.b	#1,d1
		move.b	#0,(a0)+
		moveq.l	#0,d2
		move.l	#$00000001,(a0)+		; star bit map	
		move.b	d1,(a0)+		; y coord
		move.b	$6(a5),d2
		mulu	#34,d2
		eor.b	d0,d2
		move.b	d2,(a0)+		; random x coord
		addq.b	#1,d1
		move.b	d1,(a0)+		; y stop
		addq.b	#1,d1
		move.b	#0,(a0)+
		moveq.l	#0,d2
		move.l	#$000c0003,(a0)+	; star bit map
		move.b	d1,(a0)+		; y coord
		move.b	$6(a5),d2
		mulu	#18,d2
		eor.b	d0,d2
		move.b	d2,(a0)+		; random x coord
		addq.b	#1,d1
		move.b	d1,(a0)+		; y stop
		addq.b	#1,d1
		move.b	#0,(a0)+
		moveq.l	#0,d2
		move.l	#$000c0000,(a0)+ 	; star bit map
		dbra	d0,makestars
		rts
		
***********************************************************	

TakeSystem:	movea.l	4.w,a6		; ExecBase
		jsr	-$84(a6)	; Forbid() multitasking
	
		move.l	#$dff000,a5	; Custom chip base
		move.w	$2(a5),d0	; Save DMACON
		move.w	$1c(a5),d1	; Save INTENA
		or.w	#$8000,d0	; OR in the SET bit for when we...
		or.w	#$c000,d1	;    rewrite these registers
		move.w	d0,DMACONSave	; Keep it
		move.w	d1,INTENASave	; Keep it

		move.w	#$7fff,$9a(a5)	; Kill all interrupts!
		move.w	#$7fff,$96(a5)	; Kill all DMA!

		bsr.w	InstallSprites
		bsr.w	init_stars
		bsr.w	InstallBmap

		move.l	#Copper,$80(a5)	; install copper

		move.l	$6c.w,Level3Save; Keep ptr to level 3 interrupt
		move.l	#MyLevel3,$6c.w	; Install my level 3 interrupt

		move.w	#$83e0,$96(a5)	; Turn on only certain DMA channels
		move.w	#$c020,$9a(a5)	; Turn on VBLANK (lev 3) interrupt only
		rts			; Done

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

RestoreSystem:	move.l	#$dff000,a5	; Custom chip base
		move.w	#$7fff,$96(a5)	; Again, kill all DMA
		move.w	#$7fff,$9a(a5)	; Kill all interrupts
		move.l	Level3Save,$6c.w ; Install old level 3 interrupt

		movea.l	4.w,a6		; ExecBase
		lea	GraphicsName,a1	; "graphics.library"
		jsr	-$198(a6)	; OldOpenLibrary()
		move.l	d0,a1		; Copy ptr to GfxBase
		move.l	$26(a1),$80(a5)	; Install old system copperlist
		jsr	-$19e(a6)	; CloseLibrary()

		move.w	DMACONSave,$96(a5) ; Activate old DMA channels
		move.w	INTENASave,$9a(a5) ; Reenable old interrupts
		jsr	-$8a(a6)	; Permit() multitasking
		rts			; Done

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

InstallBmap:	lea	bmapptrs+2,a0
		move.l	VisualBmap,d0
		move.w	d0,4(a0)
		swap	d0
		move.w	d0,(a0)
		rts

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

InstallSprites:	lea	sprptrs+2,a0
		move.l	#NullSprite,d0
		move.w	d0,4(a0)
		move.w	d0,12(a0)
		move.w	d0,20(a0)
		move.w	d0,28(a0)
		move.w	d0,36(a0)
		move.w	d0,44(a0)
		move.w	d0,60(a0)
		swap	d0
		move.w	d0,(a0)
		move.w	d0,8(a0)
		move.w	d0,16(a0)
		move.w	d0,24(a0)
		move.w	d0,32(a0)
		move.w	d0,40(a0)
		move.w	d0,56(a0)

		move.l	#stars1,d0
		move.w	d0,52(a0)
		swap	d0
		move.w	d0,48(a0)
		rts

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

		section fish_sticks,data

ActiveBmap:	dc.l	Bmap1
VisualBmap:	dc.l	Bmap2

GraphicsName:	dc.b	'graphics.library',0
		EVEN

scroll_add:	dc.w	1

ScrollTextPtr:	dc.l	ScrollText
ScrollText:	dc.b	' a HELLO IS THIS SINE SCROLL WORKING?  '
		DC.B	'THIS IS A SPEED OF ONE....       '
		DC.B	' b THIS IS A SPEED OF TWO....       '
		DC.B	' c AND THIS IS A SPEED OF FOUR....       '
		DC.B	' a          HERE IS THE STOPPER          s       '
		DC.B	'CONTACT EPSILON AT:     EPSILON     P.O.B. 1914 '
		DC.B	'    BEAVERTON, OR  97075-1914     U.S.A.     -OR- '
		DC.B	'    SEND ME E-MAIL AT:  IDR@RIGEL.CS.PDX.EDU     '
		DC.B	'TEXT RESTARTS.....                 '
		dc.b	$ff
		even
	
sin_ptr:	dc.l	sin_table
sin_table:	include	'sine1'
		dc.w	$ffff
	
***********************************************************

		section	squid,data_c

Font:		incbin	'slimfont.raw'

Copper:		dc.w	$0100,$1200,$0102,$0000,$0104,$0000,$0108,$0000
		dc.w	$010a,$0000,$0180,$0000
		dc.w	$01ba,$0555,$01bc,$0fff,$01be,$0888
		dc.w	$008e,$2c71,$0090,$14d1,$0092,$0036,$0094,$00ce
bmapptrs:	dc.w	$00e0,$0000,$00e2,$0000
sprptrs:	dc.w	$0120,$0000,$0122,$0000,$0124,$0000,$0126,$0000
		dc.w	$0128,$0000,$012a,$0000,$012c,$0000,$012e,$0000
		dc.w	$0130,$0000,$0132,$0000,$0134,$0000,$0136,$0000
		dc.w	$0138,$0000,$013a,$0000,$013c,$0000,$013e,$0000
color_bars:	dc.w	$5e0f,$fffe,$5f0f,$fffe,$0182,$0011

		dc.w	$600f,$fffe,$0182,$0022,$610f,$fffe,$0182,$0033
		dc.w	$620f,$fffe,$0182,$0044,$630f,$fffe,$0182,$0055
		dc.w	$640f,$fffe,$0182,$0066,$650f,$fffe,$0182,$0077
		dc.w	$660f,$fffe,$0182,$0088,$670f,$fffe,$0182,$0099
		dc.w	$680f,$fffe,$0182,$00aa,$690f,$fffe,$0182,$00bb
		dc.w	$6a0f,$fffe,$0182,$00cc,$6c0f,$fffe,$0182,$00dd
		dc.w	$6d0f,$fffe,$0182,$00ee,$6e0f,$fffe,$0182,$00ff
		dc.w	$6f0f,$fffe,$0182,$01ef

		dc.w	$700f,$fffe,$0182,$02df,$710f,$fffe,$0182,$03cf
		dc.w	$720f,$fffe,$0182,$04bf,$730f,$fffe,$0182,$05af
		dc.w	$740f,$fffe,$0182,$069f,$750f,$fffe,$0182,$078f
		dc.w	$760f,$fffe,$0182,$087f,$770f,$fffe,$0182,$096f
		dc.w	$780f,$fffe,$0182,$0a5f,$790f,$fffe,$0182,$0b4f
		dc.w	$7a0f,$fffe,$0182,$0c3f,$7b0f,$fffe,$0182,$0d2f
		dc.w	$7c0f,$fffe,$0182,$0e1f,$7d0f,$fffe,$0182,$0f0f  
		dc.w	$7e0f,$fffe,$0182,$0e1e,$7f0f,$fffe,$0182,$0d2d

		dc.w	$800f,$fffe,$0182,$0c3c,$810f,$fffe,$0182,$0b4b
		dc.w	$820f,$fffe,$0182,$0a5a,$830f,$fffe,$0182,$0969
		dc.w	$840f,$fffe,$0182,$0878,$850f,$fffe,$0182,$0787
		dc.w	$860f,$fffe,$0182,$0696,$870f,$fffe,$0182,$05a5
		dc.w	$880f,$fffe,$0182,$04b4,$890f,$fffe,$0182,$03c3
		dc.w	$8a0f,$fffe,$0182,$02d2,$8b0f,$fffe,$0182,$01e1
		dc.w	$8c0f,$fffe,$0182,$00f0,$8d0f,$fffe,$0182,$01f0
		dc.w	$8e0f,$fffe,$0182,$02f0,$8f0f,$fffe,$0182,$03f0

		dc.w	$900f,$fffe,$0182,$04f0,$910f,$fffe,$0182,$05f0
		dc.w	$920f,$fffe,$0182,$06f0,$930f,$fffe,$0182,$07f0
		dc.w	$940f,$fffe,$0182,$08f0,$950f,$fffe,$0182,$09f0
		dc.w	$960f,$fffe,$0182,$0af0,$970f,$fffe,$0182,$0bf0
		dc.w	$980f,$fffe,$0182,$0cf0,$990f,$fffe,$0182,$0df0
		dc.w	$9a0f,$fffe,$0182,$0ef0,$9b0f,$fffe,$0182,$0ff0
		dc.w	$9c0f,$fffe,$0182,$0ff1,$9d0f,$fffe,$0182,$0ff2
		dc.w	$9e0f,$fffe,$0182,$0ff3,$9f0f,$fffe,$0182,$0ff4

		dc.w	$a00f,$fffe,$0182,$0ff5,$a10f,$fffe,$0182,$0ff6
		dc.w	$a20f,$fffe,$0182,$0ff7,$a30f,$fffe,$0182,$0ff8
		dc.w	$a40f,$fffe,$0182,$0ff9,$a50f,$fffe,$0182,$0ffa
		dc.w	$a60f,$fffe,$0182,$0ffb,$a70f,$fffe,$0182,$0ffc
		dc.w	$a80f,$fffe,$0182,$0ffd,$a90f,$fffe,$0182,$0ffe
		dc.w	$aa0f,$fffe,$0182,$0fff,$ab0f,$fffe,$0182,$0fee
		dc.w	$ac0f,$fffe,$0182,$0fdd,$ad0f,$fffe,$0182,$0fcc
		dc.w	$ae0f,$fffe,$0182,$0fbb,$af0f,$fffe,$0182,$0faa

		dc.w	$b00f,$fffe,$0182,$0f99,$b10f,$fffe,$0182,$0f88
		dc.w	$b20f,$fffe,$0182,$0f77,$b30f,$fffe,$0182,$0f66
		dc.w	$b40f,$fffe,$0182,$0f55,$b50f,$fffe,$0182,$0f44
		dc.w	$b60f,$fffe,$0182,$0f33,$b70f,$fffe,$0182,$0f22
		dc.w	$b80f,$fffe,$0182,$0f11,$b90f,$fffe,$0182,$0f00
		dc.w	$ba0f,$fffe,$0182,$0e00,$bb0f,$fffe,$0182,$0d00
		dc.w	$bc0f,$fffe,$0182,$0c00,$bd0f,$fffe,$0182,$0b00
		dc.w	$be0f,$fffe,$0182,$0a00,$bf0f,$fffe,$0182,$0900

		dc.w	$c00f,$fffe,$0182,$0800,$c10f,$fffe,$0182,$0700
		dc.w	$c20f,$fffe,$0182,$0600,$c30f,$fffe,$0182,$0500
		dc.w	$c40f,$fffe,$0182,$0400,$c50f,$fffe,$0182,$0300
		dc.w	$c60f,$fffe,$0182,$0200,$c70f,$fffe,$0182,$0100
		dc.w	$c80f,$fffe,$0182,$0000

		dc.w	$cc0f,$fffe
		dc.w	$0108,-120	; display up through the bpl
		dc.w	$010a,-120	;   backwards!  (flip it vertically)
		dc.w	$0180,$0004,$0182,$0444
		dc.l	-2

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

		section nein_farb,bss

scroll_speed:	ds.l	1
scrolls:	ds.w	1
DMACONSave:	ds.w	1
INTENASave:	ds.w	1
Level3Save:	ds.l	1			
stop:		ds.l	1
		
***********************************************************

		section farb,bss_c
NullSprite:	ds.l	3	; 2 controll words,2 data words,2 blank word
		ds.l	3*42
scroll_pad:	ds.b	12*42
Bmap1:		ds.b	7000
Bmap2:		ds.b	7000
stars1:		ds.l	(NUM_STARS*15)
