/********************************************************************** This script is provided as part of the Daz Script Documentation. The contents of this script, and\or any portion thereof, may only be used in accordance with the following license: Creative Commons Attribution 3.0 Unported (CC BY 3.0) - http://creativecommons.org/licenses/by/3.0 To contact Daz 3D or for more information about Daz Script visit the Daz 3D website: - http://www.daz3d.com **********************************************************************/ // Source: /public/software/dazstudio/4/referenceguide/scripting/api_reference/samples/elements/callbacks_element_post_load_create/start // Define an anonymous function; // serves as our main loop, // limits the scope of variables (function(){ /*********************************************************************/ // DzCallBack : A function for finding or creating a callback function getCallBack( sGroup, sName, oSender, sSignal, sCode, bAsEvent, bGarbageCollect ) { // If the callback name, sender, signal, or code are not defined if( sName.isEmpty() || !oSender || sSignal.isEmpty() || sCode.isEmpty() ){ // We are done... return undefined; } // Get the callback manager var oCallBackMgr = App.getCallBackMgr(); // Get the callback with the name var oCallBack = oCallBackMgr.getCallBack( sName ); // If we have a callback if( oCallBack ){ // Return the callback return oCallBack; } // Create a callback with the name oCallBack = oCallBackMgr.createCallBack( sName ); // We want the callback to be processed as an event oCallBack.setProcessAsEvent( bAsEvent ); // Add the callback to the group oCallBack.addToGroup( sGroup ); // Set/Embed the script in the callback oCallBack.setScript( sCode, true ); // Connect the callback to the signal on the sender oCallBack.setConnection( oSender, sSignal, bGarbageCollect ); // Return the callback return oCallBack; }; /*********************************************************************/ // DzCallBack : A function for getting the statement to find an element by ID function getSceneElementIDLookup( oElement ) { // If we do not have an element if( !oElement ){ // We are done... return "null"; } // Get the element identifier var nElementId = oElement.elementID; // If the element is a node if( oElement.inherits( "DzNode" ) ){ // Return the statement to find it in the scene return String("Scene.findNodeByElementID( %1 )").arg( nElementId ); // If the element is an object } else if( oElement.inherits( "DzObject" ) ){ // Return the statement to find it in the scene return String("Scene.findObjectByElementID( %1 )").arg( nElementId ); // If the element is a shape } else if( oElement.inherits( "DzShape" ) ){ // Return the statement to find it in the scene return String("Scene.findShapeByElementID( %1 )").arg( nElementId ); // If the element is a modifier } else if( oElement.inherits( "DzModifier" ) ){ // Return the statement to find it in the scene return String("Scene.findModifierByElementID( %1 )").arg( nElementId ); // If the element is a material } else if( oElement.inherits( "DzMaterial" ) ){ // Return the statement to find it in the scene return String("Scene.findMaterialByElementID( %1 )").arg( nElementId ); } // Return invalid return "null"; }; /*********************************************************************/ // DzCallBack : A function for finding or creating a callback for an element function getElementCallBack( oElement, sGroup, sName, oSender, sSignal, sCode, bAsEvent, bGarbageCollect ) { // If the element, callback name, sender, signal, or code are not defined if( !oElement || sName.isEmpty() || !oSender || sSignal.isEmpty() || sCode.isEmpty() ){ // We are done... return undefined; } // Get the element identifier var nElementId = oElement.elementID; // Construct a name for the callback var sCallBackName = String("%1@%2").arg( nElementId ).arg( sName ); // Get the element lookup statement var sElement = getSceneElementIDLookup( oElement ); // Define the lines of the callback script; // the element from the scene stored in a variable, // followed by the code for the callback var sScript = String("var oElement = %1;\n%2").arg( sElement ).arg( sCode ); // Return the callback return getCallBack( sGroup, sCallBackName, oSender, sSignal, sScript, bAsEvent, bGarbageCollect ); }; /*********************************************************************/ // DzCallBack : A function for finding or creating a callback between two properties function getInterPropertyCallBack( oElement, sGroup, oPropertyA, oPropertyB, sSignal, sCode, bAsEvent, bGarbageCollect ) { // If the element, either property, the signal, or code are not defined if( !oElement || !oPropertyA || !oPropertyB || sSignal.isEmpty() || sCode.isEmpty() ){ // We are done... return undefined; } // Construct a name for the callback; the element name will be prepended var sCallBackName = String("%1@%2@%3") .arg( oPropertyA.name ) .arg( oPropertyB.name ) .arg( sSignal.replace( /\(.*\)/g, "" ) ); // Define the lines of the callback script; // the name of the property stored in a variable, // followed by the code for the callback var sScript = String("var sProperty = \"%1\";\n%2") .arg( oPropertyB.name ) .arg( sCode ); // Create and return an element callback return getElementCallBack( oElement, sGroup, sCallBackName, oPropertyA, sSignal, sScript, bAsEvent, bGarbageCollect ); }; /*********************************************************************/ // DzCallBack : A function for finding or creating a callback for an element function getRenderMgrCallBack( oElement, sGroup, sSignal, oProperty, sPropSignal, sCode, bAsEvent, bGarbageCollect ) { // Construct a name for the callback; the element name will be prepended var sCallBackName = String("RenderMgr@%1@%2@%3") .arg( sSignal.replace( /\(.*\)/g, "" ) ) .arg( oProperty.name ) .arg( sPropSignal.replace( /\(.*\)/g, "" ) ); return getElementCallBack( oElement, sGroup, sCallBackName, App.getRenderMgr(), sSignal, String("var sProperty = \"%1\";\n%2") .arg( oProperty.name ) .arg( sCode ), bAsEvent, bGarbageCollect ); }; /*********************************************************************/ // Create a file info object for easy access var oFileInfo = new DzFileInfo( getScriptFileName() ); // Get the base path of this script var sBasePath = oFileInfo.path(); // Create a script var oScript = new DzScript(); // Get the path of the FindProperty script. Doing it this way, we can debug // with an ascii file and ship a binary [encrypted] file with the same // name... without having to update the contents of the script or manually // handle the file extensions. var sFindPropertyPath = oScript.getScriptFile( String("%1/FindProperty").arg( sBasePath ) ); // If the script was not found if( sFindPropertyPath.isEmpty() ){ // We are done... return; } // Include the FindProperty script include( sFindPropertyPath ); // 'DataItem' is a global transient variable, available when // this script is executed as a 'post load data item' // If we did not find the 'DataItem' global transient; // this script was executed outside the context of a 'post load data item' if( typeof( DataItem ) == "undefined" ){ // We are done... return; } // Get the owner of the data item var oElement = DataItem.getOwner(); // Get the base path of this script var sBasePath = oFileInfo.path(); // Create a unique identifier for the group of callbacks var sGroupGuid = App.createDigest( sBasePath ); // Define the lines of a callback script; only the lines that are common. // We will be creating callbacks for multiple properties, but each callback uses // functions that are common to each callback and to this script, so instead of // replicating the same code in multiple scripts we extract the common functions // (e.g., the contents of FindProperty.dsa) and inlcude it in the callback. oScript.addLine( String("var sBasePath = \"%1\";").arg( sBasePath ) ); oScript.addLine( "var oScript = new DzScript();" ); oScript.addLine( "" ); oScript.addLine( "(function(){" ); oScript.addLine( "var sCallBackPath = oScript.getScriptFile( String(\"%1/Callback_##\").arg( sBasePath ) );", 1 ); oScript.addLine( "if( sCallBackPath.isEmpty() ){", 1 ); oScript.addLine( "return;", 2 ); oScript.addLine( "}", 1 ); oScript.addLine( "", 1 ); oScript.addLine( "include( sCallBackPath );", 1 ); oScript.addLine( "})();" ); // Initialize a list of callback names var aCallBackNames = []; // Declare working variables var sPropertyNameA, sPropertyNameB, sPropertyClassA, sPropertyClassB; var oPropertyA, oPropertyB, oCallBack, oTexture; var vValue; // Get the render manager var oRenderMgr = App.getRenderMgr(); // Get the active renderer var oRenderer = oRenderMgr.getActiveRenderer(); // Get the settings for the data item var oSettings = DataItem.getSettings(); // Iterate over the settings for( var i = 0, nSettings = oSettings.getNumValues(); i < nSettings; i += 1 ){ // Get the 'current' key sPropertyNameA = oSettings.getKey( i ); // Find the 'A' property oPropertyA = findElementProperty( oElement, sPropertyNameA, false ); // If the property was not found if( !oPropertyA ){ // Next!! continue; } // Get the 'current' value sPropertyNameB = oSettings.getStringValue( sPropertyNameA ); // Find the 'B' property oPropertyB = findRendererProperty( "DzIrayRenderer", "", sPropertyNameB, false, true ); // If the property was not found if( !oPropertyB ){ // Next!! continue; } // Get the class names of the properties sPropertyClassA = oPropertyA.className(); sPropertyClassB = oPropertyB.className(); // If the class names are the same if( sPropertyClassA == sPropertyClassB ){ // Create a callback for the pair of properties oCallBack = getInterPropertyCallBack( oElement, sGroupGuid, oPropertyA, oPropertyB, "currentValueChanged()", oScript.getCode() .replace( "##", "currentValueChanged_Renderer" ), true, true ); // Append the name of the callback to our list //aCallBackNames.push( oCallBack.name ); // If the callback was created if( oCallBack ){ // Get the map value of the 'B' property vValue = oPropertyB.getValue(); // If the value of the 'A' property is not the same as the 'B' property if( oPropertyA.getValue() != vValue ){ // Update the value of the 'A' property with the the value of the 'B' property oPropertyA.setValue( vValue ); } } // Create a callback for the pair of properties in the opposite direction oCallBack = getInterPropertyCallBack( oElement, sGroupGuid, oPropertyB, oPropertyA, "currentValueChanged()", oScript.getCode() .replace( "##", "currentValueChanged" ), true, false ); // Append the name of the callback to our list aCallBackNames.push( oCallBack.name ); // Create a callback for triggering signals from the property when the active renderer changes oCallBack = getRenderMgrCallBack( oElement, sGroupGuid, "activeRendererChanged(DzRenderer*)", oPropertyA, "currentValueChanged()", oScript.getCode() .replace( "##", "activeRendererChanged_currentValueChanged" ), false, true ); // Append the name of the callback to our list aCallBackNames.push( oCallBack.name ); } // If the properties are numeric and mappable if( oPropertyA.inherits( "DzNumericProperty" ) && oPropertyA.isMappable() && oPropertyB.inherits( "DzNumericProperty" ) && oPropertyB.isMappable() ){ // Create a callback for the pair of properties oCallBack = getInterPropertyCallBack( oElement, sGroupGuid, oPropertyA, oPropertyB, "mapChanged()", oScript.getCode() .replace( "##", "mapChanged_Renderer" ), true, true ); // Append the name of the callback to our list //aCallBackNames.push( oCallBack.name ); // If the callback was created if( oCallBack ){ // Get the map value of the 'B' property oTexture = oPropertyB.getMapValue(); // If the map value of the 'A' property is not the same as the 'B' property if( !pointersAreEqual( oPropertyA.getMapValue(), oTexture ) ){ // Update the map of the 'A' property with the the map of the 'B' property oPropertyA.setMap( oTexture ); } } // Create a callback for the pair of properties in the opposite direction oCallBack = getInterPropertyCallBack( oElement, sGroupGuid, oPropertyB, oPropertyA, "currentValueChanged()", oScript.getCode() .replace( "##", "mapChanged" ), true, false ); // Append the name of the callback to our list aCallBackNames.push( oCallBack.name ); // Create a callback for triggering signals from the property when the active renderer changes oCallBack = getRenderMgrCallBack( oElement, sGroupGuid, "activeRendererChanged(DzRenderer*)", oPropertyA, "mapChanged()", oScript.getCode() .replace( "##", "activeRendererChanged_mapChanged" ), false, true ); // Append the name of the callback to our list aCallBackNames.push( oCallBack.name ); } } // Restore the active renderer oRenderMgr.setActiveRenderer( oRenderer ); // Construct a list of callback names var sCallBackNames = String("var aCallBackNames = [\n\t\"%1\"\n];") .arg( aCallBackNames.join( "\",\n\t\"" ) ); // Create a callback for deleting the render manager callback when the element is deleted oCallBack = getCallBack( String("%1-gc").arg( sGroupGuid ), String("%1@destroyed").arg( oElement.elementID ), oElement, "destroyed(QObject*)", String("var sCallBackGroup = \"%1\";\n%2\n%3") .arg( sGroupGuid ) .arg( sCallBackNames ) .arg( oScript.getCode() .replace( "##", "destroyed" ) ), false, true ); // Finalize the function and invoke })();