Section 2 - Adding Overlays

Overlay Graphics are graphics drawn on top of the image in the image viewer. These are typically used to provide interactive controls for node parameters, but they can also be used to provide image masks and charts. For example, the CircleRamp node has blue overlay controls which look like the following:

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:

Coding Overlays

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"
    },
    Init,
    Shutdown,
    CreateInstance,
    DestroyInstance,
    SourceChanged,
    FullSizeChanged,
    SourceOutOfDate,
    OverlayRender,
    OverlayLeftMouseDown,
    OverlayLeftMouseDrag,
    OverlayLeftMouseUp,
    OverlayMouseEnter,
    OverlayMouseDrag,
    OverlayMouseExit,
    attach_to_node
};
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. These would 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.

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.

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 - these are given as follows. Specific arguments are defined after the table.

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

All arguments to these routines are dimensionless values between 0.0 and 1.0, except where noted. The specifics of each function are given here - this is taken from the header file CPI_Overlay.h.

Graphics Routines

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
Arbitrary Shapes

// 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 );
Utility Functions

// 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 );
}

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.
See the header file CPI_OverlayProvider.h for syntax.

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.

RAYZ Nodes - Internal Names
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 ultimatte_ae ultimatte_cc
ultimatte_csc ultimatte_gk unpremultiply unsharpmask under variableblur vectorblur vectorwarp
videosafe xpresso zcomp

Source Examples

See CircleRamp.C, SimpleOverlay.C and Mask185.C for examples.


[Previous Page] [Next Page]
[Table of Contents] [Index]

Copyright © 2002 Silicon Grail Inc.
736 Seward Street, Hollywood, CA 90038