Files
2025-09-29 00:52:08 +02:00

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