HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Writing a ROP

Introduction

Several steps are required to create a custom ROP node:

  1. Create a new class which inherits from ROP_Node.
  2. Define any parameters found on the node.
  3. Add the new node type to the table of other ROP node types.
  4. Override the rendering methods to perform the actual output operation.

Each of these steps is discussed in more detail below. Alternatively, a full example can be found in ROP/ROP_Dumper.C and ROP/ROP_Dumper.h.

Inheriting from ROP_Node

The first step in creating a custom ROP operator is to inherit from ROP_Node. ROP_Node itself does most of the background work required, and only delegates a few tasks, such as initializing, rendering, and cleaning up afterwards.

class ROP_API ROP_Dumper : public ROP_Node
{
public:
static OP_TemplatePair *getTemplatePair();
static OP_VariablePair *getVariablePair();
static OP_Node *myConstructor(OP_Network *net, const char*name,
protected:
ROP_Dumper(OP_Network *net, const char *name, OP_Operator *op);
virtual ~ROP_Dumper();
virtual int startRender(int nframes, float s, float e);
virtual ROP_RENDER_CODE renderFrame(float time, UT_Interrupt *boss);
};

Note that the constructors for ROPs are protected, and so a ROP node cannot be allocated explicitly. Instead, the task is performed by a static factory method ROP_Dumper::myConstructor(). It takes the parent network, node name, and operator type as parameters. Static getTemplatePair() and getVariablePair() provide access to this node's parameter templates and variables, correspondingly.

Defining Node Parameters

The next step is to define any parameters you may need on the node. Each ROP node has a base set of pre-defined parameters which are valid for every ROP node, as well as any other parameters specific to each particular node type. Base parameters including first and last render frame, whether to render an animation or a single frame, and more.

Custom parameters are generally defined as global variables in the ROP's C file. The overall parameter interface is generally defined as a parameter template static variable in the getTemplates() function. The example below adds a custom file output parameter, as well as five standard ROP parameters, to the node. The standard parameters represent "Render" and "Render Control Dialog" buttons, as well as the "Valid Frame Range", "Start/End/Inc" and "Render With Take" ROP parameters.

static PRM_Name theFileName("file", "Save to file");
static PRM_Default theFileDefault(0, "junk.out");
static PRM_Template* getTemplates()
{
static PRM_Template *theTemplate = 0;
if (theTemplate)
return theTemplate;
// Allocate our templates if we haven't done so yet.
theTemplate = new PRM_Template[6];
// Set our custom parameter first
theTemplate[0] = PRM_Template(PRM_FILE, 1, &theFileName, &theFileDefault);
// Set standard ROP parameters next. They are defined in ROP_Templates.h
}

Adding a New ROP Type

To be able to use the newly added ROP node type in Houdini, it must be added to the ROP types table first. This is done in the newDriverOperator() method which has the table passed to it as an argument:

{
// Node type
"dumper",
// Node type label
"Dump Tree",
ROP_Dumper::myConstructor,
// Parameter templates
ROP_Dumper::getTemplatePair(),
// Minimum number of connectors
0,
// Maximum number of connectors
0,
// Variables
ROP_Dumper::getVariablePair(),
// Operator flags, defined in OP_Operator.h
}

This method is called by Houdini after loading the library file with the custom ROP node.

Performing Output

To perform the actual output, ROP_Node calls three methods which a custom ROP should override to perform its own tasks. ROP_Node::startRender() is called before the rendering begins to do any initialization that may be needed. If it returns false, the rendering process is aborted; otherwise, ROP_Node::renderFrame() is called for each frame to be rendered, as specified by the corresponding ROP parameters. This function should return one of three return codes, which tell Houdini whether to stop rendering, continue, or retry the frame (ROP_ABORT_RENDER, ROP_CONTINUE_RENDER, ROP_RETRY_RENDER in ROP_Node.h).

After the rendering of all frames is done, Houdini calls ROP_Node::endRender(), which returns one of the three codes above to indicate the result of its operations.

Examples

An example of a custom ROP node can be found in ROP/ROP_Dumper.C and ROP/ROP_Dumper.h.