	Incdir	Df1:
	Include	Source/CustomRegisters

;-- CustomRegisters is an include file which defines all the custom
;-- chip registers I use and also creates three macros which make
;-- creating copperlists much easier ( Mov, Wait, Skip )

*************************************************************************
*****    Sorry but these examples will only work with DEVPAC II    ******
*****    despite what I said in the magazine                       ******
*************************************************************************

Ciaapra		= $BFE001	;CIA port a register, bit 6 is used for
				;the left mouse button, and bit 1 toggles
				;the power LED which is connected to the
				;low pass filter
Oldopenlibrary	= -$198		;Open a library of functions, a pointer
				;to the library name is sent in a1,
				;ignores the library version no.
Disable		= -$78		;Switch off interrupts,and multitasking
				;( taskswitching occurs in the vertical
				;blanking interrupt )
Enable		= -$7e		;Enable interrupts,including multitasking
Startlist	= 38		;The standard workbench copperlist.
Execbase	= 4		;A pointer to the EXEC library which
				;contains all the fundamental operating
				;system routines.

	Move.l	Execbase,a6
	Jsr	Disable(a6)	;Disable interrupts
	Bsr	Setup


;------ Wait for Vertical position 1 --------

Wait	Move.l	Vposr,d2
	And.l	#$0001ff00,d2
	Cmp.l	#$00000000,d2
	Bne.s	Wait

	Bsr	Main

	Btst	#6,Ciaapra	;Have you pressed the left button
	Bne.s	Wait

;------ Restore old Copper list -----------

	Move.l	Execbase,a6
	Move.l	#Grname,a1
	Clr.l	d0
	Jsr	Oldopenlibrary(a6)	;Open the graphics library
	Move.l	d0,a4
	Move.l	Startlist(a4),Cop1lc	;Restore the old copperlist
	Clr.w	Copjmp1
	Move.w	#$83E0,Dmacon
	Jsr	Enable(a6)		;Re-enable the interrupts
	Clr.l	d0			;No return-code errors
	Rts

;-------- Setup routine ----------

Setup
	Move.w	#$8780,Dmacon	;Make sure copper,blitter DMA is on
	Move.w	#$0020,Dmacon	;Turn off sprite DMA

	Lea	Spr0data,a0	;Now clear all sprite data to eliminate
	Moveq	#7,d0		;the lines you occasionaly get if you
Spr_clr				;forget to do this.
	Clr.l	(a0)
	Addq.l	#8,a0
	Dbf	d0,Spr_clr

;-- Clear the screen

	Lea	$70000,a0
	Move	#$1fff,d0
Clr_scr
	Clr.l	(a0)+
	Dbf	d0,Clr_scr

;-- Create the mask

	Lea	Bob_data(pc),a0
	Lea	Width(a0),a1
	Lea	Bob_mask(pc),a2
	Lea	Width(a2),a3

	Move	#Length-1,d1
Mask_loop2
	Move	#Width/2-1,d0
Mask_loop1
	Move	(a0)+,d2	;Or the seperate bitplanes of the bob
	Or	(a1)+,d2	;to determine its outline for the mask
	Move	d2,(a2)+
	Move	d2,(a3)+
	Dbf	d0,Mask_loop1

	Lea	Width(a0),a0
	Lea	Width(a1),a1
	Lea	Width(a2),a2
	Lea	Width(a3),a3
	Dbf	d1,Mask_loop2
	
	Move.l	#Clstart,Cop1lc		;Start up my own copperlist
	Clr	Copjmp1
	Rts

;----- Wait for the blitter to finish -----

Blit_wait
	Btst	#14,Dmaconr
	Bne.s	Blit_wait
	Rts

;--------- The main demo routine ----------
Main
;-- Double buffer the pointers and screens
;- Screen1 = $70000 , Screen2 = $74000

	Eor	#$4000,Bob_scr+2
	Eor	#$4000,Plane1+2
	Eor	#$4000,Plane2+2
	Move.l	Xa(pc),d0	;Swap the sine pointer
	Move.l	Xb(pc),Xa	;tables
	Move.l	d0,Xb
	Move.l	Ya(pc),d0
	Move.l	Yb(pc),Ya
	Move.l	d0,Yb

;-- Clear the previous bobs

	Move.l	Xa(pc),a3
	Move.l	Ya(pc),a4
	Moveq	#$46,d7		;36 bobs
Clear_bobs
	Move	(a3,d7),d0
	Move	(a4,d7),d1
	Bsr	Bob_clr
	Subq	#2,d7
	Bpl.s	Clear_bobs

;-- Calculate the new sine-positions

	Bsr	Sine_calc

;-- Now plot the bobs in their new positions

	Moveq	#$46,d7
	Move.l	Xa(pc),a3
	Move.l	Ya(pc),a4
Draw_bobs
	Move	(a3,d7),d0
	Move	(a4,d7),d1
	Bsr	Bob_draw
	Subq	#2,d7
	Bpl.s	Draw_bobs

	Rts

;--------- Sine bob calculate ---------
; This is a very slow sine-bob routine, but it is
; intentional as I think it is easier to understand
; this way. You will soon find ways of increasing
; the speed yourself.

X_vel1	= 3
X_vel2	= 4
Y_vel1	= 3
Y_vel2	= 2

X_add1	= 5
X_add2	= 12
Y_add1	= 7
Y_add2	= 8

Sine_calc
	Lea	Sintable(pc),a0
	Move.l	Xa(pc),a3
	Move.l	Ya(pc),a4

	Move	X_pt1(pc),d0	;Update the sine-pointers
	Add	#X_vel1*2,d0
	And	#$1fe,d0
	Move	d0,X_pt1

	Move	X_pt2(pc),d1
	Add	#X_vel2*2,d1
	And	#$1fe,d1
	Move	d1,X_pt2

	Move	Y_pt1(pc),d2
	Add	#Y_vel1*2,d2
	And	#$1fe,d2
	Move	d2,Y_pt1

	Move	Y_pt2(pc),d3
	Add	#Y_vel2*2,d3
	And	#$1fe,d3
	Move	d3,Y_pt2

	Moveq	#35,d7
Calc_loop
	Move	(a0,d0),d5	;The sine-table ranges from -32768
	Move	(a0,d1),d6	;to 32767
	Asr	d5
	Asr	d6
	Add	d5,d6
	Muls	#(320-Width*8),d6
	Swap	d6
	Add	#(160-Width*4),d6
	Move	d6,(a3)+

	Move	(a0,d2),d5
	Move	(a0,d3),d6
	Asr	d5
	Asr	d6
	Add	d5,d6
	Muls	#(200-Length),d6
	Swap	d6
	Add	#(100-Length/2),d6
	Move	d6,(a4)+

	Add	#X_add1*2,d0		;Update the sine_pointers
	And	#$1fe,d0		;for the next bob
	Add	#X_add2*2,d1
	And	#$1fe,d1
	Add	#Y_add1*2,d2
	And	#$1fe,d2
	Add	#Y_add2*2,d3
	And	#$1fe,d3

	Dbf	d7,Calc_loop
	Rts

;--------- Bob routine ----------
Width		= 6
Length		= 31
Bob_pt		Dc.l Bob_data
Msk_pt		Dc.l Bob_mask
Bob_scr		Dc.l $74000
Scr_width	= 40
No_pln		= 2		;Number of screen bitplanes

;-- Put x,y coordinate in d0,d1 respectively

Bob_draw
	Move	d0,d2
	Lsr	#4,d0
	Add	d0,d0		;Find which word to start drawing the bob on
	Mulu	#80,d1		;Find the screenline to start
					;drawing the bob
	Add	d1,d0
	Move.l	Bob_scr(pc),a0		;Start of the screen
	Lea	(a0,d0),a0		;a0 now has the first word to which
					;we want to copy the bob
	Bsr	Blit_wait
	Move.l	a0,Bltdpth
	Move.l	a0,Bltcpth		;Ch.C reads the screen data
	Move.l	Bob_pt(pc),Bltapth	;Ch.A is used for the bob data
	Move.l	Msk_pt(pc),Bltbpth	;Ch.B used for the mask,only A&B
					;can be shifted remember
	Move.l	#$ffff0000,Bltafwm	;Mask out the last word from A
	Clr	Bltamod
	Clr	Bltbmod
	Move	#Scr_width-Width,Bltcmod	;Move on to next screen
	Move	#Scr_width-Width,Bltdmod	;line

	And	#$0f,d2
	Ror	#4,d2
	Move	d2,d0
	Swap	d0
	Move	d2,d0			;This gets the A-B shift value into
					;the right place
	Or.l	#$fe20000,d0		;Use all 4 channels and set the
					;minterms for bob use.
	Move.l	d0,Bltcon0
	Move	#Length*No_pln*64+Width/2,Bltsize	;Blit the bob

	Rts		;This bob routine is not particularly fast
			;for instance in a demo you would create tables
			;for x,y position conversions, also some of the
			;blitter registers do not need to be changed
			;when plotting a new bob, but as this is supposed
			;to be a general bob routine I left these
			;optimisations out. See the 196 bob source for
			;an example of how far you can take this. Also
			;I have not used double buffering which is
			;essential for a large number of bobs.

Bob_clr
	Move	d0,d2
	Lsr	#4,d0
	Add	d0,d0
	Mulu	#80,d1

	Add	d1,d0
	Move.l	Bob_scr(pc),a0
	Lea	(a0,d0),a0

	Bsr	Blit_wait
	Move.l	a0,Bltdpth
	Move	#Scr_width-Width,Bltdmod
	Clr	Bltadat
	Move.l	#$1f00000,Bltcon0
	Move	#Length*No_pln*64+Width/2,Bltsize

	Rts
;--------- Constants -----------

Grname	Dc.b	"graphics.library",0

	Even

;--------- Variables -----------

Pointer	Dc.w 0
X_pt1	Dc.w $80
X_pt2	Dc.w $80
Y_pt1	Dc.w 0
Y_pt2	Dc.w 0

Xa	Dc.l Xs1
Xb	Dc.l Xs2
Ya	Dc.l Ys1
Yb	Dc.l Ys2

Xs1	Dcb.w 36,0
Ys1	Dcb.w 36,0

Xs2	Dcb.w 36,0
Ys2	Dcb.w 36,0

;---------- Copperlists -----------
Clstart
	Wait	0,2
	Mov	$4081,Diwstrt	;Define the screen window as
	Mov	$08c1,Diwstop	;320 x 200 starting on line 80
	Mov	$0038,Ddfstrt
	Mov	$00d0,Ddfstop

	Mov	0,Bplcon1	;No scrolling
	Mov	0,Bplcon2	;Clear bitplane/sprite priorities

	Mov	40,Bpl1mod	;We want the bitplanes to be arranged
	Mov	40,Bpl2mod	;side by side for faster bob plotting
Plane1
	Mov	0,Bpl1ptl	;Set the start of the screen
	Mov	7,Bpl1pth	;memory (must be placed in a
Plane2
	Mov	40,Bpl2ptl	;copperlist as it needs to be
	Mov	7,Bpl2pth	;set every frame)

	Mov	$2200,Bplcon0	;We want a 2 Bitplane, single playfield
				;screen

	Mov	$000,Color00	;Black background
	Mov	$900,Color01	;Shades of Red for the balls
	Mov	$800,Color02
	Mov	$600,Color03

	Wait	254,255		;Wait for an impossible position
				;tells the copper, this is the end
				;of the copperlist

;-------------- Binaries ---------------

Bob_data
	Incbin	Binary/Bob
Bob_mask
	Dcb.b	No_pln*Width*Length,0
Sintable
	Incbin	Binary/Sin
