In this first step, the plugin code exists already, so the
steps are very simple:
(note: this is for IRIX/linux. For Windows NT, you will have to modify
the above to your own compiling setup. Environment variables are also
set up differently on NT. More detail is given in
Compiling and Installing Plugins
Things to note:
There is a distinction between the 'node name', which is sometimes
called the internal name, and the 'menu name', which is the string used
in the node menu. Notice how, in the Node Panel, the node is shown as
being of type 'menuname', and of default name 'nodename1'.
You will also see in the sample code that there is a third string,
'opname', which is the name of the image operation that the node performs.
This is a key distinction in RAYZ - a NODE is a graphical thing you move around on the worksheet, and which you can change the parameters for interactively. An IMAGE OPERATION (often called an IM) is the actual code that does something to the image. These are separate things. This is because RAYZ is scriptable - the image op is basically the scripting command version of the node.
By convention in RAYZ, the menu name is capitalized, and the node name is the same name, in lower case. Sometimes, the menu name is not the same as the node name, especially for File Formats - we will see that later.
So far, our node doesn't do much - it just copies its input to its output. Let's add a parameter to the node, in this case a single value between 0 and 1 to multiply the incoming image by.
Here is the plugin code, with new lines highlighted:
/////////////////////////////////////////
// The init routine is called once, and typically is used to
// define the user input controls
static CPI_Bool
SimpleInit( void )
{
cpiAddFloat( "bright", "Brightness", 1.0, 0.0, 1.0,
CPI_PARM_ANIMATABLE | CPI_PARM_CLAMPMIN,
"This controls the brightness",
NULL );
return CPI_TRUE;
}
//////////////////////////////////////////
// This is called when an image is required
// The basic structure of these routines is:
// 1. get the inputs
// 2. get the parameters from the user interface
// 3. allocate metadata and copy the parameters to it
// 4. add the image op(s) to the list of operations
CPI_ImageOp
SimpleExec( CPI_Float32 myTime,
CPI_Uint8 quality,
CPI_Uint32 nodeOutput,
CPI_Uint32 viewerOutput,
CPI_Float32 scaleX,
CPI_Float32 scaleY )
{
CPI_Float32 bright;
CPI_ImageOp retval = NULL;
CPI_ImageOp myInputs;
// get the input
myInputs = cpiGetInputOp( 0, myTime, quality, scaleX, scaleY );
// get the user parameter value
cpiGetFloat ( &bright, "bright", myTime );
// create metadata and copy value to it
CPI_Metadata nodeparms = cpiCreateMetadata();
cpiSetMetaFloat32( nodeparms, "bright", bright );
// if there was input, add this image operation to the list
if ( myInputs != NULL )
retval = cpiAddImageOp( "oneparam", nodeparms, &myInputs, 1 );
cpiDeleteMetadata( nodeparms );
return retval;
}
////////////////////////////////////////////
// This structure, which is required, defines to RAYZ
// the various routines which are part of this plugin.
// Routines which are not required are set to NULL
static RPI_NodeInfo ninfo = {
{
"oneparam", // node name
"Oneparam", // menu name
"Joe Programmer", // author
"v1.0", // version
"", // help URL
"" // icon name
},
SimpleInit, // NodeInit
NULL, // NodeShutDown
NULL, // ParmChanged
NULL, // InputChanged
NULL, // GetRegion
NULL, // GetFullSize
NULL, // GetRange
NULL, // GetErrors
SimpleExec, // Node Execute
NULL, // InputLabel
NULL, // OutputLabel
NULL, // ViewerLabel
NULL, // ViewerOutputs
1, // min inputs
1, // max inputs
1, // min outputs
1, // max outputs
CPI_FALSE // is growable (eg Mcomp)
};
//////////////////////////////////////////////////////////////////////
// Image Op Functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// This is the actual image manipulation routine. It is a templated
// function so that we can write it once, and let the compiler build
// a version for each of 8, 16 and float pixel types.
template
You can find this in the support/plugIns/src directory if you don't want
to type it yourself - it's called SimpleParam.C. Compile it by typing
% make SimpleParam.so
Again, drop it into your plugin directory. Now when you run RAYZ, and
add one of these new nodes (which are called 'oneparam' in the menu), you should see a Node Panel that looks like
this:
Let's modify this node to take a second input. Here is the code that you need to add or modify:
//////////////////////////////////////////
// label the node inputs - this is optional
// Input is the number of the input you want to provide a
// label for, starting at 0 - this label shows up in the
// status line when the user mouses over the connector.
// The first letter of each string is used to label the input
// connector.
const char *
SimpleInputLabel( CPI_Uint32 input)
{
static const char input1[] = {"foreground image"};
static const char input2[] = {"background image"};
if ( input == 0 )
return input1;
else
return input2;
}
//////////////////////////////////////////
// This is called when the node is actually executed
CPI_ImageOp
SimpleExec( CPI_Float32 myTime,
CPI_Uint8 quality,
CPI_Uint32 nodeOutput,
CPI_Uint32 viewerOutput,
CPI_Float32 scaleX,
CPI_Float32 scaleY )
{
CPI_Float32 dissolve;
CPI_ImageOp retval = NULL;
CPI_ImageOp myInputs[2];
myInputs[0] = cpiGetInputOp( 0, myTime, quality, scaleX, scaleY );
myInputs[1] = cpiGetInputOp( 1, myTime, quality, scaleX, scaleY );
cpiGetFloat ( &dissolve, "Dissolve", myTime );
CPI_Metadata nodeparms = cpiCreateMetadata();
cpiSetMetaFloat32( nodeparms, "dissolve", dissolve );
if ( myInputs[0] != NULL && myInputs[1] != NULL )
retval = cpiAddImageOp( "twoinput", nodeparms, myInputs, 2 );
else
retval = false;
cpiDeleteMetadata( nodeparms );
return retval;
}
////////////////////////////////////////////
// This structure defines aspects of the node - user subroutines,
// number of inputs, etc
static RPI_NodeInfo ninfo = {
{
"twoinput", // node name
"Twoinput", // menu name
"Joe Programmer", // author
"v1.0", // version
"", // help URL
"" // icon name
},
SimpleInit, // NodeInit
NULL, // NodeShutDown
NULL, // ParmChanged
NULL, // InputChanged
NULL, // GetRegion
NULL, // GetFullSize
NULL, // GetRange
NULL, // GetErrors
SimpleExec, // Node Execute
SimpleInputLabel, // InputLabel
NULL, // OutputLabel
NULL, // ViewerLabel
NULL, // ViewerOutputs
2, // min inputs
2, // max inputs
1, // min outputs
1, // max outputs
CPI_FALSE // is growable (eg Mcomp)
};
//////////////////////////////////////////////////////////////////////
// Image Op Functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// This is the actual image manipulation routine. It is a templated
// function so that we can write it once, and let the compiler build
// a version for each of 8, 16 and float pixel types.
template
Once again, this has been done for you and placed in
SimpleTwoInput.C. Compile it by typing
% make SimpleTwoInput
Run RAYZ again, and notice that the node now looks like this:
In this example, we have required this node to have two inputs (since they are not connected, the node is marked with red, to indicate an error). Notice that the inputs are labeled 'f' and 'b' - this is under your control, as you can see in the complete source listing. The routine called SimpleInputLabel shows how this is done.
It is also possible to specify one (or more) optional inputs. This is done by setting the appropriate values in the NodeInfo structure. For example, this structure defines a node which takes 3 inputs, only 1 of which is required. Relevant lines are shown in bold:
static RPI_NodeInfo ninfo = { { "twoinput", // node name "Twoinput", // menu name "Joe Programmer", // author "v1.0", // version "", // help URL "" // icon name }, SimpleInit, // NodeInit NULL, // NodeShutDown NULL, // ParmChanged NULL, // InputChanged NULL, // GetRegion NULL, // GetFullSize NULL, // GetRange NULL, // GetErrors SimpleExec, // Node Execute SimpleInputLabel, // InputLabel NULL, // OutputLabel NULL, // ViewerLabel NULL, // ViewerOutputs 1, // min inputs 3, // max inputs 1, // min outputs 1, // max outputs CPI_FALSE // is growable (eg Mcomp) };
By definition, required inputs come are drawn first (topmost), followed by the optional ones.
This quick overview should give you a feeling for how to write and compile node plugins in RAYZ. Of course, you can do a lot more than this - you can define overlays (graphic controls) on the image, you can define new image file formats, and you can define new image display controls (including LUTS) for the image viewer.
All of these are explained in the rest of this documentation.