Prepare/Evaluate Protocol

From The Foundry MODO SDK wiki
Jump to: navigation, search

There are a few item interfaces that allow an item to return an object to a client. For example the SurfaceItem Interface has three methods: GetSurface(), Prepare(), and Evaluate(). GetSurface() takes a ChannelRead Object which can be used to get the values of channels in order to create an instance of the surface object for the item. The Prepare/Evaluate methods do the same thing, but using a different scheme to get channel values.

Basic Usage

The Prepare() method takes an Evaluation Interface as argument. This is used to let the item declare which channels it needs to read in order to compute the surface object. The index returned is typically the index of the first evaluation channel.

	LxResult
CMySurfaceItem::isurf_Prepare (
	ILxUnknownID		 evalObj,
	unsigned		*index)
{
	CLxUser_Evaluation	 eval (evalObj);

	index[0] = 
	  eval.AddChan (m_item, Cs_MYCHANNEL1);
	  eval.AddChan (m_item, Cs_MYCHANNEL2);
	  eval.AddChan (m_item, Cs_MYCHANNEL3);

	return LXe_OK;
}

The Evaluate() method is called zero or more times after preparation. This gets an Attributes Interface which is used to read channel values using the indices from preparation.

	LxResult
CMySurfaceItem::isurf_Evaluate (
	ILxUnknownID		 attrObj,
	unsigned		 index,
	void		       **ppvObj)
{
	CLxUser_Attributes	 attr (attrObj);
	CMySurface		*surf = surf_spawn.Alloc (ppvObj);

	surf->val1 = attr.Float (index + 0);
	surf->val2 = attr.Float (index + 1);
	surf->val3 = attr.Float (index + 2);

	return LXe_OK;
}

Using an EvalModifier

The Prepare/Evaluate protocol can be used directly in only limited circumstances. Specifically if the item always reads the same set of channels and they are all from the item itself. A surface that depends on channels from other items -- or which needs to read different sets of channels depending on the configuration or topology of the scene -- needs to use an EvalModifier server to deal with the additional complexity.

The item will need a channel to store the result of the modifier. This will be of the OBJREF type (which allows it to store any object, or none) and set to internal to prevent it from appearing in the channel list.

	CLxUser_AddChannel	 ac (addChan);

	ac.NewChannel  (Cs_SURFCACHE, LXsTYPE_OBJREF);
	ac.SetInternal ();

The EvalModifier will read the necessary channels from all over the scene and store the result object in a channel on the item. This can for example be done with a utility class for creating item modifiers. Since the heavy lifting has already been done, the Prepare/Evaluate method just needs to read that one channel.

	LxResult
CMySurfaceItem::isurf_Prepare (
	ILxUnknownID		 evalObj,
	unsigned		*index)
{
	CLxUser_Evaluation	 eval (evalObj);

	index[0] = eval.AddChan (m_item, Cs_SURFCACHE);
	return LXe_OK;
}

	LxResult
CMySurfaceItem::isurf_Evaluate (
	ILxUnknownID		 attrObj,
	unsigned		 index,
	void		       **ppvObj)
{
	CLxUser_Attributes	 attr (attrObj);
	CLxUser_ValueReference	 ref;

	attr.ObjectRO (index, ref);
	return ref.GetObject (ppvObj);
}