*
*	Polygon drawing demo, with clipping
*

	INCLUDE	"e:\includes\amiga\hardware\custom.i"

	SECTION	Code

_polydemo	lea	$dff000,a0

	move.w	#%0101001000000000,bplcon0(a0)	setup display registers
	move.w	#0,bplcon1(a0)
	move.w	#0,bpl1mod(a0)
	move.w	#0,bpl2mod(a0)
	move.w	#$0038,ddfstrt(a0)
	move.w	#$00d0,ddfstop(a0)
	move.w	#$2c81,diwstrt(a0)
	move.w	#$f4c1,diwstop(a0)

	lea	copperlist,a1	Put bitplane addresses in copperlist
	move.l	#bitplanes,d0
	moveq	#5-1,d1
bpl_loop	move.w	d0,6(a1)	low part of bitplane address
	swap	d0
	move.w	d0,2(a1)	high part of bitplane address
	swap	d0
	add.l	#8000,d0	address of next bitplane
	lea	8(a1),a1	next copper instruction
	dbra	d1,bpl_loop

	move.l	#copperlist,cop1lc(a0)	start copperlist
	move.w	copjmp1(a0),d0

	lea	color(a0),a1	setup random colour palette
	move.w	#0,(a1)+
	moveq	#32-2,d0
palette_loop	bsr	random
	and.w	#$fff,d7
	move.w	d7,(a1)+
	dbra	d0,palette_loop

	move.w	#%0000000000100000,dmacon(a0)	disable sprite dma
	move.w	#%1000001110000000,dmacon(a0)	enable bpls/copper dma
*
polygonloop	bsr	random	generate a random triangle
	and.w	#$1ff,d7
	move.w	d7,d0	x1
	bsr	random
	and.w	#$1ff,d7
	move.w	d7,d1	y1
	move.w	d0,d2
	move.w	d1,d3
	move.w	d0,d4
	move.w	d1,d5
	bsr	random
	and.w	#%1111111,d7
	add.w	d7,d2	x2
	bsr	random
	and.w	#%1111111,d7
	sub.w	d7,d3	y2
	bsr	random
	and.w	#%1111111,d7
	sub.w	d7,d4	x2
	bsr	random
	and.w	#%1111111,d7
	sub.w	d7,d5	y2
	movem.w	d0-d5,_polydata

	move.w	#3,d7	number of vertices
	bsr	_polyclip
	bne.s	nextpolygon

	bsr	random
	and.w	#$f,d7
	move.w	d7,a5	colour
	move.w	#3,d7	number of vertices
	bsr	_polyfill
nextpolygon	bra	polygonloop	continue forever

*
****************************************************************************
*	POLYCLIP.S	Polynomial clip routine
****************************************************************************
*	On entry	d7.w = number of vertices
****************************************************************************
*	On exit	zero flag set = fill area visible & clipped
*		zero flag clear = fill area not visible
****************************************************************************
*	d0-d7	a1-a4 used
****************************************************************************

*	register usage

*	d0/d1	coords of current vertex
*	d2/d3	coords of previous vertex
*	d4/d5	acumulators
*	d6	new vertex counter
*	d7	vertex counter
*	a0	original vertex list ptr (unchanged)
*	a1	ptr to old vertex list
*	a2	ptr to new vertex list
*	a3	copy of start of new list
*	a4	window extent coord

horiz_cross	MACRO
	move.w	d2,d4          copy of x1
	move.w	a4,d5          copy of yval
	sub.w	d3,d5          (yval-y1)
	sub.w	d0,d2          (x1-x2)
	muls	d5,d2
	sub.w	d1,d3          (y1-y2)
	divs	d3,d2
	add.w	d4,d2          new x
*	-------------------------------------------------------------
	move.w	d2,(a2)+
	move.w	a4,(a2)+
	addq.w	#1,d6
	ENDM

vert_cross	MACRO
	move.w	d3,d4          copy of y1
	move.w	a4,d5          copy of xval
	sub.w	d2,d5          (xval-x1)
	sub.w	d1,d3          (y1-y2)
	muls	d5,d3
	sub.w	d0,d2          (x1-x2)
	divs	d2,d3
	add.w	d4,d3          new y
*	-------------------------------------------------------------
	move.w	a4,(a2)+
	move.w	d3,(a2)+
	addq.w	#1,d6
	ENDM

*
cliploops	MACRO
	movem.w	-4(a3),d2-d3	previous x coord/y coord
	cmp.w	a4,d\5
	b\1.s	.outsideloop\@
	bra.s	.insideloop\@
*---------------------------------------------------------------------------
.crosstoin\@	beq.s	.startinside\@	vertex on boundary
	\3
*	-------------------------------------------------------------
	bra.s	.startinside\@
*	-------------------------------------------------------------
.insideloop\@	movem.w	(a1)+,d0-d1    x coord/y coord
	cmp.w	a4,d\4
	b\1.s	.crosstoout\@
.startinside\@	move.w	d0,(a2)+
	move.w	d1,(a2)+
	addq.w	#1,d6
	move.w	d0,d2
	move.w	d1,d3
	dbra	d7,.insideloop\@
*	-------------------------------------------------------------
	bra.s	.nonetest\@
*---------------------------------------------------------------------------
.crosstoout\@	cmp.w	a4,d\5
	beq.s	.startoutside\@
	\3
*	-------------------------------------------------------------
	bra.s	.startoutside\@
*	-------------------------------------------------------------
.outsideloop\@	movem.w	(a1)+,d0-d1    x coord/y coord
	cmp.w	a4,d\4
	b\2.s	.crosstoin\@
.startoutside\@ move.w	d0,d2
	move.w	d1,d3
	dbra	d7,.outsideloop\@
*	-------------------------------------------------------------
.nonetest\@	tst.w	d6
	beq	.offscreen
	ENDM
*
*	Handle top of screen
_polyclip	lea	_polydata(pc),a1  start of old list
	move.l	a1,a2
	move.w	d7,d0
	lsl.w	#2,d0
	add.w	d0,a2          start of new list
	move.l	a2,a3          copy of start of new list
	subq.w	#1,d7          decrement for dbcc
	clr.w	d6             new vertex count
	move.w	#398,a4        y max
*	-------------------------------------------------------------
	cliploops	gt,le,horiz_cross,1,3
*---------------------------------------------------------------------------
*	Handle bottom of screen
.lab1	move.w	d6,d7
	move.l	a3,a1          start of old list
	move.l	a2,a3          copy of start of new list
	subq.w	#1,d7          decrement for dbcc
	clr.w	d6             new vertex count
	move.w	#0,a4          y min
*	-------------------------------------------------------------
	cliploops	lt,ge,horiz_cross,1,3
*---------------------------------------------------------------------------
*	Handle left of screen
.lab2	move.w	d6,d7
	move.l	a3,a1          start of old list
	move.l	a2,a3          copy of start of new list
	subq.w	#1,d7          decrement for dbcc
	clr.w	d6             new vertex count
	move.w	#0,a4           x min
*	-------------------------------------------------------------
	cliploops	lt,ge,vert_cross,0,2
*---------------------------------------------------------------------------
*	Handle right of screen
.lab3	move.w	d6,d7
	move.l	a3,a1          start of old list
	move.l	a2,a3          end of old list
	lea	_polydata,a2    start of new list
	subq.w	#1,d7          decrement for dbcc
	clr.w	d6             new vertex count
	move.w	#638,a4         x max
*	-------------------------------------------------------------
	cliploops	gt,le,vert_cross,0,2
*---------------------------------------------------------------------------
.clipdone	move.w	d6,d7          updated number of vertices
	clr.w	d0             set zero flag
	rts
*---------------------------------------------------------------------------
.offscreen	moveq	#1,d0         clear zero flag
	rts


*
****************************************************************************
*	POLYFILL.S	Optimised polynomial fill routine
****************************************************************************
*	On entry	a5 = colour number
*		d7.w = number of vertices in list
****************************************************************************
*	Uses all registers
****************************************************************************

maxpolyorder	EQU	30

_polyfill	lea	_polydata(pc),a0
	move.l	a0,a1
	move.w	d7,d6
	subq.w	#1,d6
	lsl.w	#2,d7          number of verts*4
	add.w	d7,a1
	move.w	#$8000,d1      largest y coord storage (top)
	move.w	#$7fff,d2      smallest y coord storage (bot)
*---------------------------------------------------------------------------
loop	move.l	-(a1),d5       x,y coords of vertex
*	-------------------------------------------------------------
isitlarger	cmp.w	d5,d1          compare y coords
	bge.s	isitsmaller
newhighy	move.w	d6,a4          new top vertex
	move.l	d5,d1          store new largest x/y coords
*	-------------------------------------------------------------
isitsmaller	cmp.w	d5,d2          compare y coords
	blt.s	next
	move.w	d5,d2          new smallest y coord
*---------------------------------------------------------------------------
next	dbra	d6,loop


	move.l	d1,startx      store top left x,y coords
shift1	asr.w	#1,d2          divide by 2 for low res

*	At this point:
*		a4.w = top vertex index
*		d2.w = smallest y coord (bottom)
*
chgpoints	MACRO
	move.w	a4,d6          first vertex number
	lsl.w	#2,d6          longword index
	movem.w	0(a0,d6.w),d4-d5  x,y coords of first vertex
shift2\@	asr.w	#1,d4          divide by 2 if low res
shift3\@	asr.w	#1,d5
	bra.s	nextvertex\@   is poly a line
	IF	\1=0
loop\@	subq.w	#4,d6
	bpl.s	over\@
	add.w	d7,d6
	ENDIF
	IF	\1<>0
loop\@	addq.w	#4,d6
	cmp.w	d7,d6          end of list ?
	blt.s	over\@
	clr.w	d6             move to start of list
	ENDIF
*	-------------------------------------------------------------
over\@	move.w	d5,(a1)+       store start y coord
	move.w	d4,d0
	move.w	d5,d1
	movem.w	0(a0,d6.w),d4-d5  x,y coords of next vertex
shift4\@	asr.w	#1,d4          divide by 2 if low res
shift5\@	asr.w	#1,d5
	sub.w	d4,d0          x2-x1
	sub.w	d5,d1          y2-y1
*	-------------------------------------------------------------
	bne	divide\@
	swap	d0
	clr.w	d0
	move.l	d0,(a1)+
	bra.s	nextvertex\@
*	-------------------------------------------------------------
divide\@	ext.l	d0
	divs	d1,d0
	move.w	d0,d3          units part
	clr.w	d0
	asr.l	#1,d0
	divs	d1,d0          fractional part
	swap	d3
	clr.w	d3
	ext.l	d0
	asl.l	#1,d0
	add.l	d0,d3          result in 32 bits
	move.l	d3,(a1)+       store gradient
*	-------------------------------------------------------------
nextvertex\@	cmp.w	d5,d2          was this the last line ?
	bne	loop\@         if not, continue
	move.w	d5,(a1)        store last y coord
	move.w	#$8000,6(a1)   endmarker
	ENDM

	lea	leftdata(pc),a1
	chgpoints	0
	lea	rightdata(pc),a1
	chgpoints	1
*
	lea	filldata(pc),a2
	lea	leftdata(pc),a3
	lea	rightdata(pc),a4
	move.w	(a3),d0        current line
	addq.l	#6,a3
	addq.l	#6,a4
*---------------------------------------------------------------------------
polyloop	move.w	(a3),d1
	move.w	(a4),d2
	cmp.w	d1,d2
	blt.s	leftbigger
	bgt.s	rightbigger
	cmp.w	#$8000,d1
	beq.s	finished
	bra.s	equal
*---------------------------------------------------------------------------
leftbigger	sub.w	d1,d0
	move.w	d0,(a2)+       store number of lines
	beq.s	leftzero
	move.w	d1,d0          new current line
	move.l	-4(a3),(a2)+   store gradients
	move.l	-4(a4),(a2)+
	addq.l	#6,a3
	bra.s	polyloop
*	-------------------------------------------------------------
leftzero	move.w	d1,d0          new current line
	move.l	-4(a3),(a2)+
	clr.l	(a2)+          zero right gradient
	addq.l	#6,a3
	bra.s	polyloop
*---------------------------------------------------------------------------
rightbigger	sub.w	d2,d0
	move.w	d0,(a2)+       store number of lines
	beq.s	rightzero
	move.w	d2,d0          new current line
	move.l	-4(a3),(a2)+   store gradients
	move.l	-4(a4),(a2)+
	addq.l	#6,a4
	bra.s	polyloop
*	-------------------------------------------------------------
rightzero	move.w	d2,d0          new current line
	clr.l	(a2)+          zero left gradient
	move.l	-4(a4),(a2)+
	addq.l	#6,a4
	bra.s	polyloop
*---------------------------------------------------------------------------
equal	sub.w	d1,d0
	move.w	d0,(a2)+       store number of lines
	move.w	d1,d0
	move.l	-4(a3),(a2)+   store gradients
	move.l	-4(a4),(a2)+
	addq.l	#6,a3
	addq.l	#6,a4
	bra.s	polyloop
*---------------------------------------------------------------------------
finished	move.w	#-1,(a2)+      endmarker

*
changesize	MACRO
changeleft\@	swap	d0
	add.l	d3,d0
	bpl.s	leftplus\@
*	-------------------------------------------------------------
leftminus\@	addq.w	#2,a6          move origin right
	subq.w	#1,d2          decrement no. of middle words
	add.l	#16<<16,d0
	bmi.s	leftminus\@
	swap	d0
	bra.s	changeright\@
*	-------------------------------------------------------------
leftplus\@	swap	d0
	cmp.w	#15,d0
	ble.s	changeright\@
*	-------------------------------------------------------------
leftgreater\@	ror.w	#4,d0
	move.b	d0,d5          number of whole words
	clr.b	d0
	rol.w	#4,d0
	ext.w	d5
	add.w	d5,d2          increment no of middle words
shift6\@	asl.w	#1,d5          number of bytes
	sub.w	d5,a6          move origin to left
*	-------------------------------------------------------------
changeright\@	swap	d1
	add.l	d4,d1
	bpl.s	rightplus\@
*	-------------------------------------------------------------
rightminus\@	addq.w	#1,d2          increment no. of middle words
	add.l	#16<<16,d1
	bmi.s	rightminus\@
	swap	d1
	bra.s	out\@
*	-------------------------------------------------------------
rightplus\@	swap	d1
	cmp.w	#15,d1
	ble.s	out\@
*	-------------------------------------------------------------
rightgreater\@ ror.w	#4,d1
	move.b	d1,d5
	clr.b	d1
	rol.w	#4,d1
	ext.w	d5
	sub.w	d5,d2          decrement no of middle words
out\@
	ENDM

*
fill_poly	move.w	#0,d0	x origin
	move.w	#398,d1	y origin
	lea	bitplanes,a6	bpls address
	movem.w	startx(pc),d2-d3
*              ----------------------------------------------------n--------
	add.w	a5,a5
	add.l	#branch_table,a5
	move.w	(a5),lineloop+2  modify fill line branch
*	-------------------------------------------------------------
	asr.w	#1,d0
	asr.w	#1,d1
	asr.w	#1,d2
	asr.w	#1,d3
	add.w	d2,d0
	sub.w	d3,d1
	mulu	#40,d1        start byte of required row
	add.l	d1,a6
	ext.l	d0
	ror.l	#4,d0          start word number
	asl.w	#1,d0          byte number
*              -------------------------------------------------------------
	add.w	d0,a6
	clr.w	d0
	rol.l	#4,d0          start bit (counted from left)
	neg.w	d0
	add.w	#15,d0	conventional bit number
	move.w	d0,d1          last bit number (........)
	moveq	#-1,d2         number of words in middle
*	-------------------------------------------------------------
startfill	lea	lefttable(pc),a4
	lea	righttable(pc),a3
	lea	filldata(pc),a0
*---------------------------------------------------------------------------
sectionloop	move.w	(a0)+,d7       number of lines
	bmi	return
	beq	zero
	movem.l	(a0)+,d3-d4    get gradients
	bra	startofloop
*	-------------------------------------------------------------
lineloop	bra	low_fill0
returnpoint	changesize
startofloop	dbra	d7,lineloop
*	-------------------------------------------------------------
	bra	sectionloop
*---------------------------------------------------------------------------
zero	movem.l	(a0)+,d3-d4    get gradients
	changesize
	bra	sectionloop
*---------------------------------------------------------------------------
return	rts	               endmarker reached
*
setup	MACRO	;bit1,bit2,bit3,bit4
mask0	SET	5
mask1	SET	-1
total	SET	\1+\2+\3+\4
	IF	total<>0
	IF	total=4
mask1	SET	5
	ENDIF
	IF	total<>4
mask1	SET	6
	ENDIF
	ENDIF
	ENDM

putword	MACRO	;bit,offset
	IF	\1=0
	and.w	d\#mask0,\2(a1)
	ENDIF
	IF	\1<>0
	or.w	d\#mask1,\2(a1)
	ENDIF
	ENDM

inverse_mask	MACRO
	IF	mask1=5
	not.w	d5
	ENDIF
	IF	mask1=6
	move.w	d5,d6
	not.w	d6
	ENDIF
	ENDM

*
low_fillline	MACRO	;bit1,bit2,bit3,bit4
	setup	\1,\2,\3,\4
	cmp.w	#-1,d2
	bgt.s	diffword\@
	beq.s	sameword\@
	add.w	#40,a6
	bra	returnpoint
*	-------------------------------------------------------------
sameword\@	move.l	a6,a1          faster than using d(a1) later
	asl.w	#1,d0
	move.w	0(a4,d0.w),d5  left fill mask
	asr.w	#1,d0
	asl.w	#1,d1
	or.w	0(a3,d1.w),d5  right fill mask
	asr.w	#1,d1
	inverse_mask
	putword	\1,0
	putword	\2,8000
	putword	\3,8000*2
	putword	\4,8000*3
	add.w	#40,a6
	bra	returnpoint
*	-------------------------------------------------------------
diffword\@	move.l	a6,a1
	asl.w	#1,d0
	move.w	0(a4,d0.w),d5  left fill mask
	asr.w	#1,d0
	inverse_mask
	putword	\1,0
	putword	\2,8000
	putword	\3,8000*2
	putword	\4,8000*3
	addq.l	#2,a1
	asl.w	#1,d2          bytes
	add.w	d2,a1          move to right word
	asr.w	#1,d2          restore
	asl.w	#1,d1
	move.w	0(a3,d1.w),d5  right fill mask
	asr.w	#1,d1
	inverse_mask
	putword	\1,0
	putword	\2,8000
	putword	\3,8000*2
	putword	\4,8000*3
*              -------------------------------------------------------------
	move.w	d2,d5
	swap	d2
	move.w	d5,d2          replicate into low word
	move.l	#-1*\1,d5	setup colour
	move.l	#-1*\2,d6
	move.l	#-1*\3,a2
	move.l	#-1*\4,a5
	bclr.l	#0,d2	an odd word ?
	beq.s	longwords\@	no
	move.w	d5,-(a1)	colour odd word
	move.w	d6,8000(a1)
	move.w	a2,8000*2(a1)
	move.w	a5,8000*3(a1)
*
longwords\@	neg.w	d2
	asl.w	#3,d2
	add.w	#18*8,d2
	jmp	here\@(pc,d2.w)
here\@	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
	move.l	d5,-(a1)
	nop		make last instr. 2 words long
	move.l	d6,8000(a1)
	move.l	a2,8000*2(a1)
	move.l	a5,8000*3(a1)
*              -------------------------------------------------------------
	swap	d2             restore number of middle words
	add.w	#40,a6
	bra	returnpoint
	ENDM
*
low_fill0	low_fillline   0,0,0,0
low_fill1	low_fillline   1,0,0,0
low_fill2	low_fillline   0,1,0,0
low_fill3	low_fillline   1,1,0,0
low_fill4	low_fillline   0,0,1,0
low_fill5	low_fillline   1,0,1,0
low_fill6	low_fillline   0,1,1,0
low_fill7	low_fillline   1,1,1,0
low_fill8	low_fillline   0,0,0,1
low_fill9	low_fillline   1,0,0,1
low_fill10	low_fillline   0,1,0,1
low_fill11	low_fillline   1,1,0,1
low_fill12	low_fillline   0,0,1,1
low_fill13	low_fillline   1,0,1,1
low_fill14	low_fillline   0,1,1,1
low_fill15	low_fillline   1,1,1,1


branch_table	DC.W	low_fill0-(lineloop+2)
	DC.W	low_fill1-(lineloop+2)
	DC.W	low_fill2-(lineloop+2)
	DC.W	low_fill3-(lineloop+2)
	DC.W	low_fill4-(lineloop+2)
	DC.W	low_fill5-(lineloop+2)
	DC.W	low_fill6-(lineloop+2)
	DC.W	low_fill7-(lineloop+2)
	DC.W	low_fill8-(lineloop+2)
	DC.W	low_fill9-(lineloop+2)
	DC.W	low_fill10-(lineloop+2)
	DC.W	low_fill11-(lineloop+2)
	DC.W	low_fill12-(lineloop+2)
	DC.W	low_fill13-(lineloop+2)
	DC.W	low_fill14-(lineloop+2)
	DC.W	low_fill15-(lineloop+2)

*
lefttable	DC.W	%1111111111111110
	DC.W	%1111111111111100
	DC.W	%1111111111111000
	DC.W	%1111111111110000
	DC.W	%1111111111100000
	DC.W	%1111111111000000
	DC.W	%1111111110000000
	DC.W	%1111111100000000
	DC.W	%1111111000000000
	DC.W	%1111110000000000
	DC.W	%1111100000000000
	DC.W	%1111000000000000
	DC.W	%1110000000000000
	DC.W	%1100000000000000
	DC.W	%1000000000000000
	DC.W	%0000000000000000

righttable	DC.W	%0000000000000000
	DC.W	%0000000000000001
	DC.W	%0000000000000011
	DC.W	%0000000000000111
	DC.W	%0000000000001111
	DC.W	%0000000000011111
	DC.W	%0000000000111111
	DC.W	%0000000001111111
	DC.W	%0000000011111111
	DC.W	%0000000111111111
	DC.W	%0000001111111111
	DC.W	%0000011111111111
	DC.W	%0000111111111111
	DC.W	%0001111111111111
	DC.W	%0011111111111111
	DC.W	%0111111111111111

startx	DS.W	1
starty	DS.W	1

_polydata	DS.W	maxpolyorder*2*2*3
leftdata	DS.B	(2+4)*maxpolyorder
rightdata	DS.B	(2+4)*maxpolyorder
filldata	DS.B	(2+4+4)*maxpolyorder


random	move.w	seed,d7
	mulu	#125,d7
	divu	#65521,d7
	swap	d7
	move.w	d7,seed
	rts

seed	DC.W	1001
*
	SECTION	Data_c

cmove	MACRO	;address,data
	DC.W	(\1)&$fffe,(\2)
	ENDM

cend	MACRO
	DC.W	$ffff,$fffe
	ENDM

copperlist	cmove	bplpt,0
	cmove	bplpt+2,0
	cmove	bplpt+4,0
	cmove	bplpt+6,0
	cmove	bplpt+8,0
	cmove	bplpt+10,0
	cmove	bplpt+12,0
	cmove	bplpt+14,0
	cmove	bplpt+16,0
	cmove	bplpt+18,0
	cend

	SECTION	Bss_c

bitplanes	DS.B	8000*5

	END
