// =========================================================================== // Copyright 2018 Autodesk, Inc. All rights reserved. // // Use of this software is subject to the terms of the Autodesk license // agreement provided at the time of installation or download, or which // otherwise accompanies this software in either electronic or hard copy form. // =========================================================================== // // // Creation Date: july 15, 1997 // // Procedure Name: // AEdynObjectGoalWeightNew // // Description Name; // Creates the controls for the multiAttr GoalWeight on the dynObject Node // // Input Value: // nodeName.attrName // // Output Value: // None // global proc dynSetStatus( int $status, string $nodeName, int $index ) { setAttr ($nodeName + ".goalActive[" + $index + "]") $status; } global proc AEdynObjectGoalWeightNew ( string $nodeAttr ) { string $buffer[]; tokenize($nodeAttr, ".", $buffer); string $nodeName = $buffer[0]; string $attrName = $buffer[1]; setUITemplate -pst attributeEditorTemplate; columnLayout ($attrName+"Column"); setParent ..; setUITemplate -ppt; AEdynObjectGoalWeightReplace $nodeAttr; } global proc addPerParticleGoalPointAttr( string $node, int $goalIndex, string $attrName, string $dataType ) // // Description: // // For particle shape node $node, adds a new per-particle // attribute representing some piece of data concerning // the goal points for the goal object whose index is // $goalIndex. The name of the data is $attrName, and // its type is given by $dataType. // // As an example, if the attribute name is "Position", // and the goal object index is 4, this function will // create an attribute called "goalPosition4PP". Its // values will contain the positions of the goal points // on goal object 4 to which particles in the given system // are being attracted. // // The function will also create a corresponding initial // attribute, formed by adding a "0" to the end of the attribute // name. This is to store an initial value for the attribute. // // Currently, the only attrs created this way are: // // goalWorldPositionPP // goalWorldNormalPP // goalWorldTangentUPP // goalWorldTangentVPP // // { string $attr = ("goal" + $attrName + $goalIndex + "PP"); string $initialAttr = ($attr+"0"); // add the attr // if( !`attributeQuery -ex -n $node $attr` ) { addAttr -ln $attr -dt $dataType $node; } // add the initial attr // if( !`attributeQuery -ex -n $node $initialAttr` ) { addAttr -ln $initialAttr -dt $dataType $node; } } global proc removePerParticleGoalPointAttr( string $node, int $goalIndex, string $attrName ) // // Description: // // Same as addPerParticleGoalAttr, but removes the specified // attribute and its initial attribute. // { string $attr = ("goal"+$attrName+$goalIndex+"PP"); string $initialAttr = ($attr+"0"); // remove the attr // if( `attributeQuery -ex -n $node $attr` ) { deleteAttr -at $attr $node; } // remove the corresponding initial attr // if( `attributeQuery -ex -n $node $initialAttr` ) { deleteAttr -at $initialAttr $node; } } global proc updatePerParticleGoalPointAttr( string $node, int $goalIndex, string $attrName, string $dataType, string $buttonName ) // // Description: // // Updates the button in the Attribute Editor that lets users create or // delete a particular per-particle goal-related attribute. If the // attribute exists, the button should delete the attribute, and if the // attribute does not exist, the button should create it. // // $node is the particle shape whose AE we are updating, $goalIndex // is the index of the goal object in the sparse goalGeometry array on // that object. $attrName is the root name of the per-particle attribute // being modified ($attrName="WorldPosition" corresponds to the attribute // "goalWorldPositionPP"), $dataType is the data type of the attribute // (usually "doubleArray" or "vectorArray", and $buttonName is the name // of the actual control responsible for performing the addition/deletion. // { string $ppGoalPointAttr = ("goal"+$attrName+$goalIndex+"PP"); string $ppGoalPointNice = `uiRes( "n_particle.a_goal" + $attrName + "#PP_niceName" )`; $ppGoalPointNice = substitute( "#", $ppGoalPointNice, string( $goalIndex ) ); if( `attributeQuery -ex -n $node $ppGoalPointAttr` ) { // if the attribute exists, the button should delete it // string $fmt = (uiRes("m_AEdynObjectGoalWeightNew.kDelete")); $label = `format -s $ppGoalPointNice $fmt`; $command = ("removePerParticleGoalPointAttr " + $node + " " + $goalIndex + " " + $attrName); button -e -l $label -c $command $buttonName; } else { // if the attribute does not exist, the button should add it // string $fmt = (uiRes("m_AEdynObjectGoalWeightNew.kCreate")); $label = `format -s $ppGoalPointNice $fmt`; $command = ("addPerParticleGoalPointAttr " + $node + " " + $goalIndex + " " + $attrName + " " + $dataType); button -e -l $label -c $command $buttonName; } } global proc updateGoalWeight( string $node, int $goalIndex, string $weightSlider, string $ppWeightButton ) // // Description: // // Slightly more specialized version of updatePerParticleGoalPointAttr, // customized for the goalWeightPP attribute. When this attribute is // created, the per-object goal weight slider for the specified goal // object must be dimmed, so we need some extra code. // { string $ppGoalAttr = ("goalWeight"+$goalIndex+"PP"); string $ppGoalNice = `uiRes "n_particle.a_goalWeight#PP_niceName"`; $ppGoalNice = substitute( "#", $ppGoalNice, string( $goalIndex ) ); if( `attributeQuery -ex -n $node $ppGoalAttr` ) { // per-particle goal weight attr exists, so dim the per-object weight // slider, and set the button up to delete the attribute // string $fmt = (uiRes("m_AEdynObjectGoalWeightNew.kDelete2")); $label = `format -s $ppGoalNice $fmt`; $command = ("removePerParticleGoalPointAttr " + $node + " " + $goalIndex + " Weight "); button -e -l $label -c $command $ppWeightButton; string $oldParent = `setParent -q`; setParent $weightSlider; control -e -en 0 "AFGfield"; control -e -en 0 "AFGslider"; setParent $oldParent; //attrFieldSliderGrp -e -en 0 ($weightSlider + "|AFGfield"); //attrFieldSliderGrp -e -en 0 ($weightSlider + "|AFGslider"); } else { // per-particle goal weight attr does not exist, so enable the per-object // goal weight slider, and set the button up to create the per-particle // weight attr. // string $fmt = (uiRes("m_AEdynObjectGoalWeightNew.kCreate2")); $label = `format -s $ppGoalNice $fmt`; $command = ("addPerParticleGoalPointAttr " + $node + " " + $goalIndex + " Weight " + " doubleArray "); button -e -l $label -c $command $ppWeightButton; string $oldParent = `setParent -q`; setParent $weightSlider; control -e -en 1 "AFGfield"; control -e -en 1 "AFGslider"; setParent $oldParent; //attrFieldSliderGrp -e -en 1 ($weightSlider + "|AFGfield"); //attrFieldSliderGrp -e -en 1 ($weightSlider + "|AFGslider"); } } global proc AEdynObjectGoalWeightReplace ( string $nodeAttr ) { // bring in the procedures for managing uv dropdown boxes // (for polymesh goal objects) // uvControlUtils(); string $buffer[]; tokenize($nodeAttr, ".", $buffer); string $nodeName = $buffer[0]; // Since both particle nodes and nParticle nodes build their Attribute // Editor templates via this call, we need unique names to distinguish the // two. Use the nodeType as the prefix. // string $prefix = `nodeType $nodeName`; string $attrName = $buffer[1]; string $goalNames[] = `goal -q -g $nodeName`; int $goalIndices[] = `goal -q -i $nodeName`; string $columnName = $attrName + "Column"; setUITemplate -pst attributeEditorTemplate; if (!`columnLayout -ex $columnName`) { setUITemplate -pst attributeEditorTemplate; columnLayout $columnName; setUITemplate -ppt; } setParent $columnName; $layoutName=`setParent -q`; // $numSetsExisting is used to delete any controls that are not being // re-used, which will happen if the number of goals of the new particle // in the editor is less than that of the previous particle. So first, // we find out how many children (controls) are now in the layout. // int $numSetsExisting = `columnLayout -q -nch $layoutName`; // We have to remove from consideration in deleting unused controls the // first control, "goalSmoothness", which is always there. But also, we // delete two at a time, so we want half the number of unused controls for // the loop counter. // if ($numSetsExisting > 0) $numSetsExisting = ($numSetsExisting - 1) / 2; // The controls will be: an attrFieldSliderGrp for each // goal + weight -- the name of the goal object is the label // of the slider field, and the weight applied to that goal // object is the value in the slider field. // string $smoothness = (uiRes("m_AEdynObjectGoalWeightNew.kGoalSmoothness")) ; string $fieldName = $prefix + "pGoalSmoothness"; if (`attrFieldSliderGrp -ex $fieldName`) { attrFieldSliderGrp -e -label $smoothness -min 0.0 -s 0.1 -at ($nodeName + ".goalSmoothness") $fieldName; } else { setUITemplate -pst attributeEditorTemplate; attrFieldSliderGrp -label $smoothness -min 0.0 -s 0.1 -at ($nodeName + ".goalSmoothness") $fieldName; separator; setUITemplate -ppt; } // root names of per-particle goal attributes. // string $goalPointAttrs[] = { "Weight", "WorldPosition", "WorldNormal", "WorldTangentU", "WorldTangentV" }; string $goalPointAttr_niceNames[] = { (uiRes("m_AEdynObjectGoalWeightNew.kGoalWeightsPP")), (uiRes("m_AEdynObjectGoalWeightNew.kGoalPointPositions")), (uiRes("m_AEdynObjectGoalWeightNew.kGoalPointNormals")), (uiRes("m_AEdynObjectGoalWeightNew.kGoalPointTangentUs")), (uiRes("m_AEdynObjectGoalWeightNew.kGoalPointTangentVs")) }; int $i; for ($i = 0; $i < size($goalNames); $i++) { $sliderLabel = $goalNames[$i]; // Index i here is not correct because goals may not be // consecutive in the multi. Need to get the index from // the shape. // $fullAttrName = $nodeName + ".goalWeight[" + $goalIndices[$i] + "]"; $sliderName = $prefix+"goalWeight" + $i; string $checkBoxName = "goalActive" + $i; string $uvSetName = "goalUVSet" + $i; string $sepName = "goalSeparator" + $i; int $goalIndex = $goalIndices[$i]; string $ppGoalWeightAttr = ("goalWeight"+$goalIndex+"PP"); int $status = `getAttr ($nodeName + ".goalActive[" + $goalIndices[$i] + "]") `; if (`attrFieldSliderGrp -ex $sliderName`) { attrFieldSliderGrp -e -l $sliderLabel -min 0.0 -max 1.0 -s 0.1 -at $fullAttrName $sliderName; checkBoxGrp -e -v1 $status -on1 ("dynSetStatus 1 " + $nodeName + " " + $goalIndices[$i]) -of1 ("dynSetStatus 0 " + $nodeName + " " + $goalIndices[$i]) $checkBoxName; // update the uv set dropdown to reflect the current goal object. // The list of available uv sets is updated, as well as the currently // selected uv set. If the goal object is not a polymesh, the menu // will be hidden. // string $uvMenu = uvsControl( "replace", $nodeName, "goal", $goalIndex, $uvSetName ); int $polyGoal = uvsIsDynPoly( $nodeName, "goal", $goalIndex ); optionMenuGrp -e -m $polyGoal $uvMenu; } else { setUITemplate -pst attributeEditorTemplate; attrFieldSliderGrp -l $sliderLabel -min 0.0 -max 1.0 -s 0.1 -at $fullAttrName $sliderName; checkBoxGrp -label (uiRes("m_AEdynObjectGoalWeightNew.kGoalActive")) -ncb 1 -l1 "" -v1 $status -on1 ("dynSetStatus 1 " + $nodeName + " " + $goalIndices[$i]) -of1 ("dynSetStatus 0 " + $nodeName + " " + $goalIndices[$i]) $checkBoxName; // // Build the buttons that will allow users to add per-particle // attributes corresponding to a particular goal object. // global int $gTextColumnWidthIndex; int $a; for( $a = 0; $a < size($goalPointAttrs); $a++ ) { string $pa = $goalPointAttrs[$a]; string $ppGoalLayoutString = "ppGoal"+$pa+"Layout"+$i; string $ppGoalTextString = "ppGoal"+$pa+"Text"+$i; string $ppGoalButtonString = "ppGoal"+$pa+"Button"+$i; rowLayout -nc 2 -columnWidth 1 $gTextColumnWidthIndex -columnWidth 2 200 -columnAttach 2 both 0 -columnAttach 1 right 5 $ppGoalLayoutString; text -l $goalPointAttr_niceNames[$a] $ppGoalTextString; button -h 15 $ppGoalButtonString; setParent ..; } // create the uv set menu to allow users to select which uv set // to use on the goal object for dynamics calculations (like per-particle // goalU/goalV values). // string $uvMenu = uvsControl( "create", $nodeName, "goal", $goalIndex, $uvSetName ); int $polyGoal = uvsIsDynPoly( $nodeName, "goal", $goalIndex ); optionMenuGrp -e -m $polyGoal $uvMenu; separator $sepName; setUITemplate -ppt; } // // Update the per-particle goal point attributes, to make sure the // AE buttons properly reflect the presence or absence of the // attributes // string $pa; for( $pa in $goalPointAttrs ) { string $ppGoalButtonString = "ppGoal"+$pa+"Button"+$i; if( $pa == "Weight" ) { updateGoalWeight( $nodeName, $goalIndex, $sliderName, $ppGoalButtonString ); } else { // special handling for goalWeightPP attribute // updatePerParticleGoalPointAttr( $nodeName, $goalIndex, $pa, "vectorArray", $ppGoalButtonString ); } } } for ($i = size($goalNames); $i < $numSetsExisting; $i++) { $sliderName = $prefix + "goalWeight" + $i; string $checkBoxName = "goalActive" + $i; if (`attrFieldSliderGrp -ex $sliderName` ) { deleteUI $sliderName; } $checkBoxName = "goalActive" + $i; if (`checkBoxGrp -ex $checkBoxName`) { deleteUI $checkBoxName; } // // delete controls for per-particle goal point attributes // string $pa; for( $pa in $goalPointAttrs ) { string $ppGoalLayoutString = "ppGoal"+$pa+"Layout"+$i; string $ppGoalTextString = "ppGoal"+$pa+"Text"+$i; string $ppGoalButtonString = "ppGoal"+$pa+"Text"+$i; if( `rowLayout -ex $ppGoalLayoutString` ) { deleteUI $ppGoalLayoutString; } if( `text -ex $ppGoalTextString` ) { deleteUI $ppGoalTextString; } if( `button -ex $ppGoalButtonString` ) { deleteUI $ppGoalButtonString; } } string $uvSetName = "goalUVSet" + $i; if ( `optionMenuGrp -ex $uvSetName` ) { deleteUI $uvSetName; } string $goalSepName = "goalSeparator" + $i; if( `separator -ex $goalSepName` ) { deleteUI $goalSepName; } } setParent ..; setUITemplate -ppt; }