-- 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