@startuml
skinparam packageStyle rectangle
/' Nodes '/
/'  analog driver and history '/
package driver_history_demux{
object vrpn_analog_driver
vrpn_analog_driver : DriverSensor
vrpn_analog_driver : driver = XBOXCONTROLLER
vrpn_analog_driver : sensor = 0
vrpn_analog_driver : type = ANALOG

object vrpn_analog_data
vrpn_analog_data : HistoryProject
vrpn_analog_data : project (VALUE, CHANNELS)

/'  button driver and history '/
object vrpn_button_driver
vrpn_button_driver : DriverSensor
vrpn_button_driver : driver = XBOXCONTROLLER
vrpn_button_driver : sensor = 0
vrpn_button_driver : type = BUTTON

object vrpn_button_data
vrpn_button_data : HistoryProject
vrpn_button_data : project >BTMASK, NUMBER, STATE<

/'      demux buttons '/
object btn_number_to_int
btn_number_to_int : TypeConvert[unsigned int,int]

object get_button
get_button : Demultiplex[unsigned int]
get_button : num_outports >14<
}

/'  cursor movement from buttons '/
package button_to_movement{
/'      convert to int '/
object up_to_int
up_to_int : TypeConvert[unsigned int,int]

object right_to_int
right_to_int : TypeConvert[unsigned int,int]

object down_to_int
down_to_int : TypeConvert[unsigned int,int]

object left_to_int
left_to_int : TypeConvert[unsigned int,int]

/'      calculate movement '/
object x_movement
x_movement : Substract[int]

object y_movement
y_movement : Substract[int]
}

/'  get viewport dimensions '/
package viewport_center{
object viewport
viewport : ViewportSource
viewport : value = MAIN_VIEWPORT

/'      divide by 2 for center point '/
object const_2
const_2 : ConstantValue[int]
const_2 : value = 2

object divide_viewport_width
divide_viewport_width : Divide[int]

object divide_viewport_height
divide_viewport_height : Divide[int]
}

package update_position{
/'  latest position values '/
object latest_xpos
latest_xpos : LatestUpdate[int]

object latest_ypos
latest_ypos : LatestUpdate[int]

/'  add movement to latest position '/
object add_xpos_xmove
add_xpos_xmove : Add[int]

object add_ypos_ymove
add_ypos_ymove : Add[int]
}

/'  limit values to stay inside viewport '/
package limit_position{
object const_0
const_0 : ConstantValue[int]
const_0 : value = 0

object lower_limit_xpos
lower_limit_xpos : Max[int]

object lower_limit_ypos
lower_limit_ypos : Max[int]

object upper_limit_xpos
upper_limit_xpos : Min[int]

object upper_limit_ypos
upper_limit_ypos : Min[int]
}

/'  values to 3dmouse '/
package 3dmouse_transform{
object 3dmouse
3dmouse : 3DMouseTransform
3dmouse : displaysystem = MAIN
3dmouse : viewport = MAIN_VIEWPORT
3dmouse : in_world_coordinates = FALSE
3dmouse : origin_offset_along_ray = 0

object 3dmouse_matrix
3dmouse_matrix : MatrixCompose

object intention_transform
intention_transform : SetTransform
intention_transform : object = SELECTION_NODE
}

/'  buttons to event sources '/
package button_to_event {
/'      buttons to bool '/
object a_to_bool
a_to_bool : TypeConvert[unsigned int,bool]

object b_to_bool
b_to_bool : TypeConvert[unsigned int,bool]

object x_to_bool
x_to_bool : TypeConvert[unsigned int,bool]

/'      detect button changes '/
object a_change_detect
a_change_detect : ChangeDetect[bool]

object b_change_detect
b_change_detect : ChangeDetect[bool]

object x_change_detect
x_change_detect : ChangeDetect[bool]

/'      event sources '/
object button_01
button_01 : EventSource

object button_02
button_02 : EventSource

object button_03
button_03 : EventSource
}

/' Edges '/
/'  button driver, history and demux '/
vrpn_button_driver "history" --> "history" vrpn_button_data
vrpn_button_data "NUMBER" --> "in" btn_number_to_int
btn_number_to_int "out" --> "select" get_button
vrpn_button_data "STATE" --> "value" get_button

/'  analog driver and history '/
vrpn_analog_driver "history" --> "history" vrpn_analog_data

/'  cursor movement from buttons '/
/'      convert to int '/
get_button "11" --> "in" right_to_int
get_button "13" --> "in" left_to_int
get_button "12" --> "in" down_to_int
get_button "10" --> "in" up_to_int

/'      right - left '/
right_to_int "out" --> "first" x_movement
left_to_int "out" --> "second" x_movement

/'      down - up '/
down_to_int "out" --> "first" y_movement
up_to_int "out" --> "second" y_movement

/'  get viewport center values '/
viewport "vp_w" --> "first" divide_viewport_width
const_2 "value" --> "second" divide_viewport_width

viewport "vp_h" --> "first" divide_viewport_height
const_2 "value" --> "second" divide_viewport_height

/' initial viewport center then last value '/
divide_viewport_width "out" --> "initial" latest_xpos
divide_viewport_height "out" --> "initial" latest_ypos

/'  add movement to latest position '/
latest_xpos "out" --> "first" add_xpos_xmove
x_movement "out" --> "second" add_xpos_xmove

latest_ypos "out" --> "first" add_ypos_ymove
y_movement "out" --> "second" add_ypos_ymove

/'  feedback results after limiting into latest value node '/
limit_position "xpos" --> "current" latest_xpos
limit_position "ypos" --> "current" latest_ypos

/'  limit values to stay within viewport '/
add_xpos_xmove "out" --> "first" lower_limit_xpos
const_0 "value" --> "second" lower_limit_xpos
lower_limit_xpos "out" --> "second" upper_limit_xpos
viewport "vp_w" --> "first" upper_limit_xpos

add_ypos_ymove "out" --> "first" lower_limit_ypos
const_0 "value" --> "second" lower_limit_ypos
lower_limit_ypos "out" --> "second" upper_limit_ypos
viewport "vp_h" --> "first" upper_limit_ypos

/'  values to 3dmouse '/
upper_limit_xpos "out" --> "x_pos" 3dmouse
upper_limit_ypos "out" --> "y_pos" 3dmouse

3dmouse "orientation" --> "orientation" 3dmouse_matrix
3dmouse "position" --> "translation" 3dmouse_matrix

3dmouse_matrix "out" --> "in" intention_transform

/'  buttons to event sources '/
get_button "0" --> "in" a_to_bool
get_button "1" --> "in" b_to_bool
get_button "2" --> "in" x_to_bool

a_to_bool "out" --> "in" a_change_detect
b_to_bool "out" --> "in" b_change_detect
x_to_bool "out" --> "in" x_change_detect

a_change_detect "out" --> "value" button_01
b_change_detect "out" --> "value" button_02
x_change_detect "out" --> "value" button_03




@enduml
