Example #1
0
	public virtual bool build( bool reload_asset, bool unload_asset_first,
							   bool serialization_recovery_only,
							   bool force_reconnect,
							   bool is_duplication,
							   bool cook_downstream_assets,
							   bool use_delay_for_progress_bar )
	{
		// We can only build or do anything if we can link to our libraries.
#if !( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )
		return false;
		#pragma warning disable 0162
#endif // !( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )

		if ( !HoudiniHost.isInstallationOk() )
			return false;

		if ( !prEnableCooking )
			return false;

		if ( isPrefabInstance() )
			processParentPrefab();

		// Run post-cook hook.
		foreach ( var asset_hook in prAssetHooks )
			asset_hook.preCook( this );

		HoudiniProgressBar progress_bar = new HoudiniProgressBar();
		progress_bar.prUseDelay = use_delay_for_progress_bar;
		progress_bar.prAsset = this;

		try
		{
			progress_bar.prStartTime = System.DateTime.Now;
			
			bool is_first_time_build = false;
			
			// restore asset id and asset validation id from the backup whenever
			// reverting a prefab instance
			bool is_reverting_prefab_instance = isRevertingPrefabInstance();
			if ( is_reverting_prefab_instance )
			{
				prAssetId = prBackupAssetId;
				prAssetValidationId = prBackupAssetValidationId;
			}
			
			if ( reload_asset ) 
			{	
				if ( unload_asset_first )
				{
					// There's no reason to abort the whole rebuild process because we can't unload
					// the asset first as that would leave the user with no options other than
					// to delete this HAPI asset and create a new one for this OTL.
					try
					{
						HoudiniHost.destroyAsset( prAssetId );
					}
					catch ( HoudiniError ) {}

					// Once an asset is unloaded its id will is obviously no longer valid, so reset it here.
					prAssetId = -1;
					
					// Need to reset the parms as well.
					prParms.reset();
				}

				try
				{
					int asset_id = 0;

					if ( prAssetId < 0 )
						is_first_time_build = true;

					if ( unload_asset_first )
						asset_id = buildCreateAsset( progress_bar );
					else
						asset_id = prAssetId;

					// We need to update the prAssetId in case the cook is aborted/fails 
					// and we need to clean up (unload the asset) in the catch.
					prAssetId = asset_id;

					prAssetInfo = HoudiniHost.getAssetInfo( asset_id );
					HAPI_NodeInfo node_info = HoudiniHost.getNodeInfo( prAssetInfo.nodeId );
					
					if ( reload_asset )
						Debug.Log( 
							"Houdini Engine: Asset Loaded - ID: " + prAssetInfo.id + "\n" +
							"    Full Name: " + prAssetInfo.fullOpName + "\n" +
							"    Version: " + prAssetInfo.version + "\n" + 
							"    Unique Node Id: " + node_info.uniqueHoudiniNodeId + "\n" +
							"    Internal Node Path: " + node_info.internalNodePath + "\n" +
							"    Asset Library File: " + prAssetInfo.filePath + "\n" );
				}
				catch ( HoudiniError error )
				{
					Debug.LogError( "Asset not loaded: " + error.ToString() );
					// Nothing to build since the load failed.

					// Try to unload the asset so it doesn't dangle.
					if ( is_first_time_build )
					{
						try
						{
							HoudiniHost.destroyAsset( prAssetId );
						}
						catch ( HoudiniError ) {}
					}
					
					// Clean up.
					reset();

					// If in play mode, disable live cooks.
#if UNITY_EDITOR
					if ( EditorApplication.isPlaying )
#endif // UNITY_EDITOR
					{
						prPlaymodePerFrameCooking = false;
					}
					
					return false; // false for failed :(
				}
				
			}
			
			prAssetInfo = HoudiniHost.getAssetInfo( prAssetId );
			
			// For convenience we copy some asset info properties locally (since they are constant anyway).
			// More imporantly, structs are not serialized and therefore putting them into their own
			// variables is required in order to maintain state between serialization cycles.
			prAssetId 					= prAssetInfo.id;
			prBackupAssetId				= prAssetId;
			prAssetValidationId			= prAssetInfo.validationId;
			prBackupAssetValidationId 	= prAssetValidationId;
			prNodeId					= prAssetInfo.nodeId;
			prObjectNodeId				= prAssetInfo.objectNodeId;
			prObjectCount 				= prAssetInfo.objectCount;
			prHandleCount 				= prAssetInfo.handleCount;

			prAssetName					= prAssetInfo.name;
			prAssetOpName				= prAssetInfo.fullOpName;
			prAssetHelp					= prAssetInfo.helpText;
			prHAPIAssetType				= prAssetInfo.type;
			prTransformInputCount		= prAssetInfo.transformInputCount;
			prGeoInputCount				= prAssetInfo.geoInputCount;

#if UNITY_EDITOR
			if ( isPrefab() )
			{
				string prefab_path = AssetDatabase.GetAssetPath( GetInstanceID() );
				HoudiniHost.myCleanUpPrefabAssets[ prefab_path ] = prAssetId;
			}
#endif // UNITY_EDITOR

			// Try to load presets.
			if ( ( reload_asset && ( unload_asset_first || is_reverting_prefab_instance ) )
#if UNITY_EDITOR
				// Only load presets during serialization recovery if we really need to.
				// The only such case is when we made changes DURING playmode and Unity
				// restores the parameter values from before going into playmode.
				// We only save presets while NOT in playmode which means to restore
				// the Houdini state to before playmode state we need to loadPreset()
				// with the last saved preset. In all other cases, like going INTO
				// playmode, we should avoid this step because loadPreset() WILL
				// cause a cook regardless if the parameters have changed or not which
				// is terrible for large assets.
				|| ( serialization_recovery_only && 
					!EditorApplication.isPlayingOrWillChangePlaymode &&
					!prParms.prValuesEqualToHoudini )
#endif // UNITY_EDITOR
				)
			{
				loadPreset();
				progress_bar.statusCheckLoop();
				
				// Transform may not have been saved as part of the presets so we have to rely 
				// on the serialized value.
				if ( myLastLocalToWorld != Matrix4x4.zero && !isPrefab() )
				{
					// If this is a prefab instance being reverted we don't want to use the 
					// serialized value so don't change transform. 
					if ( !is_reverting_prefab_instance )
					{
						Matrix4x4 world_to_local = Matrix4x4.identity;
						if ( transform.parent )
							world_to_local = transform.parent.worldToLocalMatrix;
						Matrix4x4 local = myLastLocalToWorld * world_to_local;

						transform.localPosition = HoudiniAssetUtility.getPosition( local );
						transform.localRotation = HoudiniAssetUtility.getQuaternion( local );

						Vector3 scale = HoudiniAssetUtility.getScale( local );
						if ( !( Mathf.Approximately( 0.0f, scale.x )
							&& Mathf.Approximately( 0.0f, scale.y )
							&& Mathf.Approximately( 0.0f, scale.z ) ) )
						{
							transform.localScale = HoudiniAssetUtility.getScale( local );
						}
					}
					
					if ( prPushUnityTransformToHoudini )
					{
						pushAssetTransformToHoudini();
					}
				}
			}

			if ( reload_asset )
			{
				progress_bar.prCurrentValue			= 0;
				progress_bar.prTotal				= prObjectCount + prHandleCount;
				
				progress_bar.displayProgressBar();
				myProgressBarJustUsed = true;

				// Add input fields.
				if ( is_first_time_build || !force_reconnect )
					initAssetConnections();
				
				// Clean up.
				destroyChildren( transform );
				prGameObjects = new GameObject[ prObjectCount ];
			}
				
			if ( reload_asset || serialization_recovery_only )
			{
				// Need to re-acquire all the params for all the child controls that have parms exposed.
				prParms.getParameterValues();
				foreach ( HoudiniParms parms in GetComponentsInChildren< HoudiniParms >() )
					parms.getParameterValues();

				// Custom work during a full build (custom to each subclass).
				buildFullBuildCustomWork( ref progress_bar, is_duplication );
			}
			
			if ( !reload_asset && !serialization_recovery_only )
			{
				progress_bar.displayProgressBar();
				updateParameters( progress_bar );
			}

			// Create local object info caches (transforms need to be stored in a parallel array).
			if ( prObjects == null || prObjects.Length != prObjectCount )
				prObjects = new HAPI_ObjectInfo[ prObjectCount ];
			
			if ( prObjectTransforms == null || prObjectTransforms.Length != prObjectCount )
				prObjectTransforms = new HAPI_Transform[ prObjectCount ];
			
			// Refresh object info arrays as they are lost after serialization.
			HoudiniAssetUtility.getArray1Id( prAssetId, HoudiniHost.getObjects, prObjects, prObjectCount );
			HoudiniAssetUtility.getArray2Id( prAssetId, HAPI_RSTOrder.HAPI_SRT, HoudiniHost.getObjectTransforms, 
					 			 prObjectTransforms, prObjectCount );

			bool objects_need_recook = false;
			if ( !serialization_recovery_only )
			{
				// Set asset's transform.
				if ( prPushUnityTransformToHoudini )
					HoudiniAssetUtility.getHoudiniTransformAndApply( prAssetId, prAssetName, transform );
			
				progress_bar.prMessage = "Loading and composing objects...";

				// Destroy/copy non-copiable but still serialized member data.
				if ( is_duplication )
				{
					myAssetOTLUndoInfo = null;
					if ( myGeoAttributeManagerMap != null )
					{
						myGeoAttributeManagerMap = myGeoAttributeManagerMap.copy();
						myGeoAttributeManagerMap.name = prAssetName + "_GeoAttributeManagerMap";
					}
					if ( myPresetsMap != null )
					{
						myPresetsMap = myPresetsMap.clone();
						myPresetsMap.name = prAssetName + "_PresetMap";
					}
				}
			
				// Custom way to load objects (custom to each subclass).
				objects_need_recook = buildCreateObjects( reload_asset, ref progress_bar );
			
				// Process dependent assets.
				if ( cook_downstream_assets )
					processDependentAssets(
						serialization_recovery_only,
						force_reconnect,
						is_duplication,
						use_delay_for_progress_bar );
			}

			// This tells Unity that values have been overridden for this prefab instance 
			// (eg. asset id, validation id, node id, etc). 
#if UNITY_EDITOR
			if ( isPrefabInstance() )
				PrefabUtility.RecordPrefabInstancePropertyModifications( this );
#endif // UNITY_EDITOR

			// A bit of a hack (but not terrible). If we have presets for other child controls
			// they set their presets by now so we need to rebuild with the new presets.
			if ( objects_need_recook )
			{
				build(
					false,	// reload_asset
					false,	// unload_asset_first
					false,	// serializatin_recovery_only
					false,	// force_reconnect
					false,	// is_duplication
					false,	// cook_downstream_assets
					true	// use_delay_for_progress_bar
				);
			}
		}
		catch ( HoudiniErrorIgnorable ) {}
		catch ( HoudiniErrorProgressCancelled error )
		{
			// If in play mode, disable live cooks.
#if UNITY_EDITOR
			if ( EditorApplication.isPlaying )
#endif // UNITY_EDITOR
			{
				prPlaymodePerFrameCooking = false;
			}

			Debug.LogError( error.ToString() + "\nSource: " + error.Source );
		}
		catch ( HoudiniError error )
		{
			Debug.LogError( error.ToString() + "\nSource: " + error.Source );
		}
		catch ( System.Exception error )
		{
			Debug.LogError( error.ToString() + "\nSource: " + error.Source );
		}
		finally
		{
			progress_bar.clearProgressBar();

			myProgressBarJustUsed = false;

			// Run post-cook hook.
			foreach ( var asset_hook in prAssetHooks )
				asset_hook.postCook( this );
		}

		// We can only build or do anything if we can link to our libraries.
#if !( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )
		#pragma warning restore 0162
#endif // !( UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX || ( UNITY_METRO && UNITY_EDITOR ) )
		
		return true;
	}
Example #2
0
	public void updateParameters( HoudiniProgressBar progress_bar )
	{
		// Update prefab instance after parameter change on prefab if needed
#if UNITY_EDITOR
		if ( isPrefabInstance() && prUpdatePrefabInstanceParmNames.Count > 0 )
		{
			HoudiniAsset prefab_asset = getParentPrefabAsset();

			foreach ( string parm_name in prUpdatePrefabInstanceParmNames )
			{
				try
				{
					HAPI_ParmInfo parm_info = prParms.findParm( parm_name );
				
					// Do not apply changes from prefab in the following cases: 
					// Case 1: Parameter on prefab that has been changed is a
					// transform parameter
					// Case 2: Parameter on prefab that has been changed has been
					// overridden on this asset
					// Otherwise set the parameter change for this prefab
					if ( parm_name != "r" && 
						parm_name != "s" &&
						parm_name != "t" &&
						!prParms.isParmOverridden( parm_info.id ) )
					{
						// if the parameter is a string we need to manually
						// get the string value from the prefab because the
						// parameter strings are stored in a dictionary which
						// is not serialized so the value isn't overridden 
						// automatically by the prefab value as it is done
						// with float and int parameters
						if ( parm_info.isString() && prefab_asset )
						{
							HAPI_ParmInfo prefab_parm_info = prefab_asset.prParms.findParm( parm_name );
							string[] values = prefab_asset.prParms.getParmStrings( prefab_parm_info );

							prParms.setParmStrings( parm_info, values );
						}

						prParms.setChangedParameterIntoHost( parm_info.id );
					}
				}
				catch {}
			}

			prUpdatePrefabInstanceParmNames.Clear();

			// Need to set prUpdatePrefabInstanceParmName back to empty on prefab if
			// it hasn't been already. We do not set prefab to be dirty so that other
			// prefab instances that still need this value will not be affected.
			if ( prefab_asset && prefab_asset.prUpdatePrefabInstanceParmNames.Count > 0 )
			{
				prefab_asset.prUpdatePrefabInstanceParmNames.Clear();
			}
		}
#endif // UNITY_EDITOR

		prParms.setChangedParametersIntoHost();

		HoudiniHost.cookAsset( prAssetId, prSplitGeosByGroup, prImportTemplatedGeos );
		progress_bar.statusCheckLoop();

		myProgressBarJustUsed = true;
		
		progress_bar.prTotal = prObjectCount;

		prParms.getParameterValues();
	}