Date sent:        Wed, 29 Oct 1997 22:37:51 +0200 (EET)
From:             Harry Sintonen <sintonen@jyu.fi>
To:               amycoders@ibm.net
Subject:          speedopt entry to #amycoders triangledrawing compo (fwd)

*********************************************************************
*
* Your init code comes here.
*
*********************************************************************

_initcode
a
b
	rts
	
*********************************************************************
*
* Your line routine.
* Every time you are given: A0.L : Chunky Screen (256x256x8)
*
* D0.l  color
* A1    {x1,y1,x2,y2,x3,y3}.w
*
* other registers are in undefined state !!
* you may trash all regs except a7
*
*********************************************************************

	CNOP	0,8
_triangle
c

;****************************************************************************
;**
;*       Speed-optimized chunky triangledraw routine
;*
;*  This is one of my contributions to #amycoders triangledrawing-compo. This
;*  routine will participate speed-optimizing competition. This code works
;*  with MC68020+ processors with any cache setup.
;*
;*  This code benefits from copyback cache so turn it on.
;*
;*  Code size without rts: max. 582 bytes.
;*  Average time (dec): damn-it's-fast
;*
;*  Coded by Harry "Piru" Sintonen <sintonen@jyu.fi>.
;*  This code is copyright © 1997 by Harry Sintonen, and was written 26th-
;*  28th october 1997.
;*
;****************************************************************************
;*

; variables
T_SWIDTH	EQU	256		Screen width

; flags
T_ALLOWLINE	SET	0		Allow triangles that are lines
T_SMALLMODE	SET	0		Optimize for small triangles
T_4PIXWRITE	SET	0		Write 4 pixels at a time instead of 8
T_SPECIALBFLAT	SET	1		Have sep routine for flat bottom tris
T_0YDELTACHECK	SET	0		Have check for 1y=3y (ydelta=0)

; following is my quick "nop" longword align macro ;)
mcnop4tempb	; this must be longword aligned!
mcnop4	MACRO
mcnop4temps	SET	(*-mcnop4tempb)&2
	IFGT	(mcnop4temps)
	or.l	d0,d0
	ENDC
	ENDM

;  IN: d0.l=color
;      a0=chunky buffer (256x256x8)
;      a1={x1,y1,x2,y2,x3,y3}.w
; OUT: d0-d7/a0-a4 trashed

	IFEQ	T_SMALLMODE
	move.l	d0,d4		000c
	ENDC
	movem.l	(a1),d1-d3	d1=1x1y, d2=2x2y, d3=3x3y
	IFEQ	T_SMALLMODE
	lsl.l	#8,d0		00c0
	ENDC
	cmp.w	d1,d2
	bhi.b	.ns1
	exg	d1,d2
.ns1
	IFEQ	T_SMALLMODE
	or.b	d4,d0		00cc
	ENDC
	cmp.w	d1,d3
	bhi.b	.ns2
	exg	d1,d3
.ns2
	IFEQ	T_SMALLMODE
	move.l	d0,d4		00cc
	ENDC
	cmp.w	d2,d3
	bhi.b	.ns3
	exg	d2,d3
.ns3
	IFEQ	T_SMALLMODE
	swap	d0		cc00
	move.w	d4,d0		cccc
	ENDC

	IFNE	T_0YDELTACHECK
	cmp.w	d1,d3		1y=3y? (check for 0 ydelta)
	beq	.done1
	ENDC

	; d1=uppermost corner, d2=middle corner, d3=lowermost corner

	cmp.w	d1,d2		1y=2y -> top flat triangle
	beq	.top_flat

	; add position of corner 1 to chunky buffer start.

	IFEQ	T_SWIDTH-320
	; oh dear, this will be slower than mulu.w #T_SWIDTH
	; thing on 060. Should be faster on 040 tho... :)
	move.l	d1,d4
	swap	d1		001x
	ext.l	d4		0000001y
	move.l	d4,d5
	lsl.l	#8,d4		1<<8=256
	lsl.l	#6,d5		1<<6=64
	add.l	d5,d4
	or.w	d1,d4		1y*320!1x
	swap	d1
	ELSE
	IFEQ	T_SWIDTH-256
	move.l	d1,d4		001x001y
	swap	d4		001y001x
	lsl.w	#8,d4		001y1x00
	lsr.l	#8,d4		00001y1x
	ELSE
	move.w	d1,d4		001y
	swap	d1
	mulu.w	#T_SWIDTH,d4
	or.w	d1,d4		+001x
	swap	d1
	ENDC
	ENDC
	add.l	d4,a0		a0=chunky+1y*T_SWIDTH+1x

	IFNE	T_SPECIALBFLAT
	cmp.w	d2,d3		2y=3y -> bottom flat triangle
	beq	.bottom_flat
	ENDC

	; determine on which side middle (2) corner is.

	move.l	d3,d5		NOTE: 3y>1y !!
	move.w	d2,d4
	sub.l	d1,d5
	sub.w	d1,d4		d4.w=(2y-1y)
	swap	d5		d5.w=(3x-1x)
	muls.w	d5,d4		d4.l=(2y-1y)*(3x-1x)
	move.w	d3,d5
	sub.w	d1,d5		d5.l=(3y-1y)
	divs.w	d5,d4		d4.l=(2y-1y)*(3x-1x)/(3y-1y) (4x-1x)
	move.l	d1,d5
	move.l	d2,d6
	swap	d5
	swap	d6
	add.w	d4,d5		d5.w=4x=(2y/1y)*(3x-1x)/(3y-1y)+1x
	cmp.w	d6,d5		4x>2x
	blo	.middle_on_right
	IFNE	T_ALLOWLINE
	bne	.noladd
	sub.l	#$10000,d2	if it's "line" triangle fix not to be one ;)
.noladd
	ENDC

	; middle on left
	;   1
	;   /\
	;  /  \
	;2·--._\
	;       3

	;r=fill width (dbf)	dr=(3x-1x)<<16/(3y-1y)-(2x-1x)<<16/(2y-1y)
	;l=offset in chunky	dl=(2x-1x)<<16/(2y-1y)

	move.l	d2,d7		NOTE: 2y>1y !!
	sub.l	d1,d7		(2x2y-1x1y)
	move.l	d7,d6
	ext.l	d7		(2y-1y)
	clr.w	d6		(2x-1x)<<16
	divs.l	d7,d6
	move.l	d6,a3		a3=dl

	move.l	d3,d7		NOTE: 3y>1y !!
	sub.l	d1,d7		(3x3y-1x1y)
	move.l	d7,d6
	ext.l	d7		(3y-1y)
	clr.w	d6		(3x-1x)<<16
	divs.l	d7,d6
	move.l	d6,a2
	sub.l	a3,a2		a2=dr (dr-dl)

	; calculate new left delta
	move.l	d3,d4		NOTE: 3y>2y !!
	sub.l	d2,d4		(3x3y-2x2y)
	move.l	d4,d5
	clr.w	d4		(3x-2x)<<16
	ext.l	d5		(3y-2y)
	IFEQ	T_SPECIALBFLAT
	beq.b	.nodiv1
	ENDC
	divs.l	d5,d4
.nodiv1	sub.w	d1,d2		d2=2y-1y
	move.l	d4,a4		a4=dl2
	sub.w	d1,d3		d3=3y-1y (NOTE: no subq.w #1,d3)

	move.l	#$8000,d6	d6=l
	move.l	d6,d7		d7=r

	mcnop4
.oloop1	swap	d6		ffffiiii
	move.l	d7,d4		iiiiffff
	lea	(a0,d6.w),a1
	swap	d4		ffffiiii
	swap	d6		iiiiffff
	IFEQ	T_SMALLMODE
	cmp.w	#8,d4
	blo.b	.bl1
	IFNE	T_4PIXWRITE
	subq.w	#4,d4
	ELSE
	subq.w	#8,d4
	ENDC
	move.w	d4,d5
	IFNE	T_4PIXWRITE
	and.w	#%11,d4
	lsr.w	#2,d5
	ELSE
	and.w	#%111,d4
	lsr.w	#3,d5
	ENDC
.iloop1
	IFEQ	T_4PIXWRITE
	move.l	d0,(a1)+
	ENDC
	move.l	d0,(a1)+
	dbf	d5,.iloop1
	ENDC
.bl1	move.b	d0,(a1)+
	dbf	d4,.bl1

	add.l	a3,d6		l=l+dl (iiiiffff)
	lea	(T_SWIDTH,a0),a0 move to next line

	add.l	a2,d7		r=r+dr (iiiiffff)

	subq.w	#1,d2		are we on middle corner y pos?
	dbeq	d3,.oloop1	nope, do more
	tst.w	d3
	bmi.b	.done1

	; set new left delta (will affect right delta too!)
	; (begin to move towards lowermost corner)
	;dl=(3x-2x)<<16/(3y-2y)

	add.l	a3,a2		a2=dr (orig!)
	move.l	a4,a3		dl=dl2
	sub.l	a4,a2		a2=dr (dr-dl2)

	dbf	d3,.oloop1	ok, do rest of triangle
.done1	rts


	CNOP	0,4
.middle_on_right

	;    1
	;    /\
	;   /  \
	;  /_.--·2
	; 3

	; middle on right
	;r=fill width (dbf)	dr=(2x-1x)<<16/(2y-1y)-(3x-1x)<<16/(3y-1y)
	;l=offset in chunky	dl=(3x-1x)<<16/(3y-1y)

	move.l	d3,d7		NOTE: 3y>1y !!
	sub.l	d1,d7		(3x3y-1x1y)
	move.l	d7,d6
	ext.l	d7		(3y-1y)
	clr.w	d6		(3x-1x)<<16
	divs.l	d7,d6
	move.l	d6,a2		a2=dl

	move.l	d2,d7		NOTE: 2y>1y !!
	sub.l	d1,d7		(2x2y-1x1y)
	move.l	d7,d6
	ext.l	d7		(2y-1y)
	clr.w	d6		(2x-1x)<<16
	divs.l	d7,d6
	move.l	d6,a3
	sub.l	a2,a3		a3=dr (dr-dl)

	; calculate new right delta
	move.l	d3,d4		NOTE: 3y>2y !!
	sub.l	d2,d4		(3x3y-2x2y)
	move.l	d4,d5
	clr.w	d4		(3x-2x)<<16
	ext.l	d5		(3y-2y)
	IFEQ	T_SPECIALBFLAT
	beq.b	.nodiv2	
	ENDC
	divs.l	d5,d4
.nodiv2	move.l	d4,a4
	sub.w	d1,d2		d2=2y-1y
	sub.l	a2,a4		a4=dr2 (dr2-dl)
	sub.w	d1,d3		d3=3y-1y (NOTE: no subq.w #1,d3)

	move.l	#$8000,d6	d6=l
	move.l	d6,d7		d7=r

	mcnop4
.oloop2	swap	d6		ffffiiii
	move.l	d7,d4		iiiiffff
	lea	(a0,d6.w),a1
	swap	d4		ffffiiii
	swap	d6		iiiiffff
	IFEQ	T_SMALLMODE
	cmp.w	#8,d4
	blo.b	.bl2
	IFNE	T_4PIXWRITE
	subq.w	#4,d4
	ELSE
	subq.w	#8,d4
	ENDC
	move.w	d4,d5
	IFNE	T_4PIXWRITE
	and.w	#%11,d4
	lsr.w	#2,d5
	ELSE
	and.w	#%111,d4
	lsr.w	#3,d5
	ENDC
.iloop2
	IFEQ	T_4PIXWRITE
	move.l	d0,(a1)+
	ENDC
	move.l	d0,(a1)+
	dbf	d5,.iloop2
	ENDC
.bl2	move.b	d0,(a1)+
	dbf	d4,.bl2

	add.l	a2,d6		l=l+dl (iiiiffff)
	lea	(T_SWIDTH,a0),a0 move to next line

	add.l	a3,d7		r=r+dr (iiiiffff)

	subq.w	#1,d2		are we on middle corner y pos?
	dbeq	d3,.oloop2	nope, do more
	tst.w	d3
	bmi.b	.done2

	; set new right delta
	; (begin to move towards lowermost corner)
	;dr=(3x-2x)<<16/(3y-2y)

	move.l	a4,a3		dr=dr2

	dbf	d3,.oloop2	ok, do rest of triangle
.done2	rts


	CNOP	0,4
.top_flat
	;1·----·2  (or 2 1)
	;  \  /
	;   \/
	;    3

	cmp.l	d1,d2
	bhi.b	.nxs1
	exg	d1,d2
.nxs1
	; add position of corner 1 to chunky buffer start.

	IFEQ	T_SWIDTH-320
	; oh dear, this will be slower than mulu.w #T_SWIDTH
	; thing on 060. Should be faster on 040 tho... :)
	move.l	d1,d4
	swap	d1		001x
	ext.l	d4		0000001y
	move.l	d4,d5
	lsl.l	#8,d4		1<<8=256
	lsl.l	#6,d5		1<<6=64
	add.l	d5,d4
	or.w	d1,d4		1y*320!1x
	swap	d1
	ELSE
	IFEQ	T_SWIDTH-256
	move.l	d1,d4		001x001y
	swap	d4		001y001x
	lsl.w	#8,d4		001y1x00
	lsr.l	#8,d4		00001y1x
	ELSE
	move.w	d1,d4		001y
	swap	d1
	mulu.w	#T_SWIDTH,d4
	or.w	d1,d4		+001x
	swap	d1
	ENDC
	ENDC
	add.l	d4,a0		a0=chunky+1y*T_SWIDTH+1x

	;r=fill width (dbf)	dr=(3x-2x)<<16/(3y-2y)-(2x-1x)<<16/(3y-1y)
	;l=offset in chunky	dl=(3x-1x)<<16/(3y-1y)

	move.l	d3,d6		NOTE: 3y>1y !!
	sub.l	d1,d6		(3x3y-1x1y)
	move.l	d6,d7
	ext.l	d6		(3y-1y)
	clr.w	d7		(3x-1x)<<16
	divs.l	d6,d7
	move.l	d7,a2		a2=dl

	move.l	d2,d7
	sub.l	d1,d7
	sub.w	d3,d1		d3=3y-1y
	neg.w	d1		NOTE: no subq.w #1,d1

	sub.l	d2,d3		NOTE: 3y>2y !!
	clr.w	d3		(3x-2x)<<16
	neg.l	d3
	divs.l	d6,d3
	add.l	a2,d3

	move.l	#$8000,d6	d6=l
	move.w	d6,d7		d7=r (2x-1x)<<16!$8000

	mcnop4
.oloop3	swap	d6		ffffiiii
	move.l	d7,d4		iiiiffff
	lea	(a0,d6.w),a1
	swap	d4		ffffiiii
	swap	d6		iiiiffff
	IFEQ	T_SMALLMODE
	cmp.w	#8,d4
	blo.b	.bl3
	IFNE	T_4PIXWRITE
	subq.w	#4,d4
	ELSE
	subq.w	#8,d4
	ENDC
	move.w	d4,d5
	IFNE	T_4PIXWRITE
	and.w	#%11,d4
	lsr.w	#2,d5
	ELSE
	and.w	#%111,d4
	lsr.w	#3,d5
	ENDC
.iloop3
	IFEQ	T_4PIXWRITE
	move.l	d0,(a1)+
	ENDC
	move.l	d0,(a1)+
	dbf	d5,.iloop3
	ENDC
.bl3	move.b	d0,(a1)+
	dbf	d4,.bl3

	add.l	a2,d6		l=l+dl (iiiiffff)
	lea	(T_SWIDTH,a0),a0 move to next line

	sub.l	d3,d7		r=r+dr (iiiiffff)

	dbf	d1,.oloop3

	IFNE	T_SPECIALBFLAT
	rts


	CNOP	0,4
.bottom_flat
	;    1
	;   /\
	;  /  \
	;2·----· 3  (or 3 2)

	cmp.l	d2,d3
	bhi.b	.nxs2
	exg	d2,d3
.nxs2
	;r=fill width (dbf)	dr=(3x-1x)<<16/(2y-1y)-(2x-1x)<<16/(2y-1y)
	;l=offset in chunky	dl=(2x-1x)<<16/(2y-1y)

	move.l	d2,d7		NOTE: 2y>1y !!
	sub.l	d1,d7		(2x2y-1x1y)
	move.l	d7,d6
	ext.l	d7		(2y-1y)
	clr.w	d6		(2x-1x)<<16
	divs.l	d7,d6		d6=dl

	sub.l	d1,d3		NOTE: 3y>1y !!
	clr.w	d3		(3x-1x)<<16
	divs.l	d7,d3
	sub.w	d1,d2		d2=2y-1y (NOTE: no subq.w #1,d2)
	sub.l	d6,d3		d3=dr (dr-dl)

	move.l	#$8000,d1	d1=l
	move.l	d1,d7		d7=r

	mcnop4
.oloop4	swap	d1		ffffiiii
	move.l	d7,d4		iiiiffff
	lea	(a0,d1.w),a1
	swap	d4		ffffiiii
	swap	d1		iiiiffff
	IFEQ	T_SMALLMODE
	cmp.w	#8,d4
	blo.b	.bl4
	IFNE	T_4PIXWRITE
	subq.w	#4,d4
	ELSE
	subq.w	#8,d4
	ENDC
	move.w	d4,d5
	IFNE	T_4PIXWRITE
	and.w	#%11,d4
	lsr.w	#2,d5
	ELSE
	and.w	#%111,d4
	lsr.w	#3,d5
	ENDC
.iloop4
	IFEQ	T_4PIXWRITE
	move.l	d0,(a1)+
	ENDC
	move.l	d0,(a1)+
	dbf	d5,.iloop4
	ENDC
.bl4	move.b	d0,(a1)+
	dbf	d4,.bl4

	add.l	d6,d1		l=l+dl (iiiiffff)
	lea	(T_SWIDTH,a0),a0 move to next line

	add.l	d3,d7		r=r+dr (iiiiffff)

	dbf	d2,.oloop4
	ENDC
d
	rts

;len	dc.l	((b-a)+(d-c))
