Mesh Operation - Manual implementation

From The Foundry MODO SDK wiki
Revision as of 16:39, 27 June 2016 by Mattcox (Talk | contribs) (Created page with "__TOC__ Mesh Operations can be integrated directly into the procedural modelling system, allowing them to be evaluated as part of the procedural stack. A modifier should spaw...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Mesh Operations can be integrated directly into the procedural modelling system, allowing them to be evaluated as part of the procedural stack. A modifier should spawn the ILxMeshOperation server and store it in the MeshOpObj channel on the Mesh Operation Item. This channel is then evaluated by the procedural modelling system, and it's functions are called to perform the mesh edit.

Whilst we provide a method for automatically generating a mesh operation item type and modifier, in some cases, a mesh operation has to be implemented manually, for example, if the mesh operation depends on other items in the scene or time for it's evaluation, there's no way this can be provided by the automatically generated mesh operation item. In these cases, the auto conversion cannot be used to convert the ILxMeshOperation interface into a Mesh Operation item. Instead, a Package and Modifier need to be created that can provide the mesh operation to the procedural system.

The package/item should be of the type LXsITYPE_MESHOP, and the modifier should read the inputs it requires, and output the ILxMeshOperation COM object to the LXsICHAN_MESHOP_OBJ channel. The LXsMESHOP_PMODEL server tag should not be present on the ILxMeshOperation spawned by this modifier.

Sample Code

The following sample code implements the same mesh operation as above, however this time, the package and modifier is manually implemented, rather than being generated automatically by the system. The only difference with the previous sample is the size of the grid is now defined by the scene time, rather than an input channel.

C++
/*
 *	The Package and PackageInstance define the item that is added to the
 *	procedural mesh operation stack.
 */
 
class Instance : public CLxImpl_PackageInstance
{
	public:
		static void initialize ()
		{
			CLxGenericPolymorph	*srv = NULL;
 
			srv = new CLxPolymorph						<Instance>;
			srv->AddInterface		(new CLxIfc_PackageInstance	<Instance>);
 
			lx::AddSpawner ("prim.plane.inst", srv);
		}
};
 
class Package : public CLxImpl_Package
{
	public:
		static void initialize ()
		{
			CLxGenericPolymorph	*srv = NULL;
 
			srv = new CLxPolymorph						<Package>;
			srv->AddInterface		(new CLxIfc_Package		<Package>);
			srv->AddInterface		(new CLxIfc_StaticDesc		<Package>);
 
			lx::AddServer ("prim.plane", srv);
		}
 
		Package () : _inst_spawn ("prim.plane.inst") {}
 
			LxResult
		pkg_TestInterface (
			const LXtGUID		 guid)			LXx_OVERRIDE
		{
			_inst_spawn.TestInterfaceRC (guid);
		}
 
			LxResult
		pkg_Attach (
			void			**ppvObj)		LXx_OVERRIDE
		{
			_inst_spawn.Alloc (ppvObj);
 
			return ppvObj[0] ? LXe_OK : LXe_FAILED;
		}
 
		static LXtTagInfoDesc	 descInfo[];
 
	private:
		CLxSpawner <Instance>	 _inst_spawn;
};
 
LXtTagInfoDesc Package::descInfo[] =
{
	{ LXsPKG_SUPERTYPE,	LXsITYPE_MESHOP },
	{ 0 }
};
 
/*
 *	The Mesh Operation is spawned by the modifier and generates a plane in
 *	the procedural mesh.
 */
 
class MeshOp : public CLxImpl_MeshOperation
{
	public:
		static void initialize ()
		{
			CLxGenericPolymorph	*srv = NULL;
 
			srv = new CLxPolymorph						<MeshOp>;
			srv->AddInterface		(new CLxIfc_MeshOperation	<MeshOp>);
 
			lx::AddSpawner ("prim.plane.op", srv);
		}
 
			LxResult
		mop_Evaluate (
			ILxUnknownID		 mesh_obj,
			LXtID4			 type,
			LXtMarkMode		 mode)			LXx_OVERRIDE
		{
			CLxUser_Mesh		 mesh (mesh_obj);
			CLxUser_Polygon		 polygon;
			CLxUser_Point		 point;
			LXtPolygonID		 poly_id = NULL;
			LXtPointID		 point_id[4];
			LxResult		 result = LXe_FAILED;
			LXtVector		 pos;
			double			 size = 0.5;
			static double		 positions[4][3] = {{-0.5, 0.0, -0.5},
							            { 0.5, 0.0, -0.5},
							            { 0.5, 0.0,  0.5},
							            {-0.5, 0.0,  0.5}};
 
			size = _size * 2.0;
 
			if (mesh.test ())
			{
				polygon.fromMesh (mesh);
				point.fromMesh (mesh);
 
				if (polygon.test () && point.test ())
				{
					for (unsigned i = 0; i < 4; i++)
					{
						LXx_VSCL3 (pos, positions[i], size);
						point.New (pos, &point_id[i]);
					}
 
					polygon.New (LXiPTYP_FACE, point_id, 4, 0, &poly_id);
					mesh.SetMeshEdits (LXf_MESHEDIT_GEOMETRY);
 
					result = LXe_OK;
				}
			}
 
			return result;
		}
 
		double			 _size;
};
 
/*
 *	The Modifier is associated with the all items of our type, and it reads
 *	time as an input, spawns the mesh operation and writes it to the mesh
 *	operation object channel.
 */
 
class ModifierElement : public CLxItemModifierElement
{
	public:
		ModifierElement (
			CLxUser_Evaluation	&eval,
			ILxUnknownID		 item_obj)
		{
			CLxUser_Item		 item (item_obj);
 
			_time_index = -1;
			_output_index = -1;
 
			if (item.test ())
			{
				/*
				 *	Allocate time as an input and the mesh
				 *	operation object as an output.
				 */
 
				_time_index = eval.AddTime ();
				_output_index = eval.AddChan (item, LXsICHAN_MESHOP_OBJ, LXfECHAN_WRITE);
			}
		}
 
			void
		Eval (
			CLxUser_Evaluation	&eval,
			CLxUser_Attributes	&attr)			LXx_OVERRIDE
		{
			CLxUser_ValueReference	 val_ref;
			MeshOp			*meshOp = NULL;
			ILxUnknownID		 meshOp_obj = NULL;
			double			 time = 0.0;
 
			CLxSpawner <MeshOp>	 spawner ("prim.plane.op");
 
			if (_output_index < 0)
				return;
 
			if (_time_index >= 0)
				time = attr.Float (_time_index);
 
			/*
			 *	Spawn the mesh operation and copy the time channel to
			 *	it for the size.
			 */
 
			meshOp = spawner.Alloc (meshOp_obj);
			if (MeshOp)
				meshOp->size = time;
 
			/*
			 *	Write the mesh operation into the mesh operation item
			 *	output channel.
			 */
 
			if (attr.ObjectRW (_output_index, val_ref))
				val_ref.SetObject (meshOp_obj);
 
			/*
			 *	Release the mesh operation COM object, as we spawned
			 *	the item directly.
			 */
 
			lx::UnkRelease (meshOp_obj);
		}
 
	private:
		int			 _output_index, _time_index;
};
 
class ModifierServer : public CLxItemModifierServer
{
	public:
		static void initialize ()
		{
			CLxExport_ItemModifierServer <ModifierServer>	("prim.plane.mod");
		}
 
			const char *
		ItemType ()						LXx_OVERRIDE
		{
			/*
			 *	Associate the modifier with all items of our type.
			 */
 
			return "prim.plane";
		}
 
			CLxItemModifierElement *
		Alloc (
			CLxUser_Evaluation	&eval,
			ILxUnknownID		 item_obj)		LXx_OVERRIDE
		{
			return new ModifierElement (eval, item_obj);
		}
};
 
void initialize ()
{
	Package::initialize ();
	Instance::initialize ();
	MeshOp::initialize ();
	ModifierServer::initialize ();
}