Your First Tool in Modo

From The Foundry MODO SDK wiki
Revision as of 16:00, 16 October 2019 by TomDym (Talk | contribs) (Basic Tool)

Jump to: navigation, search

Basic Tool

This is a guide to creating your very first tool in Modo and will go in depth to explaining the necessary components required to create a functioning tool. Without adding unnecessary functionality to complicate things. More complicated examples will be added later on in the wiki.

Code Walkthrough

This is is the most basic required to setup a tool within modo to demonstrate how it works.

Use - Once activated using "tool.set tool.basic on" once the user has clicked in the viewport it will output a variable called factor to the I/O output of the event log.


Here we add the required packages to inherit from for our basic tool

  • <lx_tool.hpp> Gives us access to the basic tool methods.
  • <lx_vmodel.hpp> Presents a interface which allows them to participate in mouse input and direct manipulation
  • <lx_vector> Gives us access to modo vector struct.
  • <lxu_attributes.hpp> Packages the internal state of the object into a common format.
  • <lx_plugin.hpp> Allows us to create our tool as a plugin.
  • <lxu_log.hpp> Allows us to write to the Event Log.
#include <lx_tool.hpp>
#include <lx_vmodel.hpp>

#include <lx_vector.hpp>
#include <lxu_attributes.hpp>
#include <lx_plugin.hpp>

#include <lxu_log.hpp>

using namespace lx_err;

Class for printing to the IO Log - Go to Event Logs cog wheel scrool down and click I/O Output

class MyMessage : public CLxLogMessage
	const char * GetFormat()
		return "Hello";

	const char * GetVersion()
		return "0.1";

Just a Utility class to allow us to convert different data types to strings

template <class T> std::string toString(const T & t)
	std::ostringstream oss; // create a stream
	oss << t; // insert value to stream
	return oss.str(); // extract value and return

In order to create our tool we inherit from <CLxImpl_Tool> and <CLxImpl_ToolModel>
To give attributes to our tool we inherit from <CLxDynamicAttributes>

We also define al the methods we wish to use within our tool here.

class BasicTool : public CLxImpl_Tool, public CLxImpl_ToolModel, public CLxDynamicAttributes
	//Output log - Created to output data from our tool
	MyMessage             my_log;

	// Class Methods
	void		  tool_Reset() LXx_OVERRIDE;
	LXtObjectID	  tool_VectorType() LXx_OVERRIDE;
	const char *  tool_Order() LXx_OVERRIDE;
	LXtID4		  tool_Task() LXx_OVERRIDE;
	void		  tool_Evaluate(ILxUnknownID vts) LXx_OVERRIDE;

	unsigned	  tmod_Flags() LXx_OVERRIDE;
	void		  tmod_Initialize(ILxUnknownID vts, ILxUnknownID adjust, unsigned flags) LXx_OVERRIDE;
	const char *  tmod_Haul(unsigned index) LXx_OVERRIDE;

	// Variables
	CLxUser_VectorType	 v_type;



We define our tool attributes here

#include "BasicTool.h"

#define ATTRs_FACTORX "factorX"
#define ATTRs_FACTORY "factorY"
  • Inside of our constructer we first do the following.
    • Define a vector type for our tool - This is the minmum required, in future tools I will show how to add vector stacks like input and symmetry to the tool.
    • Add a Dynamic attribute to out tool to show the output and set its value
      • We define and access the attributes in the order that they are added.
	CLxUser_PacketService	 sPkt;

	sPkt.NewVectorType(LXsCATEGORY_TOOL, v_type);

	attr_SetFlt(0, 1.0);
	attr_SetFlt(1, 1.0);

Tool Reset is called to reset the attributes of our tool.

void BasicTool::tool_Reset()
	attr_SetFlt(0, 0.0);
	attr_SetFlt(1, 0.0);

The next three methods are used to define what type of tool, in this case a state altering tool.

Returns the tool vector type, describing the vector packets required for processing

LXtObjectID BasicTool::tool_VectorType()
	return v_type.m_loc;	// peek method; does not add-ref

Specifies the order in the pipe by returning an Ordinal string

const char *BasicTool::tool_Order()
	return LXs_ORD_ACTR;

Simply defines the type of task performed by this tool. Set this to an Action tool, which basically means it will alter the state of modo.

LXtID4 BasicTool::tool_Task()
	return LXi_TASK_ACTR;

Sets flags that indicate certain attributes about the tool.

  • In this case we are using <LXfTMOD_I0_ATTRHAUL> as we simply want to haul in the viewport, similar to channel hauling.
unsigned BasicTool::tmod_Flags()

Called whenever the tool is activated/deactivated

void BasicTool::tmod_Initialize(ILxUnknownID vts, ILxUnknownID adjust, unsigned int	flags)
	CLxUser_AdjustTool	 at(adjust);
	at.SetFlt(0, 0.0);

Indicates which attribute we want to haul

const char *BasicTool::tmod_Haul(unsigned index)
	if (index == 0) // For hauling Left to right in the viewport
		return ATTRs_FACTORX;
	if (index == 1) // For hauling Top to bottom in the viewport
		return ATTRs_FACTORY;
		return 0;

This is where the tools is evaluated and executes what it is intended to do.

void BasicTool::tool_Evaluate(ILxUnknownID vts)
	double factorX, factorY;

	attr_GetFlt(0, &factorX);
	attr_GetFlt(1, &factorY);

	my_log.Info("Factor X: " + std::to_string(factorX) + " Factor Y: " + toString(factorY));

This initialize method exports our servers. It is dependent on the BasicTool class and includes the interface for all the classes that BasicTool inherited from.

void initialize()
	CLxGenericPolymorph		*srv;
	srv = new CLxPolymorph<BasicTool>;
	srv->AddInterface(new CLxIfc_Tool      <BasicTool>);
	srv->AddInterface(new CLxIfc_ToolModel <BasicTool>);
	srv->AddInterface(new CLxIfc_Attributes<BasicTool>);
	thisModule.AddServer("tool.basic", srv);