Overlays can be attached to a node, and that node can be a user plugin or an existing RAYZ node - that means that you can define your own interfaces for existing RAYZ nodes, for further customization.
When an Overlay is not attached to any node, it appears in the Image
Viewer menu, and becomes available as an overlay at any time.
For example, the builtin overlay for displaying Video Safe is an
overlay that is not attached to any node:
Overlays are described, as usual, by a structure, in this case the OverlayInfo structure. This looks like this:
static RPI_OverlayInfo oinfo = { { "internal name", "menu name", "author", "version", "help URL", "icon name" }, Init, Shutdown, CreateInstance, DestroyInstance, SourceChanged, FullSizeChanged, ParameterChanged, SourceOutOfDate, OverlayRender, OverlayLeftMouseDown, OverlayLeftMouseDrag, OverlayLeftMouseUp, OverlayMouseEnter, OverlayMouseDrag, OverlayMouseExit, node_to_attach_to, getFullScreenEvents };This structure must be registered, as with the node and image op structures. This is accomplished with the cpiRegisterOverlay() call. The structure must also be unregistered when you exit RAYZ, with the cpiUnregisterOverlay() call. Notice that you register the overlay's address, while you unregister the overlay's name. These calls typically look like the following:
CPIDSOEXPORT CPI_Bool rpiPluginInit( void ) { CPI_Bool retval = CPI_TRUE; // you register with the structure's address retval = cpiRegisterImageOp( &opinfo ); if ( retval ) retval = cpiRegisterNode( &ninfo ); if ( retval ) retval = cpiRegisterOverlay( &oinfo ); return retval; } ////////////////////////////////////////////// // unregister everything void upiPluginCleanup( void ) { // you unregister with the internal name cpiUnregisterImageOp( "cropcircle" ); cpiUnregisterNode( "cropcircle" ); cpiUnregisterOverlay( "cropcircle" ); }
The fields in the overlay structure have the following meanings:
Initialize - Function called once when RAYZ starts up.
Shutdown - Function called once when RAYZ shuts down.
CreateInstance - This function creates an instance of the overlay being defined, generally by allocating a private data structure. This will be used for node overlays, because you can have more than one instance of a node and their state need to be kept distinct. For image viewer overlays, this is less likely to be needed, because even though you can have multiple viewers, the overlays are not likely to have parameters and/or states.
For example, in the CropCircle source, we need to keep track of a circle - its center and radius, plus some other state information. We can use the concept of private data to do this, as follows:
#define CIRCLE_ID 1 #define CROSS_ID 2 typedef struct _overlayState { CPI_Float32 centerX; CPI_Float32 centerY; CPI_Float32 radius; CPI_Float32 startRad; CPI_Uint32 selectedObject; CPI_Float32 myTime; } overlayState; ////////////////////////////////////// // This creates the overlay you are working with, by allocating // the defined data structure and passing it on. CPI_PrivateData CropCircleCreateInstance( void ) { overlayState *retval; retval = (overlayState *)cpiAlloc( sizeof( overlayState ) ); return retval; }Now whenever a private data 'handle' is passed into a user-define routine, the information in the structure will be available. Please refer to the CropCircle.C and CircleRamp.C examples.
DestroyInstance - This is the place to return any memory allocated in CreateInstance(). For example, you might do something like this:
void CropCircleDestroyInstance( CPI_PrivateData handle ) { overlayState *state = (overlayState *)handle; cpiFree( state ); }
SourceChanged - This is called when the input image changes, to allow any values which are based on the image attributes (mainly size, but not only) to be updated. The syntax is:
overlaySourceChanged( CPI_PrivateData handle, CPI_ImageContext fullsize, CPI_Float32 time );
FullSizeChanged - This is called when the size of the input changes. This is different from SourceChanged because the same source node/image may be connected, but that image may change size for any number of reasons. The syntax of the function to be defined is:
overlayFullSizeChanged)( CPI_PrivateData handle, CPI_ImageContext fullsize, CPI_Float32 time );
ParameterChanged - This is called when a parameter in the overlay toolbar (if any), changes value. The input values are the PrivateData structure and the name of the parameter which has changed. The syntax is:
overlayParmChanged)( CPI_PrivateData handle, const char *parmname );
SourceOutOfDate - If the node (or image viewer) is asked to recompute for any reason (such as a parameter change, either in this node or elsewhere in RAYZ), this routine is called. This is from the example in CropCircle.C:
void CropCircleSourceOutOfDate( CPI_PrivateData handle, CPI_ImageContext fullsize, CPI_Float32 theTime ) { overlayState *state = (overlayState *)handle; cpiGetFloat( &state->centerX, "center.x", theTime ); cpiGetFloat( &state->centerY, "center.y", theTime ); cpiGetFloat( &state->radius, "radius", theTime ); state->myTime = theTime; }
OverlayRender - This is the user-defined rendering routine. The programmer has available a number of standard 2D drawing routines, plus the ability to define and use toolbars and text. Details on these functions are given in the next section Drawing Overlays
OverlayLeftMouseDown -
This routine, and the ones following, are called to service the
appropriate hardware activity. They are only called if you have a current
object under the cursor. The input values for each are
handle | pointer to your private data structure |
objectID | the ID of the overlay image that is under the cursor |
x, y | the current x,y position of the cursor, in the range 0.0 - 1.0 |
keyMod | any modifier key with is pressed, one of CPI_CTRL_KEY, CPI_ALT_KEY or CPI_SHIFT_KEY. |
As a general rule, the mouse down updates values and locks the current object, the mouse drag then updates node values, and the mouse up unlocks the current selection.
For example, here is the MouseDown() routine from CropCircle.C
void CropCircleLeftMouseDown( CPI_PrivateData handle, CPI_Uint32 objectID, CPI_Float32 x, CPI_Float32 y, CPI_Uint32 keyMod ) { overlayState *state = (overlayState *)handle; state->selectedObject = objectID; // compute radius to here, and store difference as error // factor for mouse dragging state->startRad = getRad( x, y, state->centerX, state->centerY ); // prevent other objects from getting events, for example // if you drag this one across another one cpiSetSelectLock( CPI_TRUE ); }
OverlayLeftMouseDrag - See OverlayLeftMouseDown.
OverlayLeftMouseUp - See OverlayLeftMouseDown.
OverlayMouseEnter - This routine and the next two (Drag and Exit) provide entry points for mouse activity which does not involve holding down the mouse button. You might want to know this to take care of highlighting selectable objects, for example. See the header file CPI_OverlayProvider.h for syntax.
OverlayMouseDrag - This is called while the mouse is moving over an object which was previously entered.
OverlayMouseExit - This is called when the mouse leaves an object.
attach_to_node - This is a string, which is the internal name (not the menu name) of the node to attach this overlay to.
If this string is NULL, the overlay appears in the Image Viewer overlay menu, along with RAYZ own built-in overlays. This is how the Mask185.C overlay works - this source example masks out portions of the image outside of the 1:1.85 ratio.
RAYZ does not care if the node name is a plugin or one of its own built-in nodes, so in theory you can attach your own overlays to RAYZ's nodes, such as brightness. In order to facilitate this, the internal names of all RAYZ nodes are given below.
add | atop | bitdepth | blur | brightness | bumpmap | channelswap | chromakey |
color | colorbars | colorcorrect | colorcurves | comment | contrast | convolve | cornerpin |
crop | degrain | deinterlace | diff | dissolve | edge | emboss | erodedilate |
fstops | flipflop | gamma | gradient | grain | hueadjust | imagein | indexedcolor |
inside | interlace | invert | lintolog | logtolin | lumakey | matchmove | multicomp |
merge | meters | minmax | monochrome | multiply | group | noise | outside |
over | posterize | premultiply | printerlights | pulldown | pushup | rank | resize |
roto | screen | sequence | sharpen | skew | split | stabilize | subtract |
switch | text | timeblur | track | transform | ultimatte_ae | ultimatte_cc | ultimatte_csc |
ultimatte_gk | ultimatte_pfg | unpremultiply | unsharpmask | under | variableblur | vectorblur | vectorwarp |
videosafe | xpresso | zcomp |
Graphics Routines | |||
---|---|---|---|
DrawLine | DrawRect | DrawCircle | DrawEllipse |
DrawArc | DrawFilledRect | DrawFilledCircle | DrawFilledEllipse |
DrawFilledArc | DrawText | ||
Arbitrary Shapes | |||
BeginLine | LineVertex | EndLine | |
BeginPoly | BeginFilledPoly | PolyVertex | EndPoly |
BeginBezier | BezierVertex | EndBezier | |
Utility Functions | |||
StartNewObject | SetColor | DoRedraw | SetSelectLock |
Toolbar Functions | |||
StartToolbar | EndToolbar |
void cpiDrawLine( const CPI_Float32 x1, const CPI_Float32 y1, const CPI_Float32 x2, const CPI_Float32 y2 ) void cpiDrawRect( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 w, const CPI_Float32 h ) void cpiDrawFilledRect( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 w, const CPI_Float32 h ) void cpiDrawCircle( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 r ) void cpiDrawFilledCircle( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 r ) void cpiDrawEllipse( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 rx, const CPI_Float32 ry ) void cpiDrawFilledEllipse( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 rx, const CPI_Float32 ry ) void cpiDrawArc( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 r, const CPI_Float32 a, const CPI_Float32 b ) void cpiDrawFilledArc( const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 r, const CPI_Float32 a, const CPI_Float32 b ) void cpiDrawText( const CPI_Uint32 alignment, const CPI_Float32 x, const CPI_Float32 y, const CPI_Float32 w, const CPI_Float32 h, const char *msg ) where alignment is one of CPI_ALIGN_LEFT CPI_ALIGN_CENTER CPI_ALIGN_RIGHT CPI_ALIGN_BOTTOM_LEFT CPI_ALIGN_BOTTOM_CENTER CPI_ALIGN_BOTTOM_RIGHT CPI_ALIGN_TOP_LEFT CPI_ALIGN_TOP_CENTER CPI_ALIGN_TOP_RIGHT
// Define an arbitrary line void cpiBeginLine( void ); void cpiLineVertex( const CPI_Float32 x, const CPI_Float32 y ); void cpiEndLine( void ); // Define an arbitrary polygon, as outline or solid filled shape void cpiBeginPoly( void ); void cpiBeginFilledPoly( void ); void cpiPolyVertex( const CPI_Float32 x, const CPI_Float32 y ); void cpiEndPoly( void ); // Define an arbitrary bezier shape void cpiBeginBezier( void ); void cpiBezierVertex( const CPI_Float32 x, const CPI_Float32 y ); void cpiEndBezier( void );
// Start the definition of a new object. All subsequent graphics calls // will be associated with this object ID. It is not necessary to close // object - starting an object implies closing the previous one. void cpiStartNewObject( CPI_Uint32 objectID ) // Set the current color. This color is associated with all subsequent // graphics calls void cpiSetColor( const CPI_Float32 red, const CPI_Float32 green, const CPI_Float32 blue ); // Force a redraw of all defined objects - programmers must explicitly // call this routine void cpiDoRedraw( void ); // Lock the current object, to prevent picking void cpiSetSelectLock( CPI_Bool lock );
Here is an example from the CropCircle node:
void CropCircleRender( CPI_PrivateData handle, CPI_Bool isPicking ) { CPI_Float32 radius; overlayState *state = (overlayState *)handle; // state is a local pointer to our private data structure radius = state->radius * 0.5; if ( radius <= 0 ) radius = 0.075; if ( radius > 1 ) radius = 1; // each collection of lines or shapes that you want to be // separately selectable should be delimited by a call to // cpiStartNewObject. The ID that you pass will be returned // in the selection routine, so you know what the user has // selected. cpiStartNewObject( CIRCLE_ID ); cpiSetColor( 0.1, 0.1, 1.0 ); cpiDrawCircle( state->centerX, state->centerY, radius ); // define a second 'object' cpiStartNewObject( CROSS_ID ); cpiDrawLine( state->centerX - 0.05, state->centerY, state->centerX + 0.05, state->centerY ); cpiDrawLine( state->centerX, state->centerY - 0.05, state->centerX, state->centerY + 0.05 ); }
Toolbar widgets are defined just as they are for the Node Parameter panel. A toolbar can contain the following kinds of widgets:
Menu Button Button Strip Toggle Icon Button Icon Button Strip Icon ToggleAs an example, here is the relevant code from Toolbar.C, one of the source examples in the Overlays directory. This shows how the toolbar is defined; after that we show how to obtain values from the toobar.
CPI_Bool ToolbarOverlayInit( void ) { // To define a toolbar, first declare one open cpiStartToolbar(); // Now add GUI widgets just as you would for node parameters // define a menu cpiAddMenu( "results", "Results", 0, items, "Choose a result from the menu", NULL ); // define a button strip cpiAddButtonStrip( "animal", "Animal", 1, CPI_PARM_DEFAULT, animals, "Choose an animal mode", NULL ); // here we define an icon toggle // See the node example Widgets.C for details cpiRegisterIconData( "toolbar_Off", 24, 18, off_data, 255, 0, 255 ); cpiRegisterIconData( "toolbar_On", 24, 18, on_data, 255, 0, 255 ); cpiDefineIcon( "toolbar_Off", "toolbar_Off", NULL, NULL, "toolbar_Off", NULL, NULL, 255, 0, 255 ); cpiAddIconToggle( "itoggle", "toolbar_Off", CPI_FALSE, CPI_PARM_DEFAULT, "Toggle button with icon", NULL ); // then close the toolbar, name it, and attach it to an overlay cpiEndToolbar( "toolbarstrip", // name of overlay "Toolbar Strip", // label CPI_WINDOW_BOTTOM, // default alignment CPI_TRUE, // allow horizontal layout? CPI_TRUE ); // allow vertical layout? return CPI_TRUE; }When one of the toolbar widgets is changed by the user, the callback function ParmChanged() is called with a pointer to the privately defined data, and the name of the parameter which changed. The name is the name string used to define the widget. For example, the toolbar described in the code above has three widgets whose names are "results", "animal", and "itoggle."
Here is the callback function for the Toolbar example:
static void ToolbarParmChanged( CPI_PrivateData handle, const char *parmname ) { overlayState *state = (overlayState *)handle; CPI_Int32 choice; char newstring[100]; if ( NULL != state && cpiGetInteger( &choice, parmname, 0.0F ) ) { sprintf(newstring, "parameter %s, choice = %d\n", parmname, choice ); cpiSetString( newstring, "text", 0.0F, CPI_FALSE ); } }This retrieves the state of the widget that changed, and then updates the text entry area with that state value, (using cpiSetString() ), as feedback to the user.
See CircleRamp.C, SimpleOverlay.C and Mask185.C for examples.