	incdir	"include:"

DEF_SENS	equ	100
DEF_ZONE	equ	4

setv	MACRO
	move.l	\1,a0
	cmp.l	#0,a0
	beq.s	set\3
	move.l	(a0),\2
set\3:
	ENDM

start:
	move.l	sp,stack

	move.l	#err_kick20,error

	lea	dosname,a1
	move.l	4,a6
	moveq	#36,d0
	jsr	-552(a6)
	tst.l	d0
	beq.w	exit
	move.l	d0,dosbase

	move.l	#err_badargs,error

	move.l	#format,d1
	move.l	#table,d2
	clr.l	d3
	move.l	dosbase,a6
	jsr	-798(a6)
	tst.l	d0
	beq.w	exit
	move.l	d0,rdargs

	move.l	#err_help,error
	tst.l	help
	bne.w	exit

; -- set variables according to ReadArgs() --

	setv	cx,centerx,1
	setv	cy,centery,2
	setv	zone,neutralzone,3
	setv	sens,sensitivity,4
	setv	asp,aspect,5
	setv	sens,but2sensitivity,6
	setv	but2sens,but2sensitivity,7
	setv	sens,but1sensitivity,8
	setv	but1sens,but1sensitivity,9
	setv	sens,bothsensitivity,10
	setv	bothsens,bothsensitivity,11

; -- open/alloc everything --

	lea	gfxname,a1
	move.l	4,a6
	jsr	-408(a6)
	move.l	d0,gfxbase

	bsr.w	aj_start
	tst.l	d0
	bne.w	exit

	move.l	task,a1
	move.l	#20,d0
	jsr	-300(a6)

	move.l	gfxbase,a6
	jsr	-270(a6)

; -- main loop --

loop:
	move.l	gfxbase,a6
	jsr	-270(a6)		; WaitTOF()

	move.l	xpos,d0
	move.l	ypos,d1
	asr.l	#8,d0
	asr.l	#8,d1
	move.l	d0,d2
	move.l	d1,d3
	sub.l	oldxpos,d0
	sub.l	oldypos,d1
	move.l	d2,oldxpos
	move.l	d3,oldypos
	bsr.w	write

	move.b	button1,d1
	move.b	button2,d2
	cmp.b	oldbutton1,d1
	beq.s	nobchg1
	move.w	#iecode_lbutton,d0
	tst.b	button1
	bne.s	down1
	or.w	#iecode_up_prefix,d0
down1:	bsr.w	buttons
nobchg1:
	cmp.b	oldbutton2,d2
	beq.s	nobchg2
	move.w	#iecode_rbutton,d0
	tst.b	button2
	bne.s	down2
	or.w	#iecode_up_prefix,d0
down2:	bsr.w	buttons
nobchg2:
	move.b	d1,oldbutton1
	move.b	d2,oldbutton2

	move.l	4,a6
	clr.l	d0
	clr.l	d1
	jsr	-306(a6)
	and.l	#$1000,d0		; Ctrl-C ?
	beq.w	loop

	move.l	#output,d1
	move.l	#minx,d2
	move.l	dosbase,a6
	jsr	-954(a6)

exit:
; -- cleanup --

	move.l	stack,sp

err:	tst.l	error
	beq.s	noerr
	move.l	error,d1
	clr.l	d2
	move.l	dosbase,a6
	jsr	-954(a6)
noerr:

	bsr.w	aj_stop

	tst.l	rdargs
	beq.s	nordargs

	move.l	rdargs,d1
	move.l	dosbase,a6
	jsr	-858(a6)

nordargs:
	tst.l	gfxbase
	beq.s	nogc

	move.l	gfxbase,a1
	move.l	4,a6
	jsr	-414(a6)
nogc:
	tst.l	dosbase
	beq.s	nodc

	move.l	dosbase,a1
	move.l	4,a6
	jsr	-414(a6)

nodc:	moveq	#0,d0
	rts

dosbase:
	dc.l	0

minx:	dc.l	1000
maxx:	dc.l	-1000
centerx:
	dc.l	0
miny:	dc.l	1000
maxy:	dc.l	-1000
centery:
	dc.l	0
aspect:
	dc.l	0
neutralzone:
	dc.l	DEF_ZONE
sensitivity:
	dc.l	DEF_SENS
but1sensitivity:
	dc.l	DEF_SENS
but2sensitivity:
	dc.l	DEF_SENS
bothsensitivity:
	dc.l	DEF_SENS

button1:
	dc.b	0
button2:
	dc.b	0
oldbutton1:
	dc.b	0
oldbutton2:
	dc.b	0

table:
cx:	dc.l	0
cy:	dc.l	0
asp:	dc.l	0
zone:	dc.l	0
sens:	dc.l	0
but1sens:
	dc.l	0
but2sens:
	dc.l	0
bothsens:
	dc.l	0
sb:	dc.l	0
xy:	dc.l	0
help:	dc.l	0

rdargs:
	dc.l	0

; start joy routines

aj_start:
	move.l	4,a6
	suba.l	a1,a1
	jsr	-294(a6)
	move.l	d0,task

	bsr.w	openinput
	tst.l	d0
	bne.w	i_exit

	bsr.w	allocjoyport
	tst.l	d0
	bne.w	i_exit

	bsr.w	allocpotgo
	tst.l	d0
	bne.w	i_exit

	bsr.w	opentimer
	tst.l	d0
	bne.w	i_exit

	bsr.w	installinterrupt

	move.l	#0,error
	clr.l	d0
i_exit:	rts

; stop and cleanup

aj_stop:
	bsr.w	closeall
	bsr.w	removeinterrupt
	bsr.w	closetimer
	bsr.w	freepotgo
	bsr.w	freejoyport
	rts

; -------------------------------------------------------------------------

		include	'devices/gameport.i'
		include	'exec/io.i'
		include	'devices/input.i'
		include	'devices/inputevent.i'

installinterrupt:
	move.l	4,a6
	moveq	#5,d0			; add vertical blank interrupt
	lea	myinterrupt,a1
	jsr	-168(a6)
	move.l	#1,is_data
	rts

removeinterrupt:
	tst.l	is_data
	beq.s	notadded
	move.l	4,a6
	moveq	#5,d0
	lea	myinterrupt,a1
	jsr	-174(a6)
notadded:
	move.l	#0,is_data
	rts

myinterrupt:
; * Node

	dc.l	0	; Succ
	dc.l	0	; Prev
	dc.b	5	; Type
	dc.b	0	; Pri
	dc.l	IName	; Name

is_data:
	dc.l	0	; is_Data
	dc.l	IntProg	; is_Code

; --- Interrupt routine ---

IntProg:
	movem.l	d2-d7/a2-a4,-(sp)

	lea	time,a0
	move.l	(a0),d2
	move.l	4(a0),d3
	move.l	timerbase,a6
	jsr	-66(a6)		; getsystime()
	tst.l	d2
	bne.s	noinit
	tst.l	d3
	beq.w	endint
noinit:
	sub.l	(a0),d2
	sub.l	4(a0),d3
	neg.l	d2
	neg.l	d3
	tst.l	d3
	bpl.s	nocarry
	add.l	#1000000,d3
	sub.l	#1,d2
nocarry:	
	tst.l	d2
	bne.w	endint
	move.l	d3,micros

	move.w	$dff014,d0		;read pots
	move.w	d0,-(sp)
	move.w	#%0000000000000001,d0
	bsr.w	writepotgo
	move.w	(sp)+,d0
	
	move.b	d0,d1
	ext.w	d1
	ext.l	d1		; d1 - pot y
	asr.w	#8,d0
	ext.l	d0		; d0 - pot x
	add.l	d0,d0		; *2 to make centerx and centery
	add.l	d1,d1		; integers.
	tst.l	xy
	beq.s	noswitchxy
	exg	d0,d1
noswitchxy:
	cmp.l	minx,d0
	bge.s	here1		; x<minx ?
	move.l	d0,minx
here1:
	cmp.l	maxx,d0
	ble.s	here2		;x>maxx ?
	move.l	d0,maxx
here2:
	cmp.l	miny,d1
	bge.s	here3		;y<miny ?
	move.l	d1,miny
here3:
	cmp.l	maxy,d1
	ble.s	here4		;y>maxy ?
	move.l	d1,maxy
here4:

	cmp.l	#0,asp		; calculate aspect ?
	bne.s	skipasp
	move.l	maxx,d2
	sub.l	minx,d2
	move.l	maxy,d3
	sub.l	miny,d3
	tst.l	d3
	beq.s	skipasp
	muls	#100,d2		; aspect=(maxx-minx)*100/(maxy-miny)
	divs	d3,d2
	ext.l	d2
	move.l	d2,aspect
skipasp:

	cmp.l	#0,cx		; calculate centerx ?
	bne.s	skipx

	move.l	minx,d2
	add.l	maxx,d2
	asr.l	#1,d2
	move.l	d2,centerx	; centerx=(minx+maxx)/2
skipx:
	sub.l	centerx,d0	; x=x-centerx

	cmp.l	#0,cy		; calculate centery ?
	bne.s	skipy

	move.l	miny,d3
	add.l	maxy,d3
	asr.l	#1,d3
	move.l	d3,centery	; centery=(miny-maxy)/2
skipy:
	sub.l	centery,d1	; y=y-centery

; if x>0 then if x>neutralzone x=x-neutralzone else x=0
; if x<0 then if x<-neutralzone x=x+neutralzone else x=0

	move.l	neutralzone,d2
	tst.l	d0
	bpl.s	dod1

	neg.l	d2
	cmp.l	d2,d0
	ble.w	nochg2
	move.l	d2,d0
nochg2:
	bra.s	next1

dod1:	cmp.l	d2,d0
	bge.s	nochg1
	move.l	d2,d0
nochg1:
next1:	sub.l	d2,d0

; the same as above for y

	move.l	neutralzone,d2
	tst.l	d1
	bpl.s	dod2

	neg.l	d2
	cmp.l	d2,d1
	ble.s	nochg4
	move.l	d2,d1
nochg4:
	bra.s	next2

dod2:	cmp.l	d2,d1
	bge.s	nochg3
	move.l	d2,d1
nochg3:
next2:	sub.l	d2,d1

	clr.w	d3
	move.b	button2,d3
	add.b	d3,d3
	or.b	button1,d3
	asl.b	#2,d3
	move.l	#sensitivity,a0
	move.l	(a0,d3.w),d2

normb:
	muls	d2,d0		; x=x*sens
	muls	d2,d1		; y=y*sens

	move.l	micros,d3	; framerate correction
	asr.l	#6,d3
	muls	d3,d0
	muls	d3,d1
	asr.l	#8,d0
	asr.l	#8,d1

	ext.l	d0
	add.l	d0,xpos
	
	move.l	aspect,d2	; make aspect scale from 0-100 to 0-256
	asl.l	#8,d2		; *256
	divs	#100,d2		; /100
	ext.l	d2
	ext.l	d1
	muls	d2,d1		; y=y*aspect
	asr.l	#8,d1		; y=y/256
	add.l	d1,ypos

	move.w	$dff00c,d4		;read buttons
	moveq	#1,d5
	moveq	#9,d6
	tst.l	sb
	bne.s	noswitchb
	exg	d5,d6
noswitchb:
	move.b	#0,button1
	move.b	#0,button2
	btst	d5,d4
	beq.s	nextb1
	move.b	#1,button1	
nextb1:
	btst	d6,d4
	beq.s	nextb2
	move.b	#1,button2
nextb2:

endint:	movem.l	(sp)+,d2-d7/a2-a4
	lea	$dff000,a0
	clr.l	d0
	rts

xpos:	dc.l	0
ypos:	dc.l	0
oldxpos:
	dc.l	0
oldypos:
	dc.l	0

; open potgo.resource, alloc bits

allocpotgo:
		move.l	#err_potgoopen,error
		lea	potgoname,a1
		move.l	4,a6
		jsr	-498(a6)
		move.l	d0,potgobase
		tst.l	d0
		beq.s	potgoerr
		
		move.l	#err_potgoalloc,error
		move.l	#%0101000000000001,d0
		move.l	potgobase,a6
		jsr	-6(a6)
		move.l	d0,allocatedb
		cmp.l	#%0101000000000001,d0
		bne.s	potgoerr

		moveq	#0,d0
		move.l	#0,error
		rts
potgoerr:	moveq	#1,d0
		rts

; free potgo bits

freepotgo:
		tst.l	potgobase
		beq.s	nopotgo
		tst.l	allocatedb
		beq.s	nopotgo
		move.l	potgobase,a6
		move.l	allocatedb,d0
		jsr	-12(a6)
nopotgo:	move.l	#0,potgobase
		rts

; d0 - word
writepotgo:
		move.l	allocatedb,d1
		move.l	potgobase,a6
		jsr	-18(a6)
		rts

potgobase:	dc.l	0
allocatedb:	dc.l	0

; open gameport.device, alloc controller

allocjoyport:
		lea	gameportPort,a1		; reply port
		move.l	task,MP_SIGTASK(a1)	; signal us when msg received
		move.l	4,a6
		jsr	-354(a6)
		move.b	#1,gpportadded
		
		move.l	#err_gameportopen,error
		lea	gameportDevName,a0
		lea	gameportIOReq,a1
		move.l	#gameportPort,MN_REPLYPORT(a1)
		moveq.l	#1,d0			; unit number
		moveq.l	#0,d1			; flags
		move.l	4,a6
		jsr	-444(a6)
		move.l	d0,gameporterr
		tst.l	d0
		bne.s	jperr
		jsr	-132(a6)
		move.l	#err_gameportalloc,error
		lea	gameportIOReq,a1
		move.w	#GPD_ASKCTYPE,IO_COMMAND(a1)
		move.l	#contr_type,IO_DATA(a1)
		move.l	#1,io_length(a1)
		jsr	-456(a6)
		tst.b	contr_type
		bne.s	contr_used
; port free, allocating...
		lea	gameportIOReq,a1		
		move.w	#GPD_SETCTYPE,IO_COMMAND(a1)
		move.b	#GPCT_ALLOCATED,contr_type
		move.l	#contr_type,IO_DATA(a1)
		move.l	#1,io_length(a1)
		jsr	-456(a6)
		jsr	-138(a6)
		moveq	#0,d0
		move.l	#0,error
		rts
contr_used:	jsr	-138(a6)
		move.b	#0,contr_type
jperr:		moveq	#1,d0
		rts

gameporterr:	dc.l	0
contr_type:	dc.b	0
gpportadded:	dc.b	0
timerportadded:	dc.b	0
		even

; free gameport, close gameport.device

freejoyport:
		tst.b	gpportadded
		beq.w	return
		tst.l	gameporterr
		bne.s	notopened
		cmp.b	#GPCT_ALLOCATED,contr_type
		bne.s	c_notalloc
		lea	gameportIOReq,a1		
		move.w	#GPD_SETCTYPE,IO_COMMAND(a1)
		move.b	#GPCT_NOCONTROLLER,contr_type
		move.l	#contr_type,IO_DATA(a1)
		move.l	#1,io_length(a1)
		move.l	4,a6
		jsr	-456(a6)
c_notalloc:	move.l	4,a6
		lea	gameportIOReq,a1		
		jsr	-450(a6)

notopened:	lea	gameportPort,a1		; ptr to the msgport
		move.l	4,a6
		jsr	-360(a6)
return:		move.b	#0,gpportadded
		rts

; open timer.device

opentimer:
		move.l	#err_opentimer,error
		lea	TimerPort,a1		; reply port
		move.l	task,MP_SIGTASK(a1)	; signal us when msg received
		move.l	4,a6
		jsr	-354(a6)
		move.b	#1,timerportadded
		lea	TimerDevName,a0
		lea	TimerIOReq,a1
		move.l	#TimerPort,MN_REPLYPORT(a1)
		moveq.l	#0,d0
		moveq.l	#0,d1
		move.l	4,a6
		jsr	-444(a6)
		lea	TimerIOReq,a1
		move.l	20(a1),timerbase
		rts

closetimer:
		tst.l	timerbase
		beq.s	t_notopened
		lea	TimerIOReq,a1		
		move.l	4,a6
		jsr	-450(a6)
t_notopened:	tst.b	timerportadded
		beq.s	tp_notadded
		lea	TimerPort,a1		; ptr to the msgport
		move.l	4,a6
		jsr	-360(a6)
tp_notadded:	clr.l	timerbase
		rts

; -------------------------------------------------------------------------

		include	'libraries/dos_lib.i'

; open input device

openinput:
		move.l	#err_inputdev,error
		lea	InputPort,a1		; reply port for input device
		move.l	task,MP_SIGTASK(a1)	; signal us when msg received
		move.l	4,a6
		jsr	-354(a6)
		move.b	#1,iportadded
		
		lea	InputDevName,a0		; 'input.device'
		lea	InputIOReq,a1		; IOStdReq structure for it
		move.l	#InputPort,MN_REPLYPORT(a1)
		moveq.l	#0,d0			; unit number (n/a)
		moveq.l	#0,d1			; flags (n/a)
		move.l	4,a6
		jsr	-444(a6)
		lea	InputIOReq,a1
		move.l	io_device(a1),inputbase
		move.l	d0,inputdeverr
		rts

inputdeverr:
		dc.l	0
iportadded:	dc.b	0
		even

; close input device

CloseAll:	tst.b	iportadded
		beq.w	return

		tst.l	inputdeverr		; an opendevice error?
		bne.b	DeviceError		; yep

		lea	InputIOReq,a1		
		move.l	4,a6
		jsr	-450(a6)

DeviceError:	lea	InputPort,a1		; ptr to the msgport
		move.l	4,a6
		jsr	-360(a6)

		clr.b	iportadded

		rts				; exit the program

; sends pointerpos (relative) event
; d0 - x
; d1 - y

write:

; --- is moving really needed ? ---

		tst.w	d0
		bne.s	wr
		tst.w	d1
		bne.s	wr
		rts		; nope !
; yep !
wr:		movem.w	d0/d1,-(sp)
		lea	Inpute,a1
		move.b	#ieclass_pointerpos,ie_class(a1)
		move.b	#0,ie_subclass(a1)
		move.w	d0,ie_x(a1)
		move.w	d1,ie_y(a1)
		move.w	#iequalifier_relativemouse,d1
		bsr.w	setqualifier
		move.w	d1,ie_qualifier(a1)
		move.w	#0,ie_code(a1)

		lea	InputIOReq,a1		; input.device io request
		move.w	#IND_WRITEEvENT,IO_COMMAND(a1)
		move.l	#InputE,IO_DATA(a1)
		move.l	#ie_sizeof,io_length(a1)
		move.l	4,a6
		jsr	-456(a6)
		movem.w	(sp)+,d0/d1
		rts
				
; sends rawmouse event
; d0 - ie_code

buttons:
		movem.w	d0/d1,-(sp)
		lea	Inpute,a1
		move.b	#ieclass_rawmouse,ie_class(a1)
		move.b	#0,ie_subclass(a1)
		move.w	d0,ie_code(a1)
		move.w	#0,ie_x(a1)
		move.w	#0,ie_y(a1)
		move.w	#iequalifier_relativemouse,d1
		bsr.w	setqualifier
		move.w	d1,ie_qualifier(a1)

		lea	InputIOReq,a1		; input.device io request
		move.w	#IND_WRITEEvENT,IO_COMMAND(a1)
		move.l	#InputE,IO_DATA(a1)
		move.l	#ie_sizeof,io_length(a1)
		move.l	4,a6
		jsr	-456(a6)
		movem.w	(sp)+,d0/d1
		rts

; add mouse buttons to ie_qualifier

setqualifier:
	movem.l	d0/a0/a1/a6,-(sp)
	move.l	inputbase,a6
	jsr	-42(a6)
	add.w	d0,d1
	movem.l	(sp)+,d0/a0/a1/a6

	tst.b	button1
	beq.s	nol
	or.w	#iequalifier_leftbutton,d1
nol:	tst.b	button2
	beq.s	nor
	or.w	#iequalifier_rbutton,d1
nor:
	rts

inputbase:	dc.l	0
timerbase:	dc.l	0

micros:	dc.l	0

time:
	dc.l	0	;secs
	dc.l	0	;micros

; -------------------------------------------------------------------------

InputE:		ds.b	ie_sizeof
InputIOReq:	ds.b	IOSTD_SIZE
InputPort:	ds.b	MP_SIZE
gameportIOReq:	ds.b	IOSTD_SIZE
gameportPort:	ds.b	MP_SIZE
timerIOReq:	ds.b	IOSTD_SIZE
TimerPort:	ds.b	MP_SIZE
		even

; -------------------------------------------------------------------------

state:
	dc.l	0
gfxbase:
	dc.l	0
stack:
	dc.l	0
task:	
	dc.l	0
error:
	dc.l	0

format:
	dc.b	'CENTERX=X/N,CENTERY=Y/N,ASPECT=ASP/N,NEUTRALZONE=ZONE/N,SENSITIVITY=SENS/N,BUTTON1SENS=B1S/N,BUTTON2SENS=B2S/N,BOTHSENS=BS/N,SWITCHBUTTONS=SB/S,SWITCHXY=XY/S,HELP/S',0
gfxname:
	dc.b	'graphics.library',0
dosname:
	dc.b	'dos.library',0
InputDevName:
	dc.b	'input.device',0
gameportDevName:
	dc.b	'gameport.device',0
timerDevName:
	dc.b	'timer.device',0
potgoname:
	dc.b	'potgo.resource',0
IName:
	dc.b	'AnalogMouse interrupt',0
output:
	dc.b	10,"Joystick settings:",10,10
	dc.b	"min x = %ld   max x  = %ld  center x = %ld",10
	dc.b	"min y = %ld   max y  = %ld  center y = %ld",10
	dc.b	"aspect ratio (x*100/y) = %ld",10,10
	dc.b	0
err_kick20:
	dc.b	"Needed at least Kickstart 2.0!",10,0
err_inputdev:
	dc.b	"Couldn't open input.device!",10,0
err_potgoopen:
	dc.b	"Couldn't open potgo.device!",10,0
err_gameportopen:
	dc.b	"Couldn't open gameport.device!",10,0
err_opentimer:
	dc.b	"Couldn't open timer.device!",10,0
err_potgoalloc:
	dc.b	"Couldn't allocate bits in POTGO register!",10,0
err_gameportalloc:
	dc.b	"Couldn't allocate joystick port!",10
	dc.b	"Try to quit other programs that may be using it.",10,0
err_badargs:
	dc.b	'Bad arguments!',10,0
err_help:
	dc.b	10
	dc.b	155,"1mAnalogMouse",155,"0m short help:",10,10
	dc.b	155,"1mCENTERX",155,"0m - x coordinate for neutral position,",10
	dc.b	"          if not specified will be calculated and shown on exit.",10
	dc.b	155,"1mCENTERY",155,"0m - same as above but for y coordinate.",10
	dc.b	155,"1mASPECT",155,"0m  - joystick aspect ratio, calculated from a formula ",155,"3mmaxx*100/maxy",155,"0m",10
	dc.b	"          thus 100 means aspect 1:1, 200 - 2:1 etc. Automatically",10
	dc.b	"          calculated if not specified.",10
	dc.b	155,"1mZONE",155,"0m    - this parameter specifies maximum deflection of joystick at",10
	dc.b	"          which the mouse pointer still does not move. Default 4.",10
	dc.b	155,"1mSENS",155,"0m    - Joystick's sensitivity. The higher this value is, the faster",10
	dc.b	"          the mouse pointer moves. Default 100.",10
	dc.b	155,"1mB1S",155,"0m     - sensitivity when button 1 is pressed. Default equal to",10
	dc.b	"          the ",155,"1mSENSITIVITY",155,"0m parameter.",10
	dc.b	155,"1mB2S",155,"0m     - same as above, for button 2.",10
	dc.b	155,"1mBS",155,"0m      - for both buttons pressed.",10
	dc.b	155,"1mSB",155,"0m      - Switch buttons - button 1 is button 2 and vice versa.",10
	dc.b	155,"1mXY",155,"0m      - Exchange X coordinate with Y.",10
	dc.b	155,"1mHELP",155,"0m    - You're reading it :)",10
	dc.b	10
	dc.b	"When the program is working press ",155,"3mCtrl-C",155,"0m to break it.",10
	dc.b	10
	dc.b	0
version:
	dc.b	"$VER: AnalogMouse 1.0 (15.03.98) by Piotr Pawlow (PP/UNION)",0
