;Analog Joys
;-----------
;Analogue Joystick Code
;----------------------
;By Christos Dimitrakakis (aka Olethros)
;---------------------------------------


;This code is freely distributable


.Comments

;test code for using analogue joysticks
;on port 1
;seems to work
;
;for the other port, use $DFF012 instead of $DFF014
;setting up the pins and Paula IO seems to be unnnneeecccessarrry?



;I'd've liked to see an OS-Friendly way to do this... oh well

;Also note that I am not an assembly expert, so any asm
;code used will probably not be the ideal way of doing things.


;|--------------------------------------------------------------|
;| saving of cx,cy,mx,my,nx,ny values                           |
;| seems to be enough for proper calibration                    |
;| be careful to use them properly.                             |
;|                                                              |
;| the final calibration stage is a nice easy example of how    |
;| to properly use those values                                 |
;|                                                              |
;|      NOTE: In this example I am adding                       |
;|      8 measurements together                                 |
;|                                                              |
;|    Take this under consideration and scale accordingly       |
;|  if you intend to use AnalogJoyPrefs data for Calibration    |
;|                                                              |
;|--------------------------------------------------------------|



;HOW TO CONVERT A PC ANALOGUE JOYSTICK(?)

;Well, I dunno the pin assignments from the PC joystick.
;The way I did this:
;(I hope you are adept in things like that. Only danger if you connect 5V to common and
;short your amiga - test with multimeter for max safety)


;Cut the cable and look at the wires.
;Open Up the joystick and look at where they're coming from
;There should be at least one wire coming out from each potentiometer
;Examine the wiring carefully; Find the cable wire corresponding to each potentiometer
;If the two potentiometers have a common wire, then this goes to +5V
;the others go to POTX and POTY
;if they don't (unlikely) then just connect one wire from each pot. to +5V,
;then connect the other 2 wires to POTX and POTY pins as above


;Anyways, my cable was like that:
;GREEN  - 5V
;ORANGE - POTX
;BROWN  - POTY
;BLACK  - COMMON
;WHITE  - JOYBUTTON (1?)
;BLUE   - JOYBUTTON (2?)





;by the way, especially for driving games, you do NOT want to get raw data from
;the joystick - reasons:
; 1)Jitter
;    all potentiometers exhibit jitter, which means noise
;   it is quite possible that you have actually listened to
;   the effects of jitter the last time you adjusted the
;   volume of your aeons-old amp
; 2)Inaccuracy
;   Jitter aside, all proportional controllers are inaccurate,
;   because of mechanical deficiences (at least mine is)

;Measures:
;
;   1) Averaging
;       Averaging in general will considerably improve playability. Try
;     continuous averaging for a more immediate and smooth joystick response
;
;   2) Driver (ok Player) aids
;       It is important to be able to provide some assistance to the player
;     Examples:
;     --Logarithmic input - converts linear input to logarithmic, for
;       finer control near the centre and more drastic at the edges.
;       or you can raise input to a power between 1 and 2 and then scale.
;     --Aid Centralize - similar in effect to logarithmic input, this
;       creats a dead-zone near the centre, where no input is assumed.
;       This could also be implemented by a computer aid that always
;       centers the fictional wheel of the car by a small amount
;     --Driving Line Aids - A very small, almost tiny help towards
;       the perfect driving line can be very helpful without making
;        the game too easy. Avoid extremes (ie F1GP) - No-one wants
;       to be FORCED on the driving line.
;     --Speed-sensitive sensitivity - With this, joystick movements will have
;       less effect at higher speeds.
;
;
;     Ideally, all these parameters should be user-adjustable...




;if you do not want to wait for a lot of frames to read the joystick
;you can do a continuous average instead
;or a fifo-based accumulator
    ;(ie get samples and put them in a queue
    ;each time an item is added to the queue, add its
    ;value to a variable somewhere.
    ;every time the queue gets filled up,
    ;flush the oldest item, WITHOUT FORGETTING TO SUBTRACT
    ;ITS VALUE FROM THE VARIABLE
    ;and then push the rest of the items to make room for the
    ;new value. Note that you can implement a queue as
    ;a looped Buffer so that you wont have to move all of the
    ;items everytime a new sample arrives-)



.Main_Code

Dim xqueue(8)
Dim yqueue(8)
apoint=8

WbToScreen 0
ShowScreen 0
Window 0,10,10,200,200,$2|$4|$8,"AnalogJoy Calibration",2,1

oxx.w=0
oyy.w=0
mx.w=0
my.w=0
nx.w=0
ny.w=0
sx.w=0
sy.w=0
Window 1,70,170,360,60,2|4|$800,"",2,1
WBox 0,0,360,60,1
WBox 1,1,359,59,2
WBox 2,2,358,58,0

WLocate 12,12:NPrint "CENTER JOYSTICK AND PRESS A MOUSE BUTTON"
While Joyb(0)=0
  xx.w=0:x.w=0
  yy.w=0:y.w=0
  For n=1 To 8
    VWait
    MOVE.w $dff014,d0
    MOVE.b d0,d1
    LSR.w #8,d0
    MOVE.b #1,$dff034
    PutReg d0,y.w
    PutReg d1,x.w
    cx+x
    cy+y
  Next n

  WLocate 10,22
  Print cx,":",cy," "
  cx=0:cy=0
Wend

  xx.w=0:x.w=0
  yy.w=0:y.w=0
  For n=1 To 16
  VWait
  MOVE.w $dff014,d0
  MOVE.b d0,d1
  LSR.w #8,d0
  MOVE.b #1,$dff034
  PutReg d0,y.w
  PutReg d1,x.w
  cx+x
  cy+y
;  MOVE.w #1,$dff034
  ;move.w #65281,$dff034
  Next n
cx/2
cy/2
WCls
WBox 0,0,360,60,1
WBox 1,1,359,59,2
WBox 2,2,358,58,0

WLocate 36,4
NPrint "NOW WIGGLE THE JOYSTICK AROUND"
WLocate 24,14
NPrint "UNTIL THE CURSOR FITS IN THE BOX"
WLocate 48,24
NPrint "THEN PRESS A MOUSE BUTTON"

Use Window 0
WindowOutput 0


WBox 50,50,150,150,2
Format "+00.00"
mx.w=0
my.w=0
nx.w=0
ny.w=0

xx.w=0:yy.w=0
Repeat
  x.w=0
  y.w=0
  For n=1 To 1
  VWait                   ;this code should ALWAYS run on type 5 interrupt
                          ;unless 100% positive that game loop runs
                          ;in time < 1 frame
  MOVE.w $dff014,d0       ;get Port1 POT
  MOVE.b d0,d1            ;move lower byte (X) to d1
  LSR.w #8,d0             ;shift 8 - now Y is in lower byte

                          ;(perhaps the MOVE/LSR combo could
                          ;be replaced with a bitfield instruction?)

  MOVE.b #1,$dff034       ;dump the capacitors!
                          ;almost immediately after the VBLANK
                          ;must read POTX/POTY first, though

  PutReg d0,y.w           ;put the stuff into place
  PutReg d1,x.w
  xx+x-xqueue(apoint)                    ;add them
  yy+y-yqueue(apoint)
  xqueue(apoint)=x
  yqueue(apoint)=y
  apoint+1
  If apoint>8 Then apoint=1
  Next n

  rx.w=xx-cx
  ry.w=yy-cy

  mx=Max(mx,rx)
  my=Max(my,ry)
  nx=Min(nx,rx)
  ny=Min(ny,ry)

  If rx>0 Then Cfx=mx Else Cfx=-nx
  If ry>0 Then Cfy=my Else Cfy=-ny

  CalX=10*rx/Cfx
  CalY=10*ry/Cfy

  WLocate 1,1
  NPrint "X:",CalX," Y:",CalY," "

  WCircle ox,oy,3,0
  ox=5*CalX+100:oy=5*CalY+100
  WCircle ox,oy,3,1
  WCircle 100,100,4,3
Until Joyb(1)=1 OR Joyb(0)=1

Format "00000"

;NOW SAVE THE PREFS
choose=RTEZRequest("AnalogJoyPrefs","Calibration Complete","SAVE|USE|CANCEL")

If choose=1
  If Exists("ENVARC:")
    If Exists("ENVARC:AnalogJoy.prefs")
      KillFile("ENVARC:AnalogJoy.prefs")
    EndIf
    If WriteFile(0,"ENVARC:AnalogJoy.prefs")
      FileOutput 0
      Gosub write_data
      CloseFile 0
      DefaultOutput
    EndIf
  EndIf
EndIf

If choose<>0
  If Exists("ENV:")
    If Exists("ENV:AnalogJoy.prefs")
      KillFile("ENV:AnalogJoy.prefs")
    EndIf
    If WriteFile(0,"ENV:AnalogJoy.prefs")
      FileOutput 0
      Gosub write_data
      CloseFile 0
      DefaultOutput
    EndIf
  EndIf
EndIf
Use Window 0
InnerCls


Gosub write_data

MouseWait
End


;What follows is the proposed stanard for files
;related to analogue joysticks

;look at accompanying docs for more info on the standard


.write_data
  NPrint "ANALOGJOYPREFS"
  NPrint "1.0"
  NPrint "TYPE"
  NPrint "STANDARD_PORT1"
  NPrint "CX"
  NPrint cx
  NPrint "CY"
  NPrint cy
  NPrint "MX"
  NPrint mx
  NPrint "MY"
  NPrint my
  NPrint "NX"
  NPrint nx
  NPrint "NY"
  NPrint ny
  NPrint "END"

Return

.Appendix

;Appendix
;--------



;Standard code for analog Joys using above var names
;---------------------------------------------------
;(NOTE: CODE UNTESTED)


;InitBank(0,32,65536)
;BuffOffset.b=14
;JoyBuff.l=Bank(0)   ;location of the joybuffer
;avx.w=0
;avy.w=0
;
;SetInt 5
;  GetReg a0,JoyxBuff     ;this asm code implements a continuous
;                         ;average using a small buffer and a pointer
;  GetReg d2,BuffOffset   ;to store the temporary data
;
;  GetReg d3,avx
;  GetReg d4,avy
;
;
;  CLR.w d0                ;clear those so that we can
;  CLR.l d1                ;do word addition later
;
;  MOVE.w $dff014,d0       ;get Port1 POT
;  MOVE.b d0,d1            ;move lower byte (X) to d1
;  LSR.w #8,d0             ;shift 8 - now Y is in lower byte
;  MOVE.b #1,$dff034       ;dump the capacitors!
;
;  SUB.w (a0,d2.b),d3      ;sub the last values
;  SUB.w 16(a0,d2.b),d4    ;in the queue
;
;  MOVE.w d1,(a0,d2.b)     ;place the new values in the queue
;  ADD.w d1,d3             ;and add them
;  MOVE.w d0,16(a0,d2.b)   ;code slightly optimized for pipelining :) -yeah
;  ADD.w d0,d4
;
;  SUBI.b #2,d2              ;decrease counter
;  BGE end_read_loop         ;alternatively use:
;  MOVE.b #14,d2             ;ADDI.b #2,d2:AND.b #15,d2
;
;end_read_loop:
;
;  PutReg d3,avx             ;put things back so we can read them again
;  PutReg d4,avy
;  PutReg d2,BuffOffset
;
;End SetInt
;
;xx+x
;rx.w=xx-cx
;ry.w=yy-cy
;
;If rx>0 Then Cfx=mx Else Cfx=-nx
;If ry>0 Then Cfy=my Else Cfy=-ny
;
;CalX=10*rx/Cfx
;CalY=10*ry/Cfy

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



