534 lines
18 KiB
Plaintext
Executable File
534 lines
18 KiB
Plaintext
Executable File
-- Takes a selected joystick and links it to bone
|
|
-- Rick Stirling
|
|
-- January 2009
|
|
|
|
-- This evolved from the facecontroller script, but that used Wire Parameters. This script uses Float Expressions instead.
|
|
-- July 2009: Tidy up, bug fixing added more comments. Script now supports Zero'd and non zero bones.
|
|
-- 1st August 2009: Creates joystick arrays, clamps for creating animated normal sliders. Added error checking
|
|
-- 19 August 2009: R* Toronto Creates 16 sliders. Layout new sliders in columns and rows. Zero padded numbering extension of sliders.
|
|
-- August 2011. Rick Stirling. , moved to new Wildwest, renamed Slider_toolkit.
|
|
|
|
-- Load the useful Functions
|
|
|
|
-- This line loads the custom header
|
|
filein (RsConfigGetWildWestDir() + "script/3dsMax/_config_files/Wildwest_header.ms")
|
|
|
|
sliderToolkit = undefined --declare the rollout so we can destroy it
|
|
|
|
-- We need to gather scene information
|
|
fullbonelist=#()
|
|
fullbonelistname=#()
|
|
fullcontrollerlist=#()
|
|
fullcontrollerlistname=#()
|
|
activebonelist=#()
|
|
activebonelistname=#()
|
|
activecontrollerlist=#()
|
|
activecontrollerlistname=#()
|
|
initialdotproduct=#()
|
|
|
|
defaultSliderScreenPos = [1,0,2]
|
|
|
|
|
|
-- Define a struct as a container for the bone and slider data.
|
|
struct boneSliderStruct
|
|
(
|
|
BoneObject = undefined,
|
|
BoneControlType = undefined,
|
|
BoneAxis = undefined,
|
|
SliderObject = undefined,
|
|
SliderControlType = undefined,
|
|
SliderAxis = undefined,
|
|
DriverObject = undefined,
|
|
Limit1 = undefined,
|
|
Limit2 = undefined,
|
|
sliderFlipToggle = undefined,
|
|
RotationFlipToggle = undefined,
|
|
ZeroBoneBool = undefined
|
|
)
|
|
|
|
|
|
|
|
fn DisconnectSelected obj =
|
|
(
|
|
-- Objects with Zero'd rotations
|
|
try (obj.rotation.controller.Zero_Euler_XYZ.controller.X_Rotation.controller = bezier_float ()) catch()
|
|
try (obj.rotation.controller.Zero_Euler_XYZ.controller.Y_Rotation.controller = bezier_float ()) catch()
|
|
try (obj.rotation.controller.Zero_Euler_XYZ.controller.Z_Rotation.controller = bezier_float ()) catch()
|
|
|
|
-- Objects with non Zero'd rotations
|
|
try (obj.rotation.controller.X_Rotation.controller = bezier_float () )catch()
|
|
try (obj.rotation.controller.Y_Rotation.controller = bezier_float () )catch()
|
|
try (obj.rotation.controller.Z_Rotation.controller = bezier_float () )catch()
|
|
|
|
|
|
-- Translation on sliders
|
|
-- Don't disconnect any float limits
|
|
-- This is a bit hacky at the minute
|
|
try (ctx = obj.pos.controller.X_Position.controller as string)catch()
|
|
try (cty = obj.pos.controller.Y_Position.controller as string)catch()
|
|
try (ctz = obj.pos.controller.Z_Position.controller as string)catch()
|
|
|
|
try (ctx = obj.pos.controller.Zero_Pos_XYZ.controller.X_Position.controller as string)catch()
|
|
try (cty = obj.pos.controller.Zero_Pos_XYZ.controller.Y_Position.controller as string)catch()
|
|
try (ctz = obj.pos.controller.Zero_Pos_XYZ.controller.Z_Position.controller as string)catch()
|
|
|
|
if ctx != "Controller:Float_Limit" then try (obj.pos.controller.X_Position.controller = bezier_float ()) catch()
|
|
if cty != "Controller:Float_Limit" then try (obj.pos.controller.Y_Position.controller = bezier_float ()) catch()
|
|
if ctz != "Controller:Float_Limit" then try (obj.pos.controller.Z_Position.controller = bezier_float ()) catch()
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Populate the bone and controller arrays
|
|
-- Parses the scene looking for sliders and bones
|
|
fn gathersceneinfo =
|
|
(
|
|
|
|
-- Clear all the arrays
|
|
fullbonelist=#()
|
|
fullbonelistname=#()
|
|
|
|
fullcontrollerlist=#()
|
|
fullcontrollerlistname=#()
|
|
|
|
activebonelist=#()
|
|
activebonelistname=#()
|
|
|
|
activecontrollerlist=#()
|
|
activecontrollerlistname=#()
|
|
|
|
-- Generate a list of all the bones in the scene
|
|
for obj in geometry do
|
|
(
|
|
if (classof obj == BoneGeometry) then
|
|
(
|
|
append fullbonelist obj
|
|
append fullbonelistname obj.name
|
|
)
|
|
)
|
|
|
|
-- Adds point helpers to the bone list
|
|
for obj in helpers do
|
|
(
|
|
if (classof obj == Point ) then
|
|
(
|
|
append fullbonelist obj
|
|
append fullbonelistname obj.name
|
|
)
|
|
)
|
|
|
|
-- Generate a list of all the controllers in the scene
|
|
for obj in shapes do
|
|
(
|
|
if (classof obj == Circle) then
|
|
(
|
|
append fullcontrollerlist obj
|
|
append fullcontrollerlistname obj.name
|
|
)
|
|
)
|
|
|
|
|
|
-- Make those full lists active
|
|
activecontrollerlist=fullcontrollerlist as array
|
|
activecontrollerlistname=fullcontrollerlistname as array
|
|
activebonelist=fullbonelist as array
|
|
activebonelistname=fullbonelistname as array
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
fn radioToXYZ numericalAxis =
|
|
(
|
|
XYZAxis = undefined
|
|
case numericalAxis of
|
|
(
|
|
1: XYZAxis = "X"
|
|
2: XYZAxis = "Y"
|
|
3: XYZAxis = "Z"
|
|
4: XYZAxis = "XYZ"
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
if ((sliderToolkit != undefined) and (sliderToolkit.isDisplayed)) do
|
|
(destroyDialog sliderToolkit)
|
|
|
|
|
|
rollout sliderToolkit "Slider Toolkit"
|
|
(
|
|
hyperlink lnkHelp "Help?" address:"https://devstar.rockstargames.com/wiki/index.php/Slider_Toolkit" align:#right color:(color 20 20 255) hoverColor:(color 255 255 255) visitedColor:(color 0 0 255)
|
|
|
|
Edittext edtSliderName "Slider Name: " pos:[10,35] width:220
|
|
RadioButtons rbtnSliderType labels:#("Square", "Vertical", "Horizontal") default:2 pos:[30,70]
|
|
|
|
Button btnCreateSlider "Create Slider" width:100 height:28 pos:[250,30]
|
|
|
|
Button btnCreate16Sliders "Create 16 Sliders" width:100 height:28 pos:[250,65]
|
|
|
|
button btnGrabController "Select" width:50 height:20 pos:[10,125]
|
|
dropdownlist ddlSliderList "Choose Slider and Effect Axis" items:#("") width:120 pos:[65,105]
|
|
radiobuttons rbtnSliderAxis labels:#("Left/Right","Up/Down") pos:[220,125] default:2
|
|
button btnGrabBone "Select" width:50 height:20 pos:[10,175]
|
|
dropdownlist ddlBoneList "Choose Bone" items:#("") width:120 pos:[65,155]
|
|
checkbox chkControlFlip "Invert controller effect" pos:[220,150]
|
|
checkbox chkZeroflag "Zero'd Bone" pos:[220,175] checked:true
|
|
|
|
|
|
groupBox grp1 "Rotation (degrees)" pos:[10,200] width:170 height:210
|
|
groupBox grp2 "Translation (cm)" pos:[200,200] width:170 height:210
|
|
|
|
|
|
-- Rotation interface
|
|
radiobuttons rbtnBoneAxis labels:#("Bone X","Bone Y","Bone Z") pos:[40,220] default:3 columns:1
|
|
spinner spnAngleLimit1 "Angle Limit 1" range:[0,180,30] type:#integer pos:[80,280] width:60
|
|
spinner spnAngleLimit2 "Angle Limit 2" range:[0,180,30] type:#integer pos:[80,300] width:60
|
|
checkbox chkRotationFlip "Flip rotation " pos:[40,330]
|
|
button btnSliderDrivesBoneR "Slider Drives Bone Rotation" pos:[20,350] width:150 height:25
|
|
button btnBoneDrivesSliderR "Bone Rotation Drives Slider " pos:[20,380] width:150 height:25
|
|
|
|
|
|
-- Translation interface
|
|
radiobuttons rbtnTboneAxis labels:#("Bone X","Bone Y","Bone Z") pos:[225,220] default:1 columns:1
|
|
spinner spnTransLimit1 "Move Limit (cm)" range:[0,10,1] type:#float pos:[275,300] width:60
|
|
button btnnull1 "*nothing yet*" pos:[210,350] width:150 height:25
|
|
button btnnull2 "*nothing yet*" pos:[210,380] width:150 height:25
|
|
|
|
|
|
button btnResetAllControls "Reset All Controllers" pos:[10,420] width:110 height:30
|
|
button btnReevaluateScene "Reevaluate Scene" pos:[130,420] width:110 height:30
|
|
button btnDisconnectSelected "Disconnect Selected" pos:[250,420] width:110 height:30
|
|
|
|
--button BresetControllers "Re-centre Controllers" width:145 height:25
|
|
--button BunwireController "Unwire selected" width:145 height:25
|
|
|
|
|
|
|
|
-- When the script is ran, we need to do some setup.
|
|
on rigcontrollers open do
|
|
(
|
|
-- populate the dropdown boxes
|
|
-- Use 'English' names and not actual max object names
|
|
|
|
gathersceneinfo()
|
|
ddlBoneList.items = activebonelistname
|
|
ddlSliderList.items = activecontrollerlistname
|
|
|
|
-- Fill the dotproduct array. This was suggested by Luke Openshaw for bone orientation
|
|
for i = 1 to activebonelist.count do
|
|
(
|
|
wiredvector = in coordsys world activebonelist[i].transform.row2
|
|
wdp = dot [0,-1,0] wiredvector -- Shouldn't be more than 0.0
|
|
append initialdotproduct wdp
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
-- A general function to create the given number of sliders.
|
|
-- Only does a special layout if there are 16 sliders.
|
|
fn createSlider sliderCount = (
|
|
-- call the joystick creation function with the UI data
|
|
jstemp = edtSliderName.text as string
|
|
jsname = replacespace jstemp
|
|
jstyle = rbtnSliderType.state as integer
|
|
jpos = defaultSliderScreenPos -- the default position on screen. This can overridden later, perhaps by mouse click.
|
|
|
|
eighthSliderCount = 2
|
|
quarterSliderCount = eighthSliderCount * 2
|
|
halfSliderCount = eighthSliderCount * 4
|
|
threeQuarterSliderCount = eighthSliderCount * 6
|
|
if sliderCount == 1 then (
|
|
-- Create a joystick slider and select it
|
|
seljoy = createJoystick jsname jstyle jpos 1 -- This can also be copied and pasted to a script to auto build a controller
|
|
)
|
|
else (
|
|
-- Create several sliders and select them
|
|
sliderarray= #()
|
|
|
|
for sc = 0 to (sliderCount-1) do (
|
|
|
|
-- Figure out the positional offset
|
|
posmod = [0,0,0]
|
|
if ( (jstyle == 1) or (jstyle == 2) ) then (
|
|
if ( sliderCount != 16 ) then (
|
|
posmod = [(sc*0.2), 0, 0]
|
|
) else (
|
|
-- Divide the vertical sliders into 2 rows and offset the second row below the first.
|
|
if ( sc < halfSliderCount ) then (
|
|
if ( (sliderCount == 16) and (sc < quarterSliderCount) )then (
|
|
posmod = [(sc*0.2), 0, 0]
|
|
) else (
|
|
posmod = [(sc*0.2) + 0.1, 0, 0]
|
|
)
|
|
) else (
|
|
if ( (sliderCount == 16) and (sc < threeQuarterSliderCount) ) then (
|
|
posmod = [((sc-halfSliderCount)*0.2), 0, -0.3]
|
|
) else (
|
|
posmod = [((sc-halfSliderCount)*0.2) + 0.1, 0, -0.3]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
if jstyle == 3 then (
|
|
-- Divide the horizontal sliders into 2 columns and offset the second column to the right of the first.
|
|
if ( sliderCount != 16 ) then (
|
|
posmod = [0, 0, -(sc*0.1)]
|
|
) else (
|
|
if ( sc < 8 ) then (
|
|
if ( sc < 4 ) then (
|
|
if ( sc < 2 ) then (
|
|
posmod = [(sc*0.2), 0, 0]
|
|
) else (
|
|
posmod = [(sc*0.2) - 0.4, 0, -0.1]
|
|
)
|
|
) else (
|
|
if ( sc < 6 ) then (
|
|
posmod = [(sc*0.2) - 0.3, 0, 0]
|
|
) else (
|
|
posmod = [(sc*0.2) - 0.4 - 0.3, 0, -0.1]
|
|
)
|
|
)
|
|
) else (
|
|
if ( sc < 12 ) then (
|
|
if ( sc < 10 ) then (
|
|
posmod = [(sc*0.2) - 1.6, 0, -0.3]
|
|
) else (
|
|
posmod = [(sc*0.2) - 0.4 - 1.6, 0, -0.3 - 0.1]
|
|
)
|
|
) else (
|
|
if ( sc < 14 ) then (
|
|
posmod = [(sc*0.2) - 1.9, 0, -0.3]
|
|
) else (
|
|
posmod = [(sc*0.2) - 0.4 - 1.9, 0, -0.3 - 0.1]
|
|
)
|
|
)
|
|
)
|
|
)
|
|
)
|
|
|
|
|
|
ext = formattedPrint sc format:"03d"
|
|
seljoy = createJoystick (jsname + "-" + ext as string) jstyle (jpos + posmod) 1 -- This can also be copied and pasted to a script to auto build a controller
|
|
|
|
myJS = getnodebyname (jsname + "-" + ext as string)
|
|
append sliderarray myJS
|
|
)
|
|
select sliderarray
|
|
|
|
|
|
)
|
|
|
|
gathersceneinfo()
|
|
ddlBoneList.items = activebonelistname
|
|
ddlSliderList.items = activecontrollerlistname
|
|
|
|
-- select $.parent
|
|
)
|
|
|
|
|
|
-- Create a new slider
|
|
on btnCreateSlider pressed do createSlider(1)
|
|
|
|
|
|
-- Create 16 new sliders, forcing the spinner count to be 16.
|
|
on btnCreate16Sliders pressed do createSlider(16)
|
|
|
|
|
|
-- Allow the user to choose the controller from the scene as well as the dropdown
|
|
on btnGrabController pressed do (
|
|
|
|
objSelectedArray = getCurrentSelection()
|
|
selectedobj = objSelectedArray[1]
|
|
|
|
if selectedobj != undefined then (
|
|
|
|
-- Is it a rectangle? If so try to select the circle child
|
|
if (substring selectedobj.name 1 7) == "JSBbox_" then (
|
|
for c = 1 to selectedobj.children.count do (if classof selectedobj.children[c] == Circle then selectedobj = selectedobj.children[c])
|
|
)
|
|
|
|
-- Is it a circle?
|
|
if classof selectedobj == Circle then (
|
|
matchpos = 0
|
|
for i = 1 to activecontrollerlistname.count do (if activecontrollerlistname[i] == selectedobj.name then matchpos = i)
|
|
|
|
-- Set the dropdown box to be the controller if possible
|
|
if matchpos > 0 then ddlSliderList.selection = matchpos
|
|
)
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
on btnGrabBone pressed do
|
|
(
|
|
-- Let the user pick the bone by selecting it in the scene
|
|
objSelectedArray = getCurrentSelection()
|
|
selectedobj = objSelectedArray[1]
|
|
|
|
-- Is it a bone
|
|
if classof selectedobj == BoneGeometry then
|
|
(
|
|
matchpos = 0
|
|
for i = 1 to activebonelistname.count do (if activebonelistname[i] == selectedobj.name then matchpos = i)
|
|
|
|
-- Set the dropdown box to be the controller.
|
|
if matchpos > 0 then ddlBoneList.selection = matchpos
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
-- Bone rotation drives a slider
|
|
on btnBoneDrivesSliderR pressed do
|
|
(
|
|
-- Create and populate the struct
|
|
boneSliderData = boneSliderStruct()
|
|
|
|
-- fill in the main details from the UI
|
|
boneSliderData.BoneObject = activebonelist[sliderToolkit.ddlboneList.selection]
|
|
boneSliderData.BoneAxis = (radioToXYZ sliderToolkit.rbtnBoneAxis.state)
|
|
|
|
boneSliderData.SliderObject = activecontrollerlist[sliderToolkit.ddlsliderList.selection]
|
|
boneSliderData.SliderAxis = (radioToXYZ sliderToolkit.rbtnSliderAxis.State)
|
|
|
|
boneSliderData.sliderFlipToggle = sliderToolkit.chkControlFlip.state
|
|
boneSliderData.RotationFlipToggle = sliderToolkit.chkRotationFlip.state
|
|
boneSliderData.ZeroBoneBool = sliderToolkit.chkzeroflag.state
|
|
|
|
-- Set the correct stuff for this function
|
|
boneSliderData.DriverObject = activebonelist[sliderToolkit.ddlboneList.selection] -- Bone Drives the slider in this function
|
|
boneSliderData.BoneControlType = "R" -- Rotation in this function
|
|
boneSliderData.SliderControlType = "T" -- Always translate sliders
|
|
|
|
-- Angles
|
|
boneSliderData.Limit1 = sliderToolkit.spnAngleLimit1.value
|
|
boneSliderData.Limit2 = sliderToolkit.spnAngleLimit2.value
|
|
|
|
|
|
resetControllers activecontrollerlist -- just to be sure, reset all the controllers to 0
|
|
|
|
-- Call the connection function with this sdata
|
|
FECBoneSliderConnect boneSliderData
|
|
)
|
|
|
|
|
|
-- Bone rotation drives a slider
|
|
on btnSliderDrivesBoneR pressed do
|
|
(
|
|
-- Create and populate the struct
|
|
boneSliderData = boneSliderStruct()
|
|
|
|
-- fill in the main details from the UI
|
|
boneSliderData.BoneObject = activebonelist[sliderToolkit.ddlboneList.selection]
|
|
boneSliderData.BoneAxis = (radioToXYZ sliderToolkit.rbtnBoneAxis.state)
|
|
|
|
boneSliderData.SliderObject = activecontrollerlist[sliderToolkit.ddlsliderList.selection]
|
|
boneSliderData.SliderAxis = (radioToXYZ sliderToolkit.rbtnSliderAxis.State)
|
|
|
|
boneSliderData.sliderFlipToggle = sliderToolkit.chkControlFlip.state
|
|
boneSliderData.RotationFlipToggle = sliderToolkit.chkRotationFlip.state
|
|
boneSliderData.ZeroBoneBool = sliderToolkit.chkzeroflag.state
|
|
|
|
-- Set the correct stuff for this function
|
|
boneSliderData.DriverObject = activecontrollerlist[sliderToolkit.ddlsliderList.selection] -- Slider drives the bone
|
|
boneSliderData.BoneControlType = "R" -- Rotation in this function
|
|
boneSliderData.SliderControlType = "T" -- Always translate sliders
|
|
|
|
|
|
-- Angles
|
|
boneSliderData.Limit1 = sliderToolkit.spnAngleLimit1.value
|
|
boneSliderData.Limit2 = sliderToolkit.spnAngleLimit2.value
|
|
|
|
|
|
resetControllers activecontrollerlist -- just to be sure, reset all the controllers to 0
|
|
|
|
-- Call the connection function with this sdata
|
|
FECBoneSliderConnect boneSliderData
|
|
)
|
|
|
|
|
|
|
|
|
|
on btnConnectBoneTrans pressed do
|
|
(
|
|
-- Call the functions in another file to set up expressions.
|
|
-- The Axis is a numberical code for axis
|
|
-- x=1, y=2, z=3, all=4
|
|
|
|
theBone = activebonelist[sliderToolkit.ddlboneList.selection]
|
|
theControl =activecontrollerlist[sliderToolkit.ddlsliderList.selection]
|
|
|
|
if chkControlFlip.state == true then sliderflip=1 else sliderflip = -1 --"Invert controller effect"
|
|
|
|
|
|
resetControllers activecontrollerlist -- just to be sure, reset all the controllers to 0
|
|
|
|
-- Link it up now
|
|
FECSliderToBone "T" theBone theControl rbtnTboneAxis.state rbtnSliderAxis.State spnTransLimit1.value 0 sliderflip chkzeroflag.state 0
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
on btnResetAllControls pressed do resetControllers activecontrollerlist
|
|
|
|
|
|
on btnReevaluateScene pressed do
|
|
(
|
|
gathersceneinfo()
|
|
ddlBoneList.items = activebonelistname
|
|
ddlSliderList.items = sort activecontrollerlistname
|
|
)
|
|
|
|
|
|
|
|
on btnDisconnectSelected pressed do
|
|
(
|
|
|
|
-- reset the controllers to default
|
|
resetControllers activecontrollerlist
|
|
|
|
-- set the expressions to bezier floats
|
|
DisconnectSelected $
|
|
-- $.rotation.controller.Zero_Euler_XYZ.controller.Z_Rotation.controller = bezier_float ()
|
|
--$.rotation.controller.Y_Rotation.controller = bezier_float ()
|
|
)
|
|
|
|
) -- rollout end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- Create floater
|
|
createDialog sliderToolkit width:380
|