Size Issues in RAYZ

Scaling from Full Size

The RAYZ image viewer presents the user with 4 options for viewing the output of any given node: Full, Medium, Low and Fit. These choices are implemented as scaling factors from the Full Size, whose scale factor is 1.0.

The Exec() function has a scaleX and scaleY parameter, and these values are used to tell the programmer what fraction of the input image size the result is to be. Recall that the Exec function signature looks like this:

static CPI_ImageOp
SimpleExec( CPI_PrivateData  handle,
            CPI_Float32      myTime,
            CPI_Uint8        quality,
            CPI_Uint32       nodeOutput,
            CPI_Bool         viewerOutput,
            CPI_Float32      scaleX,
            CPI_Float32      scaleY )

{
Assuming that the users set the "computation size" in the menu to Medium, then the Exec function will be called with scaleX = 0.5 and scaleY = 0.5 (Note that these are the default values for Medium and that the user can change them, via the Preferences, to be any other set of values). For "Fit", the scale factors will be whatever they need to be to keep the image fully in view.

The programmer may or may not need to take this into account. For source nodes, such as Grid or CircleRamp, this information is very important, since you want to generate the correct image for any given scale. For example, the Grid example uses these values in this way:

    gridData->lineWidth[0] = cpiRound( linewid * scaleX );
    gridData->lineWidth[1] = cpiRound( linewid * scaleY );
    if ( gridData->lineWidth[0] < 1 )
         gridData->lineWidth[0] = 1;
    if ( gridData->lineWidth[1] < 1 )
         gridData->lineWidth[1] = 1;

    gridData->lineGap[0] = cpiRound( linegap * scaleX );
    gridData->lineGap[1] = cpiRound( linegap * scaleY );
    if ( gridData->lineGap[0] < 1 )
         gridData->lineGap[0] = 1;
    if ( gridData->lineGap[1] < 1 )
         gridData->lineGap[1] = 1;
where gridData is a pointer to the private data structure which holds, among other things, information about the grid parameters. If this scaling were not done, the grid parameters would be too large for the image being created. In general, image parameters should be handled as relative to the size of the image, not as absolute values.

Note that this is not the same as the zoom in/out values. When you zoom in or out, the scaling of the image is handled after the given size is computed. So zooming out to 1/2 does not save any computation - the image is still computed at Full Size, then scaled down by RAYZ. However, asking for a Medium Size image does save computation, since now only half the image (in each dimension) is calculated.

Requests for Different Sizes

Nodes which are not sources will not usually be worried about using the scaleX and scaleY parameters, because they will tend to operate on a pixel-by-pixel basis (though of course there are other possibilities).

However, even for nodes which take inputs, you should not assume that your plugin will only be handed images of a certain size. Nodes are given requests to execute at various sizes for various reasons. One reason would be if your plugin is executing on a multi-processor machine - in that case, each thread will call the Exec() function with a sub-image region of the whole incoming image.

Another reason for execution requests at odd sizes would be if the user wants to see a thumbnail on the plugin node. In that case, RAYZ does not simply scale down the full size output - it makes a specific request to the node to generate a thumbnail image (usually, but not always, 60 x 45 pixels). So your plugin needs to be generalized to handle any size requests that come in. That also means not assuming that the first line is line 0, or that the first pixel is pixel 0.

The best way to do this is to use the myContext.sizeX & Y and myContext.offsetX & Y values, and to use the function cpiGetLine() to access the appropriate pixel for processing. For example, this processing routine (taken from Simple.C), assumes nothing about the size or offset of the incoming image. Loops do not begin or end at magic numbers like 0, and the offset is not assumed to be 0. It also checks for a user Abort signal from the interface before processing each scanline.

template  static
void simple( CPI_Image  &input,
             CPI_Image  *result,
             T           max)
{
    CPI_Int32    x, y, endX, endY, i, j = 0;
    CPI_Int32    chans = result->myContext.channels;
    T           *pin, *pout;

    endX    = result->myContext.offsetX + result->myContext.sizeX;
    endY    = result->myContext.offsetY + result->myContext.sizeY;

    for ( y = result->myContext.offsetY; y < endY; y++ )
    {
        // this detects the user requesting an early exit
        if ( cpiIsProcessingAborted() )
            break;

        // Notice that we use cpiGetLine to avoid any sub-image issues
        // as rayz may ask us to process a small part of a larger image
        pin     = (T *)cpiGetLine( &input, y );
        pout    = (T *)cpiGetLine( result, y );
        j       = 0;

        for ( x = result->myContext.offsetX; x < endX; x++ )
        {
            // copy each channel
            for ( i = 0; i < chans; i++, j++ )
                pout[j] = pin[j];
        }
    }
}

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

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