[SESI logo]

Houdini Development Toolkit - Version 6.5

Side Effects Software Inc. 2004

General Operators

Local Variables

Each OP can have local variables which are defined over the scope of its cook (i.e. active when the cook method has been called). These variables are defined in the OP_Operator constructor (which defines the operator). Currently all variables must be floating point valued (i.e. no vectors or strings).

The OP_Operator constructor takes an array of CH_LocalVariable's. This class simply contains a string (representing the variable name) and a unique integer (used for evaluation). So, for example, to define 4 local variables for an operator, we might have the following code:

// First, lets get a bunch of uniqe integers enum { VAR_PT, // Current point VAR_NPT, // Total number of points VAR_ID, // Particle ID VAR_LIFE, // Life time }; // Next, we define our local variable table CH_LocalVariable OP_MyNode::myVariables[] = { { "PT", VAR_PT }, { "NPT", VAR_NPT }, { "ID", VAR_ID }, { "LIFE", VAR_LIFE }, { 0 } // End the table with a null entry }; During evaluation of the parameters of the OP, these variables become "active". If the variable is found in an expression, the getVariableValue callback will be invoked. It is your responsibility to return a value for the variable in question. For example, in the above example:
float OP_MyNode::getVariableValue(int index) { GEO_Point *ppt; int *id; float *life; if (myCurrPoint < 0) // Sorry, we're in an invalid state return 0; switch (index) { case VAR_PT: return myCurrPoint; case VAR_NPT: return myTotalPoints; case VAR_ID: ppt = myInputGeo->points()(myCurrPoint); id = (int *)ppt->getAttribData(myInputIdOffset); return (float)*id; case VAR_LIFE: ppt = myInputGeo->points()(myCurrPoint); life = (float *)ppt->getAttribData(myInputLifeOffset); return life[0]/life[1]; } return 0; // Whoops, forgot a variable } The code for cooking might look something like: OP_ERROR OP_MyNode::cookMe(OP_Context &context) { ... // First, let's set up the member data we'll need for // evaluation of variables. myInputGeo = input(0, context.myTime); myInputIdOffset = myInputGeo->findPointAttrib("id", sizeof(int), GEO_ATTRIB_INT); myInputLifeOffset = myInputGeo->findPointAttrib("life", sizeof(float)*2, GEO_ATTRIB_FLOAT); myTotalPoints = myInputGeo->points().entries(); // Now, we loop through each point, doing expression // evaluation INSIDE the loop. for (myCurrPoint = 0; myCurrPoint < myTotalPoints; myCurrPoint++) { // In the POS() method, it's possible that the expression // would use one of our local variables, so pos.x() = POSX(context.myTime); ... } myCurrPoint = -1; // Make sure to flag that we're in a // bad state ... } The reason for setting the flag myCurrPoint to -1 outside of the loop is that occasionally, it is possible for your getVariableValue method to be called out of context. The reason for this is complicated, but it has to do with displaying the values of the parameters in the dialog boxes (i.e. the parameters need to be evaluated, but the OP isn't being cooked). In this case, it's try to return a reasonable value.
Table of Contents
Operators | Surface Operations | Particle Operations | Composite Operators | Channel Operators
Material & Texture | Objects | Command and Expression | Render Output |
Mantra Shaders | Utility Classes | Geometry Library | Image Library | Clip Library
Customizing UI | Questions & Answers

Copyright © 2004 Side Effects Software Inc.
477 Richmond Street West, Toronto, Ontario, Canada M5V 3E7