// =========================================================================== // 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: 1999 // // Procedure Name: // AElodGroupTemplate // // Description: // Creates the attribute editor controls for the joint Node // // Input Value: // nodeName // // Output Value: // None // // Procedure Name: // AElodGroupTemplate // // global proc updateMinMaxDistances( string $nodeName ) { string $nodeAttr = $nodeName + ".minMaxDistance"; int $dimMinMax = !(`getAttr $nodeAttr`); editorTemplate -dimControl $nodeName "minDistance" $dimMinMax; editorTemplate -dimControl $nodeName "maxDistance" $dimMinMax; } proc enableThresholdUI( string $nodeName, int $thresholdType, int $isOrtho ) // // Description: // Enable/disable threshold type switching. Workaround for MAYA-60899. // // Inputs: // $nodeName - lodGroup node name // $thresholdType - current/effective threshold type // $isOrtho - true if and only if current/effective camera is orthographic // { TODO( "BUG", "Threshold conversion with ortho camera not working", "MAYA-60899" ); // Now determine if we can switch between types. If the "other" type hasn't // been populated yet (i.e,. it has 0 entries, and we will automatically // populate it if a switch happens), or if it contains the same // number of entries, allow switching. In all other cases, there's a size // mismatch, and we don't know how to compensate for the missing or extra // entries, so don't allow switching. // string $thresholdAttr = $nodeName + ($thresholdType? ".percentageThreshold":".threshold"); int $maxThreshold = (1+(`getAttr -size $thresholdAttr`)); string $otherThresholdAttr = $nodeName + ($thresholdType? ".threshold":".percentageThreshold"); int $numOtherThreshold = `getAttr -size $otherThresholdAttr`; int $orthoDisabled = ( $isOrtho && ($numOtherThreshold == 0) ); int $canSwitch = ( ( ( $numOtherThreshold == 0 ) || ($numOtherThreshold == ($maxThreshold-1))) && !$orthoDisabled ); radioButtonGrp -e -enable $canSwitch -ann ($orthoDisabled?($thresholdType ? (uiRes("m_AElodGroupTemplate.kOrthoSwitchDisabled")) : (uiRes("m_AElodGroupTemplate.kSwitchDisabled")) ) : (uiRes("m_AElodGroupTemplate.kSwitch")) ) thresholdTypeBtn; } proc rebuildThresholdUI( string $useScreenHeightPercentage, int $thresholdType ) { string $attrName = `plugAttr $useScreenHeightPercentage`; string $nodeName = `plugNode $useScreenHeightPercentage`; setUITemplate -pst attributeEditorTemplate; // First, delete the old layout // string $columnLayout = ($attrName + "Column"); setParent $columnLayout; string $children[] = `columnLayout -query -childArray $columnLayout`; int $numChildren = size($children); if( $numChildren > 0 ){ string $cmd = "deleteUI "; for( $child in $children ){ $cmd += ($child + " "); } eval( $cmd ); } // Next, get the number of thresholds and levels // $displayAttr = $nodeName + ".displayLevel"; string $thresholdAttr = $nodeName + ($thresholdType? ".percentageThreshold":".threshold"); int $maxDisplay = `getAttr -size $displayAttr`; int $maxThreshold = (1+(`getAttr -size $thresholdAttr`)); string $conns[] = `listConnections ($nodeName+".cameraMatrix")`; if ( 0 < size($conns)) { enableThresholdUI( $nodeName, $thresholdType, `objectType -isType "fourByFourMatrix" $conns[0]` ); } // Initialize format strings // string $displayFmt = (uiRes("m_AElodGroupTemplate.kDisplay")); string $thresholdFmt = (uiRes("m_AElodGroupTemplate.kStartDistance")); if( $thresholdType ){ $thresholdFmt = (uiRes("m_AElodGroupTemplate.kStartPercentage")); } // Interleave thresholds & display levels, adding any un-matched entries // at the end, if necessary. // int $index = 0; int $maxIndex = $maxThreshold; if( $maxDisplay > $maxIndex ){ $maxIndex = $maxDisplay; } while( $index < $maxIndex ){ if( ($index > 0) && ($index < $maxThreshold)){ string $label = `format -s ($index) $thresholdFmt`; attrControlGrp -label $label -a ($thresholdAttr+"["+($index-1)+"]"); } if( $index < $maxDisplay ){ string $label = `format -s ($index) $displayFmt`; attrControlGrp -label $label -a ($displayAttr+"["+$index+"]"); } $index++; } setParent ..; setUITemplate -ppt; global string $gChannelBoxName; if( $gChannelBoxName != "" ){ // Now force channelBox to update // channelBox -e -update $gChannelBoxName; } } proc string getFirstCamera( string $transform ) // // Description: // Given a transform, return the first child camera, if any. // { string $camera; string $children[] = `listRelatives -children $transform`; int $numChildren = size($children); int $i = 0; while( $i < $numChildren ){ string $camera = $children[$i]; if( `objectType -isType "camera" $camera` ){ return $camera; } $i++; } // No camera found, return the empty string. // return ""; } proc string[] findMatrixConnection( string $matrixNode ) // // Description: // Given a 4x4 matrix, find the attr connected upstream, if any. If // found, return both that attr, and the node to which it is connected. // { string $results[]; if( !`objectType -isType "fourByFourMatrix" $matrixNode` ){ return $results; } // One of i30, i31, or i32 will be connected // string $matrixAttr = ($matrixNode + ".i30"); string $conns[] = `listConnections $matrixAttr`; if( size($conns) == 0 ){ $matrixAttr = ($matrixNode + ".i31"); $conns = `listConnections $matrixAttr`; if( size($conns) == 0 ){ $matrixAttr = ($matrixNode + ".i32"); $conns = `listConnections $matrixAttr`; if( size($conns) == 0 ){ // No connection, return empty array // return $results; } } } $results[0] = $conns[0]; $results[1] = $matrixAttr; return( $results ); } global proc updateThresholdType( string $plug, int $usePercentage, int $rebuildUI ) { if( $rebuildUI ){ rebuildThresholdUI( $plug, $usePercentage ); } string $nodeName = `plugNode $plug`; editorTemplate -dimControl $nodeName "worldSpace" ($usePercentage); editorTemplate -dimControl $nodeName "minMaxDistance" ($usePercentage); editorTemplate -dimControl $nodeName "minDistance" ($usePercentage); editorTemplate -dimControl $nodeName "maxDistance" ($usePercentage); if( `optionMenuGrp -exists lodCameraMenu` ){ // Camera switching only makes sense for screen height percentage, // since it's a transferable measure. Give user a hint as to why // the menu is disabled if their threshold type is distance. // optionMenuGrp -e -enable $usePercentage -ann ($usePercentage ? (uiRes("m_AElodGroupTemplate.kPercentageCameraAnn")) : (uiRes("m_AElodGroupTemplate.kDistanceCameraAnn")) ) lodCameraMenu; // When switching between distance and percentage, we need to // modify connections, as need be. // string $plugCameraMatrix = $nodeName + ".cameraMatrix"; string $conns[] = `listConnections $plugCameraMatrix`; if (size($conns) == 0) { // No camera connected, bail // return; } string $upNode = $conns[0]; if( `objectType -isType "transform" $upNode` ){ if( $usePercentage ){ string $perspCamera = getFirstCamera( $upNode ); if( $perspCamera != "" ){ // We have a perspective camera; add the focalLength // connection if it's missing. // string $attr = ".focalLength"; string $lodFocalLength = $nodeName + $attr; clear $conns; $conns = `listConnections $lodFocalLength`; if( size($conns) == 0 ){ connectAttr ($perspCamera+$attr) $lodFocalLength; } } } } else { string $results[] = findMatrixConnection( $upNode ); if( size($results) > 0 ){ // Ortho camera - add/remove multDouble connection // string $upNode = $results[0]; int $isMultNode = `objectType -isType "multDoubleLinear" $upNode`; string $matrixAttr = $results[1]; string $ow = ".orthographicWidth"; if( $usePercentage ){ // Connect camera directly to 4x4 matrix // if( $isMultNode){ clear $conns; $conns = `listConnections $upNode`; if( size($conns) > 0 ){ string $orthoCamera = getFirstCamera( $conns[0] ); if( $orthoCamera != "" ){ connectAttr -f ($orthoCamera+$ow) $matrixAttr; } } } } else if(!$isMultNode){ // Add multDoubleLinear node between camera and matrix, // or re-connect old one. // string $orthoCamera = getFirstCamera( $upNode ); clear $conns; $conns = `listConnections ($orthoCamera+$ow)`; int $i = 0; string $mult; int $numConns = size($conns); while( $i < $numConns ){ $mult = $conns[0]; if(`objectType -isType "multDoubleLinear" $mult`){ break; } $i++; } if( $i == $numConns ){ // Create a new multDoubleLinear node // string $sel[] = `ls -sl`; $mult = `createNode multDoubleLinear`; select -r $sel; setAttr ($mult+".input2") 3.3333; connectAttr ($orthoCamera+$ow) ($mult+".input1"); } connectAttr -f ($mult+".output") $matrixAttr; } } } } } global proc AEthresholdTypeNew( string $useScreenHeightPercentage ) { setUITemplate -pst attributeEditorTemplate; string $attrName = `plugAttr $useScreenHeightPercentage`; radioButtonGrp -label (uiRes("m_AElodGroupTemplate.kThresholdType")) -numberOfRadioButtons 2 -label1 (uiRes("m_AElodGroupTemplate.kDistance")) -da1 0 -an1 (uiRes("m_AElodGroupTemplate.kDistanceAnnot")) -label2 (uiRes("m_AElodGroupTemplate.kPercentage")) -da2 1 -an2 (uiRes("m_AElodGroupTemplate.kPercentageAnnot")) thresholdTypeBtn; columnLayout ($attrName + "Column"); // set up initial value of threshold type // AEthresholdTypeReplace( $useScreenHeightPercentage ); setParent ..; setUITemplate -ppt; } global proc AEthresholdTypeReplace( string $useScreenHeightPercentage ) { // Initialize radio button with threshold type // int $thresholdType = `getAttr $useScreenHeightPercentage`; radioButtonGrp -e -select ($thresholdType + 1) -onCommand1 ("updateThresholdType " + $useScreenHeightPercentage + " 0 1") -onCommand2 ("updateThresholdType " + $useScreenHeightPercentage + " 1 1") thresholdTypeBtn; connectControl thresholdTypeBtn $useScreenHeightPercentage; string $attrName = `plugAttr $useScreenHeightPercentage`; string $nodeName = `plugNode $useScreenHeightPercentage`; rebuildThresholdUI( $useScreenHeightPercentage, $thresholdType ); updateThresholdType( $useScreenHeightPercentage, $thresholdType, false ); } global proc validateMinDistance( string $nodeName ) { float $thresh[] = `getAttr ($nodeName + ".threshold")`; if ( 0 == size($thresh) ) { // Threshold array can be empty. return; } string $minDistAttr = $nodeName + ".minDistance"; float $minDist = `getAttr $minDistAttr`; if ( $thresh[0] < $minDist ) { // The minimum distance cannot be bigger // then the smallest threshold. setAttr $minDistAttr $thresh[0]; } } global proc validateMaxDistance( string $nodeName ) { float $thresh[] = `getAttr ($nodeName + ".threshold")`; int $nbThresh = size($thresh); if ( 0 == $nbThresh ) { // Threshold array can be empty. return; } string $maxDistAttr = $nodeName + ".maxDistance"; float $maxDist = `getAttr $maxDistAttr`; if ( $thresh[$nbThresh-1] > $maxDist ) { // The maximum distance cannot be smaller // then the biggest treshhold. setAttr $maxDistAttr $thresh[$nbThresh-1]; } } proc string disconnectOrthoCamera( string $upNode ) // // Description: // Disconnect the 4x4 matrix from the ortho camera, and return the // disconnected plug; return the empty string if this was not possible. // { // Upstream node should be a 4x4 matrix // string $results[] = findMatrixConnection( $upNode ); if( size($results) == 0 ){ return ""; } string $currentCamera = $results[0]; string $matrixAttr = $results[1]; // Disconnect old camera, connect new camera // disconnectAttr ($currentCamera+".orthographicWidth") $matrixAttr; return $matrixAttr; } global proc cameraMatrixCB( string $plugCameraMatrix, string $menu ) // // Description: // When a different camera is chosen via the UI, this method gets called // with the plug of the lodGroup's cameraMatrix attribute, as well as the name // of the menu that triggered this callback. Switch to the selected camera, if // possible. // { string $nodeName = `plugNode $plugCameraMatrix`; int $thresholdType = `getAttr ($nodeName+".useScreenHeightPercentage")`; string $selectedTransform = `optionMenuGrp -q -value $menu`; if( !`objExists $selectedTransform` ){ string $errFmt = (uiRes("m_AElodGroupTemplate.kCameraNotFound")); string $errMsg = `format -s $selectedTransform $errFmt`; error( $errMsg ); return; } string $selectedCamera = getFirstCamera( $selectedTransform ); if( $selectedCamera == "" ){ string $errFmt = (uiRes("m_AElodGroupTemplate.kCameraNotValid")); string $errMsg = `format -s $selectedCamera $errFmt`; error( $errMsg ); return; } // Connect the camera to the lodGroup // int $willBeOrtho = `getAttr ($selectedCamera + ".orthographic")`; enableThresholdUI( $nodeName, $thresholdType, $willBeOrtho ); string $conns[] = `listConnections $plugCameraMatrix`; if( size($conns) == 0 ){ // No camera connected, bail // return; } string $upNode = $conns[0]; int $wasOrtho = `objectType -isType "fourByFourMatrix" $upNode`; if( $willBeOrtho ){ // Break old connection, make connection to an ortho camera // string $matrixAttr; if( $wasOrtho ){ // Disconnect the current ortho camera, and get the name of the // relevant 4x4 matrix. // $matrixAttr = disconnectOrthoCamera( $upNode ); if( $matrixAttr == "" ){ // Error while trying to disconnect, bail // return; } // Connect the ortho camera to the existing 4x4 matrix. // connectAttr ($selectedCamera + ".orthographicWidth") $matrixAttr; } else { // Converting from perspective to ortho. // // Connect ortho camera; this will create a 4x4 matrix, so we must // save selection and restore it. // if( !`exists connectOrthoToLod` ){ eval("source \"lodUtils.mel\""); } string $selection[] = `ls -sl`; connectOrthoToLod( $selectedCamera, $plugCameraMatrix ); // Restore selection // select -r $selection; } } else { // Break old connection, make connection to a persp camera // if( $wasOrtho ){ // Converting from ortho to persp. // // Disconnect the ortho camera from the 4x4 matrix, and delete the // 4x4 matrix since we no longer need it. // if( disconnectOrthoCamera( $upNode ) == "" ){; // Unable to disconnect, bail // return; } delete $upNode; } else { // Break connection to old persp camera; upstream node should be // the current camera. // string $currentCamera = getFirstCamera( $upNode ); if( $currentCamera == "" ){ // No camera found, bail // return; } disconnectAttr ($currentCamera + ".worldMatrix") $plugCameraMatrix; } // Connect the persp camera to the lodGroup // connectAttr ($selectedCamera + ".worldMatrix") $plugCameraMatrix; } } global proc AEcameraMatrixNew( string $plugCameraMatrix ) // // Description: // Create the camera switching control. // { // Create a control which consists of a drop-down menu of all similar // cameras. // setUITemplate -pst attributeEditorTemplate; string $menu = `optionMenuGrp -label (uiRes("m_AElodGroupTemplate.kCamera")) lodCameraMenu`; setParent ..; // set up initial value of UI // AEcameraMatrixReplace( $plugCameraMatrix ); setUITemplate -ppt; } global proc AEcameraMatrixReplace( string $plugCameraMatrix ) // // Description: // Update the camera control menu, based on the lodGroup node's // cameraMatrix plug. // { // Assign the callback with appropriate parameters // string $menu = "lodCameraMenu"; optionMenuGrp -e -cc ("cameraMatrixCB \"" + $plugCameraMatrix + "\" " + $menu) $menu; // Get the name of the camera (transform) currently associated with the // lodGroup node. // string $conns[] = `listConnections $plugCameraMatrix`; if (size($conns) == 0) { // No camera connected, bail // return; } string $upNode = $conns[0]; // Determine if we have an orthographic camera or a persp camera. The // lodGroup node will be connected to a 4x4 matrix if we have an // orthographic camera, otherwise it will be connected directly to the // perspective camera. // int $isOrtho = `objectType -isType "fourByFourMatrix" $upNode`; string $currentCam = $upNode; if( $isOrtho ){ // This is an ortho camera, traverse upstream to it. // clear $conns; $conns = `listConnections -s 1 -d 0 $upNode`; $currentCam = $conns[0]; } // Remove current camera menu items, if any. // string $children[] = `optionMenuGrp -q -ill $menu`; if( size($children) > 0 ){ deleteUI -mi $children; } // Now populate the menu, with the current camera selected. // int $i=0; string $cameras[] = `listCameras`; int $numCameras = size($cameras); while( $i < $numCameras ){ string $camera = $cameras[$i]; menuItem -parent ($menu+"|OptionMenu") -label $camera; $i++; if( $camera == $currentCam ){ optionMenuGrp -e -select $i $menu; } } } global proc AElodGroupTemplate ( string $nodeName ) { editorTemplate -beginScrollLayout; // include/call base class/node attributes AEtransformMain $nodeName; editorTemplate -beginLayout (uiRes("m_AElodGroupTemplate.kLodAttributes")) -collapse 0; editorTemplate -beginNoOptimize; int $usePercentage = false; string $nodeAttr = ""; editorTemplate -callCustom "AEthresholdTypeNew" "AEthresholdTypeReplace" "useScreenHeightPercentage"; $nodeAttr = $nodeName + ".useScreenHeightPercentage"; $usePercentage = `getAttr $nodeAttr`; editorTemplate -callCustom "AEcameraMatrixNew" "AEcameraMatrixReplace" "cameraMatrix"; editorTemplate -collapse false -addControl "worldSpace" ; editorTemplate -collapse false -addControl "minMaxDistance" "updateMinMaxDistances"; editorTemplate -endNoOptimize; editorTemplate -collapse false -addControl "minDistance" "validateMinDistance"; editorTemplate -collapse false -addControl "maxDistance" "validateMaxDistance"; editorTemplate -endLayout; // Defer the update of the UI, to make sure all the controls have been // created, otherwise the first update will not work properly. // evalDeferred( "updateThresholdType " + $nodeAttr + " " + $usePercentage + " 0"); //suppressed attributes editorTemplate -suppress "activeLevel"; editorTemplate -suppress "distance"; editorTemplate -suppress "screenHeightPercentage"; editorTemplate -suppress "output"; // We handle percentageThreshold implicitly, so we don't want it to appear // in the extra section. // editorTemplate -suppress "percentageThreshold"; // The focalLength attribute is meant for internal usage only, and // shouldn't appear in the AE. // editorTemplate -suppress "focalLength"; editorTemplate -suppress "threshold"; editorTemplate -suppress "displayLevel"; // include/call base class/node attributes AEtransformNoScroll $nodeName; editorTemplate -addExtraControls; editorTemplate -endScrollLayout; }