// =========================================================================== // 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. // =========================================================================== // // Procedure Name: // AEhardwareTextureTemplate // // Description: // Procedure to generate template hardware texture controls. // // Input Arguments: // nodeName is the material node name. (currently unused) // attrTokens contains the space deliminated material attribute names. // // Return Value: // None. // global string $gNiceNameSeparator = "|"; proc string getPlugNode( string $plug ) { string $buffer[]; tokenize($plug, ".", $buffer); return size($buffer) > 0 ? $buffer[0] : ""; } proc string getPlugAttr( string $plug ) { string $buffer[]; tokenize($plug, ".", $buffer); return size($buffer) > 1 ? $buffer[size($buffer) - 1] : ""; } // Takes a material plug as argument (say, "phong1.message") // and return an appropriate channelMenu name (eg: "phong_channelMenu") // proc string getChannelMenuNameFromMaterialPlug ( string $materialPlug ) { string $materialType = `nodeType $materialPlug`; if ($materialType == "") { string $msg = uiRes("AEhardwareTextureTemplate.kNotValid"); string $proc = "getChannelMenuNameFromMaterialPlug()"; error(`format -stringArg $proc -stringArg $materialPlug $msg`); return ""; } return ($materialType+"_channelMenu"); } // Takes a material plug as argument (say, "phong1.message") // and return an appropriate channelMenu name (eg: "phong_qualityMenu") // proc string getQualityMenuNameFromMaterialPlug ( string $materialPlug ) { string $materialType = `nodeType $materialPlug`; if ($materialType == "") { string $msg = uiRes("AEhardwareTextureTemplate.kNotValid"); string $proc = "getQualityMenuNameFromMaterialPlug()"; error(`format -stringArg $proc -stringArg $materialPlug $msg`); return ""; } return ($materialType+"_qualityMenu"); } proc string getFilterMenuNameFromMaterialPlug ( string $materialPlug ) { string $materialType = `nodeType $materialPlug`; if ($materialType == "") { string $msg = (uiRes("m_AEhardwareTextureTemplate.kNotValid")); string $proc = "getFilterMenuNameFromMaterialPlug()"; error(`format -stringArg $proc -stringArg $materialPlug $msg`); return ""; } return ($materialType+"_filterMenu"); } // Takes a material plug as argument (say, "phong1.message") // and return an appropriate filterMenu name (eg: "phong_mimapMenu") // proc string getMaterialInfo( string $messagePlug ) { string $materialName[] = `ls $messagePlug`; if ($materialName[0] == "") { // When the user changes the shader type in the attribute // editor, multiple scriptjobs could be assigned to the same // materialInfoNode, but only one of them would relate to the // new shader. Older scriptjobs should exit silently. return ""; } string $connections[] = `listConnections $messagePlug`; for ($item in $connections) if (`objectType $item` == "materialInfo") return $item; return ""; } proc disconnectInfoTexture( string $info ) { // We need to break all connection because we want to ensure the // texture being displayed has a multi index of zero. // // Note: the connections are broken from back to front because // breaking a connection at the end of the multi will not affect // the connections at the start of the multi. string $connections[]; // We need to specify shape because fluids textures are shape nodes // as well as being textures. $connections = `listConnections -connections true -shapes true ($info+".texture")`; for ($i = size($connections); $i > 0; $i -= 2) disconnectAttr ($connections[$i-1]+".message") $connections[$i-2]; } proc string getMaterialPlugFromTexture(string $texturePlug, string $material) // // Description: // Procedure to return the plug on the specified material which is // connected to texturePlug. If there is a bump node between, it will // be by passed to return the correct plug. // // Returns: // The returned plug will be something like "lambert1.color". // { string $materialPlug = ""; string $connections[] = `listConnections -source false -destination true -plugs true $texturePlug`; for ($item in $connections) { string $node = getPlugNode($item); string $type = `objectType $node`; if ($type == "bump2d" || $type == "bump3d") { // The node connected to the output is a bump, we want to // skip over this node and determine the material // attribute connected to the bump. string $bump = $node; string $buffer[] = `listConnections -plugs true -source false -destination true ($bump+".outNormal")`; if (size($buffer) < 1) continue; $item = $buffer[0]; } if (getPlugNode($item) == $material) { $materialPlug = $item; break; } } return $materialPlug; } proc string getTexturePlugFromMaterial(string $materialPlug) // // Description: // Procedure to return the plug on a texture which is connected to // materialPlug. If there is a bump node between, it will be by passed // to return the correct plug. // // Returns: // The returned plug will be something like "file1.outColor". // { string $texturePlug = ""; string $connections[] = `listConnections -source true -destination false -plugs true $materialPlug`; // If there is a bump connected to this channel, skip over it // to get the actual texture. if (size($connections) > 0) { string $node = getPlugNode($connections[0]); string $type = `objectType $node`; if ($type == "bump2d" || $type == "bump3d") { string $bump = $node; $connections = `listConnections -source true -destination false -plugs true ($bump+".bumpValue")`; } } if (size($connections) > 0) $texturePlug = $connections[0]; return $texturePlug; } proc updateChannelMenu( string $attrTokens, string $messagePlug) { string $connections[]; // Make sure we have at least a materialInfo and material. // string $material = getPlugNode($messagePlug); string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $channelMenuName = getChannelMenuNameFromMaterialPlug($messagePlug); // Get the texture currently used for hardware shading. // // This will return a value like "file1.outColor". // string $texturePlug = `getAttr ($info+".texturePlug")`; if ($texturePlug == "") { // There is no texture, set the channel menu to none. optionMenuGrp -e -select 1 -annotation "" $channelMenuName; return; } else if ($texturePlug == ($material+".outColor")) { // The connection is set to display all textures // (ie: bake the whole shader into one texture) // return; } // Get the material plug connected to the texture. // // This will return a value like "lambert1.color". // string $materialPlug = getMaterialPlugFromTexture($texturePlug, $material); if ($materialPlug == "") { // There is no material, set the channel menu to none. optionMenuGrp -e -select 1 -annotation "" $channelMenuName; return; } // Figure out which channel the menu is currently displaying and // if we are already displaying the right item return. // // Querying the annotation will return a plug like "lambert1.color". // string $currentChannelPlug = `optionMenuGrp -q -annotation $channelMenuName`; if ($currentChannelPlug == $materialPlug) return; // Determine the correct item to select in the channel menu based // on the material attribute // int $selectItem = 1; string $annotateItem = ""; string $materialAttr = getPlugAttr($materialPlug); if ($materialAttr != "") { string $channelAttrs[]; tokenize($attrTokens, " ", $channelAttrs); for ($index = 0 ; $index < size($channelAttrs); $index += 1) { // We need to also check the extensions _Color and _FloatValue which // correspond to ramp attribute child parameter extensions. if ($channelAttrs[$index] == $materialAttr || ($channelAttrs[$index] + "_Color") == $materialAttr || ($channelAttrs[$index] + "_FloatValue") == $materialAttr) { $selectItem = $index + 2; $annotateItem = $materialPlug; break; } } } optionMenuGrp -e -select $selectItem -annotation $annotateItem $channelMenuName; } proc updateFilterMenu( string $attrTokens, string $messagePlug) { string $connections[]; // Make sure we have at least a materialInfo and material. // string $material = getPlugNode($messagePlug); string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $filterMenuName = getFilterMenuNameFromMaterialPlug($messagePlug); // Get the texture currently used for hardware shading. // // This will return a value like "file1.outColor". // string $filterPlug = `getAttr ($info+".textureFilter")`; if ($filterPlug == "") { // There is no filter texture, set the channel menu to none. optionMenuGrp -e -select 1 -annotation "" $filterMenuName; return; } int $filterValue = `getAttr ($info+".textureFilter")`; if ($filterValue >= 0) optionMenuGrp -e -select ($filterValue) $filterMenuName; } proc updateQualityMenu( string $attrTokens, string $messagePlug ) { string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $qualityMenuName = getQualityMenuNameFromMaterialPlug($messagePlug); string $connections[] = `listConnections ($info+".texture[0]")`; int $hasTexture = (size($connections) != 0); if ($hasTexture) { if (size($connections) == 0) return; string $texture = $connections[0]; int $index = 1; // default string $buffer[] = `listAttr -string resolution $texture`; // Does the texture have a resolution attribute ? if (size($buffer) != 0) { $index = 2; // low int $resolution = `getAttr ($texture+".resolution")`; if ($resolution >= 256) $index = 5; // highest else if ($resolution >= 128) $index = 4; // high else if ($resolution >= 64) $index = 3; // medium } optionMenuGrp -e -enable true -select $index $qualityMenuName; } else { optionMenuGrp -e -enable false $qualityMenuName; } } // // Procedure Name: // AEhardwareTextureChangedCB // // Description: // Callback which is invoked when the materialInfo texture // attribute changes. This procedure will update the channel and // quality menus. // // Input Arguments: // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureChangedCB( string $attrTokens, string $messagePlug) { updateChannelMenu($attrTokens, $messagePlug); updateQualityMenu($attrTokens, $messagePlug); updateFilterMenu($attrTokens, $messagePlug); } // // Procedure Name: // AEhardwareTextureMaterialChangedCB // // Description: // Callback to be invoked when any channel attributes on the // material are changed. As new connections are made and broken // to the material; the menu items in the channel control will // be enabled/disabled. Also, if a texture we are currently // displaying is disconnected we update the materialInfo to // display "None". // // Input Arguments: // menuItem, name of the menu corresponding to this channel // channelPlug, material plug which changed (ie. "lambert1.color") // messagePlug, message plug on the material (ie. "lambert1.message") // // Return Value: // None. // global proc AEhardwareTextureMaterialChangedCB( string $menuItem, string $channelPlug, string $messagePlug ) { string $connections[] = `listConnections -plugs true $channelPlug`; int $hasConnections = (size($connections) != 0); menuItem -e -enable $hasConnections $menuItem; string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $channelMenuName = getChannelMenuNameFromMaterialPlug($messagePlug); // Are we currently displaying this channel ? // string $materialPlug = `optionMenuGrp -q -annotation $channelMenuName`; if ($materialPlug == $channelPlug) { string $texturePlug = getTexturePlugFromMaterial($materialPlug); // Was the connection broken ? if ($texturePlug == "") { disconnectInfoTexture($info); // There is no texture, set the channel menu to none. optionMenuGrp -e -select 1 -annotation "" $channelMenuName; } } } // // Procedure Name: // AEhardwareTextureChannelCB // // Description: // The user has updated the channel menu. This procedure will modify // materialInfo texture connection and the quality menu. // // Input Arguments: // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureChannelCB( string $attrTokens, string $messagePlug ) { // Get the material info node. string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $channelMenuName = getChannelMenuNameFromMaterialPlug($messagePlug); // Disconnect the current texture from materialInfo // disconnectInfoTexture($info); // Get the channel to now display. // int $index = `optionMenuGrp -q -select $channelMenuName`; if ($index > 1) { string $material = getPlugNode($messagePlug); string $channelAttrs[]; tokenize($attrTokens, " ", $channelAttrs); string $attr = $channelAttrs[$index - 2]; // If the attribute is not found in the provided tokens, // assume that it is set to 'Combined'. (bake the whole shader // as if it was a texture) // if ($attr == "") { // In order to display all textures at once, we need to // hook up the materialInfo node in a non-standard way: // the "texture[0]" attribute is set to the shader (as opposed // to a standard texture), and the texturePlug is set // to the outColor of the shader. // connectAttr -f ($material+".message") ($info+".texture[0]"); } else { string $materialPlug = ($material+"."+$attr); string $texturePlug = getTexturePlugFromMaterial($materialPlug); // Is a texture connected on this channel ? // if ($texturePlug != "") { // Connect up the new texture to materialInfo. // string $node = getPlugNode($texturePlug); if (size(`listConnections $node`) > 1) { // It may be ambiguous for materialInfo to figure out which // channel to display (for example, if a file texture is // hooked up to both color and bump on a material). We // make a connection to the "textureChannel" to specify // which plug should be used. // connectAttr $texturePlug ($info+".textureChannel"); } // Now let materialInfo do its thing // connectAttr ($node+".message") ($info+".texture[0]"); } } updateQualityMenu( $attrTokens, $messagePlug ); } } // // Procedure Name: // AEhardwareMimapChannelCB // // Description: // The user has updated the channel menu. This procedure will modify // materialInfo texture connection and the quality menu. // // Input Arguments: // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureFilterCB( string $attrTokens, string $messagePlug ) { // Get the material info node. string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $filterMenuName = getFilterMenuNameFromMaterialPlug($messagePlug); int $index = `optionMenuGrp -q -select $filterMenuName`; setAttr ($info + ".textureFilter") ($index ); updateFilterMenu( $attrTokens, $messagePlug ); refresh -force; } // // Procedure Name: // AEhardwareTextureQualityCB // // Description: // The user has updated the quality menu. Update the resolution // attribute on the texture. // // Input Arguments: // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureQualityCB( string $attrTokens, string $messagePlug ) { // Get the material info node. string $info = getMaterialInfo($messagePlug); if ($info == "") return; string $qualityMenuName = getQualityMenuNameFromMaterialPlug($messagePlug); // Get the texture connected to the material info // string $connections[] = `listConnections ($info+".texture[0]")`; if (size($connections) == 0) return; string $texture = $connections[0]; // Get the user setable quality // int $index = `optionMenuGrp -q -select $qualityMenuName`; string $buffer[] = `listAttr -string resolution $texture`; int $hasResolutionAttr = (size($buffer) != 0); if ($index == 1) { // default // Delete the resolution attribute if it already exists. // if ($hasResolutionAttr) { deleteAttr -at resolution $texture; // check the connection between ($texture+".message") and ($info+".texture[0]") string $connections[] = `listConnections -p on ($texture+".message")`; string $plug = $info+".texture[0]"; int $i, $found = false; for ($i = 0; $i < size($connections); $i++) { if ($plug == $connections[$i]) { $found = true; break; } } // make connection if not existance. // conectAttr and refresh -force will cause refresh. if ($found) { refresh -force; } else { connectAttr ($texture+".message") ($info+".texture[0]"); } } } else { // Create a resolution attribute if one doesn't exist // if (!$hasResolutionAttr) { addAttr -ln resolution -at long -dv 32 $texture; } // Set the resolution attribute on the texture depending on // the quality the user specified. // switch ($index) { case 2: // low setAttr ($texture+".resolution") 32; break; case 3: // medium setAttr ($texture+".resolution") 64; break; case 4: // high setAttr ($texture+".resolution") 128; break; case 5: // highest setAttr ($texture+".resolution") 256; break; } } } // // Procedure Name: // AEhardwareTextureNewCB // // Description: // Callback to create the hardware texture controls. // // Input Arguments: // nodeName contains the node name. // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureNew( string $attrTokens, string $attrTokensAsNiceNames, string $messagePlug ) { global string $gNiceNameSeparator; $channelMenuName = getChannelMenuNameFromMaterialPlug($messagePlug); if (isLegacyViewportEnabled()) $qualityMenuName = getQualityMenuNameFromMaterialPlug($messagePlug); $filterMenuName = getFilterMenuNameFromMaterialPlug($messagePlug); string $channelAttrs[]; tokenize($attrTokensAsNiceNames, $gNiceNameSeparator, $channelAttrs); columnLayout -adj true layout; optionMenuGrp -label (uiRes("m_AEhardwareTextureTemplate.kTexturedChannel")) $channelMenuName; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kNone")) ; for ($item in $channelAttrs) { menuItem -label $item; } menuItem -label (uiRes("m_AEhardwareTextureTemplate.kCombinedTextures")) ; setParent ..; if (isLegacyViewportEnabled()) { optionMenuGrp -label (uiRes("m_AEhardwareTextureTemplate.kTextureResolution")) $qualityMenuName; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kDefault")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kLow32by32")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kMedium64by64")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kHigh128by128")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kHighest256by256")) ; setParent ..; } optionMenuGrp -label (uiRes("m_AEhardwareTextureTemplate.kTextureFilter")) $filterMenuName; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kUseGlobalSettings")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kNearestUnfiltered")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kBilinear")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kMipmapNearest")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kMipmapLinear")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kMipmapBilinear")) ; menuItem -label (uiRes("m_AEhardwareTextureTemplate.kMipMapTrilinear")) ; setParent ..; setParent ..; AEhardwareTextureReplace($attrTokens, $messagePlug); } // // Procedure Name: // AEhardwareTextureReplaceCB // // Description: // Callback to initialize and install callbacks for the hardware // texture controls. // // Input Arguments: // nodeName contains the node name. // attrTokens contains the space deliminated material attribute names. // messagePlug is the material message plug. // // Return Value: // None. // global proc AEhardwareTextureReplace( string $attrTokens, string $messagePlug ) { $channelMenuName = getChannelMenuNameFromMaterialPlug($messagePlug); if (isLegacyViewportEnabled()) $qualityMenuName = getQualityMenuNameFromMaterialPlug($messagePlug); $filterMenuName = getFilterMenuNameFromMaterialPlug($messagePlug); string $info = getMaterialInfo($messagePlug); int $hasMaterialInfo = ($info != ""); int $hasTexture = ($info != ""); if ($info != "") { string $connections[] = `listConnections ($info+".texture[0]")`; $hasTexture = (size($connections) > 0); scriptJob -parent layout -replacePrevious -disregardIndex -attributeChange ($info+".texture[0]") ("AEhardwareTextureChangedCB \""+$attrTokens+"\" "+$messagePlug); } // Set up some script jobs so we can detect when the user makes a // new connection to our channel attributes. // string $material = getPlugNode($messagePlug); if ($material != "") { string $channelAttrs[]; tokenize($attrTokens, " ", $channelAttrs); string $channelItems[] = `optionMenuGrp -q -itemListShort $channelMenuName`; for ($i = 0; $i < size($channelAttrs); $i += 1) { string $channelPlug = $material+"."+$channelAttrs[$i]; string $menuItem = $channelItems[$i+1]; scriptJob -parent $channelItems[$i+1] -replacePrevious -attributeChange $channelPlug ("AEhardwareTextureMaterialChangedCB "+$menuItem+" "+ $channelPlug+" "+$messagePlug); AEhardwareTextureMaterialChangedCB( $menuItem, $channelPlug, $messagePlug); } } optionMenuGrp -e -enable $hasMaterialInfo -cc ("AEhardwareTextureChannelCB \""+$attrTokens+"\" "+$messagePlug) $channelMenuName; if (isLegacyViewportEnabled()) { optionMenuGrp -e -enable $hasTexture -cc ("AEhardwareTextureQualityCB \""+$attrTokens+"\" "+$messagePlug) $qualityMenuName; } optionMenuGrp -e -enable $hasMaterialInfo -cc ("AEhardwareTextureFilterCB \""+$attrTokens+"\" "+$messagePlug) $filterMenuName; updateChannelMenu($attrTokens, $messagePlug); updateFilterMenu($attrTokens, $messagePlug); if (isLegacyViewportEnabled()) updateQualityMenu($attrTokens, $messagePlug); } // // Procedure Name: // AEhardwareTextureTemplate // // Description: // Procedure to generate template hardware texture controls. // // Input Arguments: // nodeName is the material node name. (currently unused) // attrTokens contains the space deliminated material attribute names. // // Return Value: // None. // global proc AEhardwareTextureTemplate( string $nodeName, string $attrTokens ) { global string $gNiceNameSeparator; string $niceAttrNames = ""; string $channelAttrs[]; tokenize($attrTokens, " ", $channelAttrs); for ($item in $channelAttrs) { // The name normalCamera is not well understood by the // user so we will name this menu item bump. string $currentNiceAttrName = `attributeName -nice ($nodeName + "." + $item)`; if ($item == "normalCamera") $currentNiceAttrName = (uiRes("m_AEhardwareTextureTemplate.kBumpMap")); $niceAttrNames = $niceAttrNames + $gNiceNameSeparator + $currentNiceAttrName; } editorTemplate -callCustom ("AEhardwareTextureNew \""+$attrTokens+"\" \""+$niceAttrNames+"\"") ("AEhardwareTextureReplace \""+$attrTokens+"\"") "message"; editorTemplate -addControl "materialAlphaGain"; }