;Entry_JoystickMouse
;------------------
;Translates Joystick movement into mouse movement

STRUCT Joystick_Mouse
{
  .Event_JoystickMouse	DCD 0
  .joystick		DCB 0
  .select		DCB 0
  .menu			DCB 0
  .adjust		DCB 0
  .damping		DCD 0
  .X_offset		DCD 0
  .Y_offset		DCD 0
  .bound_left		DCD 0
  .bound_bottom		DCD 0
  .bound_right		DCD 0
  .bound_top		DCD 0
  .previous_values	DCD 0,0,0
  .size
}

#set Joystick_Shift = 15
#set Joystick_Percentage = ((1<<Joystick_Shift)-1)/100

;Entry:
; R0 - Command tail
; R1 = no. of parameters
; R12 - pointer to module private word

;Exit:
; R0 - corrupt

.Entry_ADFJoystickMouse
 STMFD   R13!, {R1-R4, R12, R14}

 LDR     R12, [R12, #0]
 ADD     R12, R12, #Joystick_Mousemapping - VARS	;R12=pointer to Joystick_Mousemapping
 TEQ     R1, #0				;are we shutting down?
 BEQ     _exit_cancel			;YES

 MVN     R4, #0
 MOV     R3, #65535			;default to no damping
 STR     R4, [R12, #Joystick_Mouse.joystick]	;invalidate Joystick and buttons
 MOV     R2, #0				;default to Joystick 1
 STRB    R2, [R12, #Joystick_Mouse.joystick]
 STR     R3, [R12, #Joystick_Mouse.damping]

 MOV     R1, R0				;R1=command tail
 MOV     R0, #1 << 29			;restrict OS_ReadUnsigned to value in R2
 ._L1
   BL      skip_spaces_R1		;ignore SPACE
   BCC     _P1				;exit, if end of commandline

   CMP     R2, #ASC("0")
   RSBHSS  R3, R2, #ASC("9")		;0-9 is the damping %
   BHS     _damping

   BIC     R2, R2, #32			;force to uppercase
   TEQ     R2, #ASC("J")
   BEQ     _joystick			;its a Joystick

   TEQ     R2, #ASC("S")
   MOVEQ   R3, #Joystick_Mouse.select
   BEQ     _read_button

   TEQ     R2, #ASC("M")
   MOVEQ   R3, #Joystick_Mouse.menu
   BEQ     _read_button

   TEQ     R2, #ASC("A")
   MOVEQ   R3, #Joystick_Mouse.adjust
   BEQ     _read_button
 B       _L1

 ._P1
 LDR     R0, [R12, #Joystick_Mouse.Event_JoystickMouse]
 TEQ     R0, #0				;is handler already running?
 LDMNEFD R13!, {R1-R4, R12, PC}		;YES

 MOV     R0, #1				;50/sec
 ADR     R1, _mouse
 MOV     R2, R12
 SWI     XOS_CallEvery
 STRVC   R1, [R12, #Joystick_Mouse.Event_JoystickMouse]

 ._exit
LDMFD   R13!, {R1-R4, R12, PC}

 ._exit_cancel
 LDR     R0, [R12, #Joystick_Mouse.Event_JoystickMouse]
 TEQ     R0, #0				;is handler already running?
 LDMEQFD R13!, {R1-R4, R12, PC}		;NO
 
 MOV     R1, R12
 SWI     XOS_RemoveTickerEvent
 MOVVC   R1, #0
 STRVC   R1, [R12, #Joystick_Mouse.Event_JoystickMouse]
LDMFD   R13!, {R1-R4, R12, PC}


 ._joystick
   MOV     R2, #Max_Joysticks		;R2=max value
   SWI     XOS_ReadUnsigned		;read the value PRM1-460
   BVS     _exit			;exit on error

   SUB     R2, R2, #1			;reduce value
   STRB    R2, [R12, #Joystick_Mouse.joystick]
 B       _L1

 ._damping
   SUB     R1, R1, #1
   MOV     R2, #100			;R2=max value
   SWI     XOS_ReadUnsigned		;read the value PRM1-460
   BVS     _exit			;exit on error

   RSB     R2, R2, #100
   MOV     R3, #Joystick_Percentage
   MUL     R2, R3, R2
   STR     R2, [R12, #Joystick_Mouse.damping]
 B       _L1

 ._read_button
     LDRB    R2, [R1], #1		;find the value
     TEQ     R2, #0
     BEQ     _exit
     TEQ     R2, #ASC("=")
   BNE     _read_button

   ._L6
     LDRB    R4, [R1], #1
     TEQ     R4, #0
     BEQ     _exit
     TEQ     R4, #ASC(" ")		;skip spaces
   BEQ     _L6
   TEQ     R4, #ASC("B")		;ignore "B"
   TEQNE   R4, #ASC("b")
   SUBNE   R1, R1, #1

   MOV     R2, #32			;R2=max value (8 buttons)
   SWI     XOS_ReadUnsigned		;read the value PRM1-460
   BVS     _exit			;exit on error
   
   SUB     R2, R2, #1			;reduce value
   STRB    R2, [R12, R3]		;NO
 B       _L1
  
 ._clearV_exit
 SUBS    R0, R0, R0			;clear V
LDMFD   R13!, {R0-R7, R9, PC}


;Entry:
; R12 - pointer to Joystick_Mousemapping

 ._mouse
 STMFD   R13!, {R0-R7, R9, R14}

 LDRB    R0, [R12, #Joystick_Mouse.joystick]	;Joystick we're going to map to the mouse
 ADD     R4, R12, #Joystick_DeadZonesSQ - Joystick_Mousemapping
 LDR     R4, [R4, R0, LSL #2]		;R4 = deadzone

 ORR     R0, R0, #1 << 8		;read 16bit Joystick interface
 SWI     XJoystick_Read
 MOVVC   R5, R1				;R5=buttons
 BICVC   R1, R0, #&FFFF << 16
 SUBVC   R1, R1, #1 << 15		;R1= - down / + up
 MOVVC   R0, R0, LSR #16
 SUBVC   R0, R0, #1 << 15		;R0= - left / + right
 BVC     _16bit_supported

 LDRB    R0, [R12, #Joystick_Mouse.joystick]	;16bit not supported, use 8bit
 SWI     XJoystick_Read
 BVS     _clearV_exit			;no Joysticks
 MOV     R5, R0, LSR #16		;R5=buttons
 MOV     R1, R0, LSL #24
 MOV     R0, R0, LSL #16
 MOV     R1, R1, ASR #16		;R1= - down / + up
 MOV     R0, R0, ASR #16
 BIC     R0, R0, #&FF			;R0= - left / + right

 ._16bit_supported			;ranges are -32768 TO 32767
 MUL     R6, R0, R0
 MLA     R6, R1, R1, R6			;R6=(X*X)+(Y*Y)=distance
 SUBS    R6, R6, R4			;reduce by deadzone
 MOVMI   R0, #0
 MOVMI   R1, #0
 BMI     _deadzone			;in deadzone, so exit early

 MOV     R2, #1<<30			;work out square root of R6
 ._L2
   CMP     R2, R6
   MOVHI   R2, R2, LSR #2
 BHI     _L2				;R2=highest ^4

 CMP     R2, #0
 MOV     R7, #0
 BEQ     _sqr_zero
 ._L3
   ADD     R3, R7, R2
   CMP     R6, R3
   MOV     R7, R7, LSR #1
   SUBHS   R6, R6, R3
   ADDHS   R7, R7, R2
   MOVS    R2, R2, LSR #2
 BNE     _L3

 ._sqr_zero				;R7=SQR(R6)
; Not normalized
 MUL     R0, R7, R0
 MUL     R1, R7, R1
 MOV     R0, R0, ASR #16		;R0 = (X * SQR(R6))>>16
 MOV     R1, R1, ASR #16		;R1 = (Y * SQR(R6))>>16
; *****

; Normalize Joystick
; CMP     R0, #0
; RSBMI   R2, R0, #0
; MOVPL   R2, R0
; CMP     R1, #0
; RSBMI   R3, R1, #0
; MOVPL   R3, R1
; CMP     R3, R2
; MOVHI   R2, R3				;R2=ABS(greater of X%/Y%)
; 
; MOV     R7, R7, ASL #Joystick_Shift+1
; U_DIV   R7, R2, R3			;R7=R7/R2  R3=mod
; MUL     R0, R7, R0
; MUL     R1, R7, R1
; MOV     R0, R0, ASR #Joystick_Shift+1
; MOV     R1, R1, ASR #Joystick_Shift+1
; *****
 LDR     R7, [R12, #Joystick_Mouse.damping]
 MUL     R0, R7, R0			;damp the value
 MUL     R1, R7, R1
 MOV     R0, R0, ASR #Joystick_Shift-1	;R0 = (X * damping)>>Joystick_Shift
 MOV     R1, R1, ASR #Joystick_Shift-1	;R1 = (Y * damping)>>Joystick_Shift

 ._deadzone
 LDR     R2, [R12, #screen_OS_units_X - Joystick_Mousemapping]
 LDR     R3, [R12, #screen_OS_units_Y - Joystick_Mousemapping]
 ADD     R0, R0, #1 << 15		;change range to 0>65535
 ADD     R1, R1, #1 << 15
 MUL     R0, R2, R0			;scale to max X (R2)
 MUL     R1, R3, R1			;scale to max Y (R3)
 MOV     R0, R0, ASR #16		;R0 = X * 2
 MOV     R1, R1, ASR #16		;R1 = Y * 2

 LDR     R4, [R12, #Joystick_Mouse.X_offset]	;add mouse offset
 LDR     R6, [R12, #Joystick_Mouse.Y_offset]
 ADD     R0, R0, R4
 ADD     R1, R1, R6

 LDR     R4, [R12, #Joystick_Mouse.bound_left]	;apply bounding
 LDR     R6, [R12, #Joystick_Mouse.bound_right]
 CMP     R0, R4
 MOVLT   R0, R4
 CMP     R0, R6
 MOVGT   R0, R6
 LDR     R4, [R12, #Joystick_Mouse.bound_bottom]
 LDR     R6, [R12, #Joystick_Mouse.bound_top]
 CMP     R1, R4
 MOVLT   R1, R4
 CMP     R1, R6
 MOVGT   R1, R6

 LDRB    R6, [R12, #Joystick_Mouse.select]	;check buttons
 MOV     R4, #1
 MOV     R2, #0
 TST     R5, R4, LSL R6			;is the button associated with Select pressed?
 ORRNE   R2, R2, #%001
 LDRB    R6, [R12, #Joystick_Mouse.menu]
 TST     R5, R4, LSL R6			;is the button associated with Menu pressed?
 ORRNE   R2, R2, #%010
 LDRB    R6, [R12, #Joystick_Mouse.adjust]
 TST     R5, R4, LSL R6			;is the button associated with Adjust pressed?
 ORRNE   R2, R2, #%100

 ADD     R3, R12, #Joystick_Mouse.previous_values
 LDMIA   R3, {R4, R5, R6}		;have the values changed?
 TEQ     R0, R4
 TEQEQ   R1, R5
 TEQEQ   R2, R6
 BEQ     _clearV_exit			;NO, exit
 STMIA   R3, {R0, R1, R2}		;store new state

 MOV     R0, R0, LSL #8
 ORR     R0, R0, #3
 ORR     R0, R0, R1, LSL #24
 MOV     R1, R1, LSR #8
 STMFD   R13!, {R0-R1}
 MOV     R0, #21
 MOV     R1, R13
 BL      pass_SWI_on			;pass next SWI on
 SWI     XOS_Word			;set the Mouse position
 ADD     R13, R13, #8

 MOV     R9, #Vector_KeyV
 EOR     R6, R6, R2			;bit set if changed
 MOV     R5, #3				;3 Mouse buttons
 MOV     R1, #112			;low level key for Mouse button 1
 ._L4
   MOVS    R6, R6, LSR #1		;C set if changed
   ANDCS   R0, R2, #1
   ADDCS   R0, R0, #1			;R0 1=released or 2=pressed
   SWICS   XOS_CallAVector		;PRM1-70
   MOV     R2, R2, LSR #1

   ADD     R1, R1, #1
   SUBS    R5, R5, #1
 BNE     _L4

 ._clearV_exit
 SUBS    R0, R0, R0			;clear V
LDMFD   R13!, {R0-R7, R9, PC}
