Single-Thread Custom ICENode

 
 
 

Custom ICENodes are processed in multi-thread by default. Sometimes it may be required to have a way of processing the node in one single thread instead. Single-thread processing gives you the ability to access the entire input data set at once, as opposed to batch processing as it's the case in multi-threading. Single-threading mode is useful for implementing simple mathematical functions such as average, min, or max. You could also use it to implement more sophisticated nodes such as bounding box generators or particle collison detectors. The bounding box generator however can also be done in multi-threading but will force you to perform extra operations in order to find the min and max values among the values collected once the multi-thread processing is done.

The first step to enable the single-thread processing is to set the threading model to siICENodeSingleThreadingModel. This must be done during the node registration with ICENodeDef::PutThreadingModel. The input and output ports need to be defined with respect to the following rules:

  1. All input ports must be set with a singleton context (siICENodeContextSingleton), if not set with a singleton context then all input ports' context must be constrained by their context type.

  2. Output ports can be of any context type.

If the first rule is not met, Softimage will log an error at registration time and then abort the ICENode registration.

The following example demonstrates how the single-threading model can be used to generate a bounding box out of a geometry vertices:

XSIPLUGINCALLBACK CStatus XSILoadPlugin( PluginRegistrar& in_reg )
{
	in_reg.PutAuthor(L"Softimage");
	in_reg.PutName(L"BBoxGenerator Plugin");
	in_reg.PutVersion(1,0);
	
	ICENodeDef nodeOpDef;
	nodeOpDef = Application().GetFactory().CreateICENodeDef(L"BBoxGenerator");
	
	// Set the threading model to single-thread
	CStatus st;
	st = nodeOpDef.PutThreadingModel(XSI::siICENodeSingleThreading);
	st.AssertSucceeded( ) ;
	
	// Add input ports and groups.
	st = nodeOpDef.AddPortGroup(ID_G_100);
	st.AssertSucceeded( ) ;
	
	st = nodeOpDef.AddInputPort(
		ID_IN_vector3, // port index
		ID_G_100, // group index
		siICENodeDataVector3, // data type
		siICENodePortStructureSingle, // structure type
		siICENodeEvaluationContextAny, // context type
		L"vector3", // port name
		L"vector3", // port scripting name
		MATH::CVector3f(1.0,1.0,1.0)// default value
	);
	st.AssertSucceeded( ) ;
	
	// Add output ports.
	st = nodeOpDef.AddOutputPort(
		ID_OUT_minPos, // port index
		siICENodeDataVector3, // data type
		siICENodePortStructureSingle, // structure type
		siICENodeContextSingleton, // context type
		L"minPos", // port name
		L"minPos"// port scripting name
	);
	st.AssertSucceeded( ) ;
	
	st = nodeOpDef.AddOutputPort(
		ID_OUT_maxPos, // port index
		siICENodeDataVector3, // data type
		siICENodePortStructureSingle, // structure type
		siICENodeContextSingleton, // context type
		L"maxPos", // port name
		L"maxPos"// port scripting name
	);
	st.AssertSucceeded( ) ;
	
	PluginItem nodeItem = in_reg.RegisterICENode(nodeOpDef);
	nodeItem.PutCategories(L"Custom ICENode");
	
	return CStatus::OK;
}
XSIPLUGINCALLBACK CStatus BBoxGenerator_Evaluate( ICENodeContext& in_ctxt )
{
	ULONG nPortID = in_ctxt.GetEvaluatedOutputPortID();
	switch ( nPortID )
	{
		case ID_OUT_minPos:
		case ID_OUT_maxPos:
		{
			Application xsi;
			
			CDataArrayVector3f posArray( in_ctxt, ID_IN_vector3 );
			CDataArrayVector3f outData( in_ctxt );
			CVector3f v3fMin(FLT_MAX,FLT_MAX,FLT_MAX);
			CVector3f v3fMax(-FLT_MAX,-FLT_MAX,-FLT_MAX);
			CIndexSet indexSet( in_ctxt );
			for ( CIndexSet::Iterator it = indexSet.Begin(); it.HasNext(); it.Next() )
			{
				CVector3f& v3f = posArray[ it ];
				
				if ( v3fMin.GetX() > v3f.GetX() && v3fMin.GetY() > v3f.GetY() && v3fMin.GetZ() > v3f.GetZ() )
				{
					v3fMin = v3f;
				}
				else if ( v3fMax.GetX() < v3f.GetX() && v3fMax.GetY() < v3f.GetY() && v3fMax.GetZ() < v3f.GetZ() )
				{
					v3fMax = v3f;
				}
			}
			
			if ( ID_OUT_minPos == nPortID ) 
			{
				xsi.LogMessage( L"BBox Min: " + CString( v3fMin ) );
				outData[ 0 ] = v3fMin;
			}
			else
			{
				xsi.LogMessage( L"BBox Max: " + CString( v3fMax ) );
				outData[ 0 ] = v3fMax;
			}
		}
		break;
	};
	return CStatus::OK;
}