*****************************************************************************
*** Point in Polygon Routine	       (c) November 1991 by McDeal/D-TECT ***
*** Released in HACK-MAG Issue #7					  ***
*****************************************************************************

;With this routine you can test whether a point is within a convex polygon
;or not.

;This formula was used:    C = (x2-x1)*(y-y1)-(y2-y1)*(x-x1)
;when C<0, then the point P(x,y) is left of the line (x1,y1,x2,y2)
;when C>0, then the point P(x,y) is right of the line (x1,y1,x2,y2)

;The result of this formula is only correct if your coordinate origin is
;in the upper left corner of the screen. If it is in the lower left corner
;you have to interprete the result the other way round...

;IMPORTANT NOTE: I didn't optimize anything of this example because I was
;in a BIG hurry! And I think it is much easier for beginners to understand
;source codes which aren't optimized... You know...

;						signed: McDeal/D-TECT

;PS: GREEN means: Inside polygon.
;    RED means: Outside polygon.   Now start it!

;PPS: This is a Devpac Source Code!

***************************************************
*** Constants Definition			***
***************************************************

PlaneWidth	= 40
PlaneLen	= PlaneWidth*256
SpriteHigh      = 1
SpriteWidth     = 16

MouseClipX      = 320-SpriteWidth+1
MouseClipY      = 256-SpriteHigh-5

DL_MInterns	= $ca
SML		= 0

***************************************************
*** Program Start				***
***************************************************

		opt	o+

		section	a,code_c

Start:		lea	$dff000,a5

		bsr 	DrawPolygon
		bsr.s	InitInts
		bsr.s	InitSprite
		bsr.s	SetPlanePtr
		bsr	StartCopper
		bsr	Main
		bsr	StopCopper
		bsr.s	ReInitInts

		moveq	#0,d0
		rts

***************************************************
*** Init Interrupt				***
***************************************************

InitInts:	move.w	$1c(a5),d0		;Save INTENA
		bset	#15,d0
		move.w	d0,Interrupts
		move.w	#$3fff,$9a(a5)		;turn off all Ints (INTENA)
		move.l	$6c.w,Level3Int		;Save old Level 3 Int
		lea	MouseRoutine(pc),a0	;Set New Routine Ptr
		move.l	a0,$6c.w
		move.w	#$c020,$9a(a5)		;Permit Level 3 Int
		rts

Interrupts:	dc.w	0
Level3Int:	dc.l	0

***************************************************
*** ReInit Interrupts				***
***************************************************

ReInitInts:	move.w	#$3fff,$9a(a5)		;turn off all Ints (INTENA)
		move.l	Level3Int(pc),$6c.w	;set old Level3Int Ptr
		move.w	Interrupts(pc),$9a(a5)	;set old INTENA contents
		rts

***************************************************
*** Init Sprite					***
***************************************************

InitSprite:	move.l	#MouseSpr,d0		;Sprite Structure Ptr
		lea	MouseSprite(pc),a0	;NCList Ptr
		move.w	d0,6(a0)		;Set Ptr
		swap	d0
		move.w	d0,2(a0)
		rts

***************************************************
*** Set Plane Ptr in Copperlist			***
***************************************************

SetPlanePtr:	lea	PlanePtr(pc),a1
		move.l	#Plane,d0
		move.w	d0,6(a1)		;Low Word
		swap	d0
		move.w	d0,2(a1)		;High Word
		rts

***************************************************
*** Start/Stop Copper				***
***************************************************

StartCopper:	move.w	#$0380,$96(a5)
		move.l	#NCList,$84(a5)
		clr.w	$8a(a5)
		move.w	#$83a0,$96(a5)
		clr.w	$36(a5)			;Clear JOY0DAT
		rts

StopCopper:	move.w	#$0380,$96(a5)
		clr.w	$88(a5)
		move.w	#$8380,$96(a5)
		rts

***************************************************
*** Draw Polygon				***
***************************************************

DrawPolygon:	lea	$dff002,a6
		lea	Koords(pc),a2
		move.w	(a2)+,d7		;Number of Lines

.DrawLineLoop:	lea	Plane,a0
		moveq	#PlaneWidth,d4		;This shitty loop isn't
		moveq	#-1,d5			;optimized!!! Don't blame me!
		movem.w	(a2)+,d0-d3

.WB:		btst	#6,(a6)
		bne.s	.WB
		move.w	d5,$44-$02(a6)
		move.w	d5,$72-$02(a6)
		move.w	#$8000,$74-$02(a6)
		move.w	d4,$60-$02(a6)
		move.w	d4,$66-$02(a6)

		bsr.s	DrawLine
		dbf	d7,.DrawLineLoop
		rts

***************************************************
*** DrawLine					***
***************************************************

;Needs:
; a0    PlanePtr
; a6    $dff002
; d0/d1 x,y start pos
; d2/d3 x,y end   pos
; d4    Width of plane

;Kills:
; d0-d4/a0-a1 (+d5 in Fill Mode)

DrawLine:	cmp.w	d1,d3			;drawing only from top to bottom is
		bge.s	.y1ly2			;necessary for:
		exg	d0,d2			;a: up-down differences (same koords)
		exg	d1,d3			;b: blitter invert bit (only at top of line)

.y1ly2:		sub.w	d1,d3			;d3:yd

;here we could do an optimization with special shifts
;depending on the PlaneWidth value ... i know it, but please, let it be.

		mulu	d4,d1			;use muls for neg y-vals
		add.l	d1,a0			;please don't use add.w here!
		moveq	#0,d1			;d1:quant-counter
		sub.w	d0,d2			;d2:xd
		bge.s	.xdpos
		addq.w	#2,d1			;set bit 1 of quant-counter (here it could be a moveq)
		neg.w	d2
.xdpos:		moveq	#$f,d4			;d4 full cleaned (for later oktants move.b)
		and.w	d0,d4
		lsr.w	#3,d0			;yeah, on byte (necessary for bchg) ....
		add.w	d0,a0			;... blitter ands automagically
		ror.w	#4,d4			;4:shift
		or.w	#$b00+DL_MInterns,d4	;bltcon0-codes
		swap	d4
		cmp.w	d2,d3			;which delta is the biggest?
		bge.s	.dygdx
		addq.w	#1,d1			;set bit 0 of quant-counter
		exg	d2,d3			;exchange xd with yd
.dygdx:		add.w	d2,d2			;d2:xd*2
		move.w	d2,d0			;d0:save for $52(a6)
		sub.w	d3,d0			;d0:xd*2-yd
		addx.w	d1,d1			;Bit0:sign-bit
		move.b	.oktants(pc,d1.w),d4	;in low byte of d4 (upper byte cleaned above)
		swap	d2
		move.w	d0,d2
		sub.w	d3,d2			;d2:2*(xd-yd)
		moveq	#6,d1			;d1:shiftval(not necessary) + testval for the blitter
		lsl.w	d1,d3			;d3:BLTSIZE
		add.w	#$42,d3
		lea	$52-2(a6),a1		;a1:CUSTOM + $52

;WARNING:  if you use fastmem and an extreme DMA-Access (e.g.  6
;planes and copper), you should insert a tst.b (a6) here (for the
;shitty AGNUS-BUG).

.WB:		btst	d1,(a6)			;waiting for the blitter ...
		bne.s	.WB

		move.l	d4,$40-2(a6)		;writing to the blitter regs as fast as possible.
		move.l	d2,$62-2(a6)
		move.l	a0,$48-2(a6)
		move.w	d0,(a1)+
		move.l	a0,(a1)+		;shit-word buffer pt.
		move.w	d3,(a1)
		rts

; ------------- oktant-table --------------------------------------------

.Oktants:	dc.b	SML+1,SML+1+$40
		dc.b	SML+17,SML+17+$40
		dc.b	SML+9,SML+9+$40
		dc.b	SML+21,SML+21+$40

***************************************************
*** Main Loop					***
***************************************************

Main:		move.l	$04(a5),d0
		and.l	#$1ff00,d0
		cmp.l	#150*256,d0
		bne.s	Main

.Wait:		move.l	$04(a5),d0
		and.l	#$1ff00,d0
		cmp.l	#151*256,d0
		bne.s	.Wait

		bsr.s	TestMousePos		;This is the MAIN routine!

		btst	#6,$bfe001
		bne.s	Main

.WB:		btst	#6,2(a5)
		bne.s	.WB
		rts

***************************************************
*** Test Mouse Pos				***
***************************************************

TestMousePos:	lea	Koords(pc),a0		;Polygon Ptr
		movem.w	MousePos(pc),d4-d5	;X,Y Coord of Point
		bsr.s	PointInPolygon
		tst.w	d0			;Test Flag
		beq.s	.InPolygon		;if d0 = 0 -> inside!

.Beep:		move.w	#$f00,$dff180		;Point outside polygon
		rts

.InPolygon:	move.w	#$0f0,$dff180		;Point inside polygon
.Exit:		rts

***************************************************
*** Point in Polygon Routine			***
***************************************************

;a0 = Ptr on Polygon Coordinate Lis (Polygon Clockwise!)
;d4 = X-Coord of point
;d5 = Y-Coord of point
;-> d0 <> 0 when point outside; d0 = 0 when point inside

PointInPolygon:	move.w	(a0)+,d7		;Amount of polygon lines-1

.PolygonLoop:	movem.w	(a0)+,d0-d3		;Get Line Coords

		sub.w	d0,d2			;(x2-x1)
		move.w	d5,d6			;save y
		sub.w	d1,d6			;(y-y1)
		muls	d6,d2			;(y-y1)*(x2-x1)

		sub.w	d1,d3			;(y2-y1)
		move.w	d4,d6			;save x
		sub.w	d0,d6			;(x-x1)
		muls	d6,d3			;(y2-y1)*(x-x1)

		sub.l	d3,d2			;(y-y1)*(x2-x1)-(y2-y1)*(x-x1)
		bmi.s	.OutOfPolygon		;if neg-> outside

		dbf	d7,.PolygonLoop
		moveq	#0,d0			;set inside-flag
		rts

.OutOfPolygon:	moveq	#-1,d0			;set outside-flag
		rts

*** Polygon Structure ***

Koords:		dc.w	5-1			;Polygon with 5 lines
		dc.w	55,1,100,30		;1. lines
		dc.w	100,30,80,90		;2. lines
		dc.w	80,90,20,80		;3. lines
		dc.w	20,80,10,30		;4. lines
		dc.w	10,30,55,1		;5. lines

***************************************************
*** Level3Int (Mouse-Routine)			***
***************************************************

MouseRoutine:	movem.l	d0-d4/a0/a5,-(sp)

		lea	$dff000,a5
		btst	#5,$1e+1(a5)		;VBI ? (INTREQR+1)
		beq.s	.Exit			;no-> Exit

		move.w	#$0020,$9c(a5)		;Clear VBI Bit

		lea	MousePos(pc),a0
		move.w	(a0)+,d0
		move.w	(a0)+,d1
		move.w	$0a(a5),d2
		move.w	d2,d3
		sub.b	1(a0),d2
		move.b	d2,d4
		ror.w	#8,d2
		sub.b	(a0),d2
		move.w	d3,(a0)
		ext.w	d4
		add.w	d4,d0
		bgt.s	.Right
		moveq	#0,d0
		bra.s	.Up
.Right:		cmp.w	#MouseClipX,d0
		blt.s	.Up
		move.w	#MouseClipX,d0

.Up:		ext.w	d2
		add.w	d2,d1
		bgt.s	.Down
		moveq	#0,d1
		bra.s	.SetSpr
.Down:		cmp.w	#MouseClipY,d1
		blt.s	.SetSpr
		move.w	#MouseClipY,d1

;\
; >- Now set the Sprite 
;/

.SetSpr:	movem.w	d0-d1,-(a0)		;Set X,Y
		lea	MouseSpr(pc),a0		;Sprite Structure Ptr
		add.w	#128,d0
		add.w	#42,d1
		move.w	d1,d3
		addq.w	#SpriteHigh,d3
		moveq	#0,d4
		lsl.w	#8,d1
		addx.b	d4,d4
		lsl.w	#8,d3
		addx.b	d4,d4
		or.w	d4,d3
		lsr.w	#1,d0
		addx.b	d3,d3
		or.w	d0,d1
		move.w	d1,(a0)+
		move.w	d3,(a0)
.Exit:		movem.l	(sp)+,d0-d4/a0/a5
		rte

MousePos:	dc.w	0,0			; Don't change the order!
OldMove:	dc.w	0			;/

***************************************************
*** Datas					***
***************************************************

NCList:
MouseSprite:	dc.l	$01200000,$01220000,$01240000,$01260000
		dc.l	$01280000,$012a0000,$012c0000,$012e0000
		dc.l	$01300000,$01320000,$01340000,$01360000
		dc.l	$01380000,$013a0000,$013c0000,$013e0000

		dc.l	$008e2981,$009029c1,$00920038,$009400d0
		dc.l	$01020000,$01040000,$01080000,$010a0000
		dc.l	$01000200,$01a20ff0

PlanePtr:	dc.l	$00e00000,$00e20000
		dc.l	$01001200

		dc.l	$01800000,$018200ff
		dc.l	-2

MouseSpr:	dc.w	0,0
		dc.w	$8000,$0000
		dc.w	0,0

***************************************************
*** BSS Data Segment				***
***************************************************

		section	b,bss_c

Plane:		ds.b	PlaneLen

		END

