ColorRamp.C

This demonstrates a node with no inputs, such as the color node. This also shows how a node can change its size and/or type depending on user input.

/*
   Plugin Tutorial
   example 6 - CircleRamp.C
   Generate a circular ramp or matte image. This node works like 
   the color node, in that it takes no input and generates an image
   of user-selectable size.
 */

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <string.h>
#include <math.h>
#include "cpi.h"

#define TRUE    1
#define FALSE    0

template <class T>
void make_ramp(T *image, float radii[], float values[], int oval,
                int chans, T max, int sizeX, int sizeY)
{
    int        i, x, y;
    float    dx, dy, xcen, ycen, radius, d;
    float    minval=values[0], maxval=values[1];
    float    minrad=radii[0], maxrad=radii[1], scalefac;
    T        *ptr, val;

    ptr = image;
    xcen = (float)sizeX / 2.0;
    ycen = (float)sizeY / 2.0;

    // next 3 lines just for boundary conditions
    d = maxrad - minrad;
    if (fabs(d) < 0.0001)
        minrad = maxrad - 0.0001;

    scalefac = (maxval - minval)/(maxrad - minrad);
    radius = (sizeX >= sizeY ? ycen : xcen);

    for (y = 0; y < sizeY; y++)
    {
        for (x = 0; x < sizeX; x++)
        {
            // for each (x, y) compute d, the distance to the
            // center of the image
            dx = (float)x - xcen;
            dy = (float)y - ycen;
            d = sqrt(dx*dx + dy*dy) / radius;

            // make it so that 0.0 <= d <= 1.0
            if (d < minrad) d = minrad;
            else if (d > maxrad) d = maxrad;
            d = (d - minrad)*scalefac + minval;

            val = d * max;        // compute color
            
            // put in color, update pointer
            for (i = 0; i < chans; i++)
                *ptr++ = val;
        }
    }
}

// Tell Chalice to put this plugin into the I/O menu
CPI_PluginType upiPluginType(void)
{
    return T_IO;
}

// because we are computing pixel values based on distance from the
// center of the image, slicing the image would mess up our 
// calculations. Deal with this by forcing Chalice to cook the 
// image at full size.
int upiCookFull(void)
{
    return TRUE;
}

// This section defines the user interface (UI) 
#define        RADIUS    "In Out Radius"
#define        AMOUNT    "In Out Value"
#define        SIZE    "Width   Height"
#define     OUTPUT    "Image Type"
#define     BITS    "Image Depth"

CPIDSOEXPORT void upiCreateParameters( void )
{
    char    *cmenu[] = {"RGBA", "RGB", "Alpha", NULL};
    char    *bmenu[] = {"8 bit", "16 bit", "Float", NULL};
    float     rvals[] = {0.0, 1.0};
    float     avals[] = {1.0, 0.0};
    int          svals[] = {512, 512};

    cpiAddTab("Circle Ramp");
    cpiAddFloatVector(RADIUS, 2, rvals, 0.0, 1.0, P_MINMAX|P_ANIMATE);
    cpiAddFloatVector(AMOUNT, 2, avals, 0.0, 1.0, P_MINMAX|P_ANIMATE);
    cpiAddIntVector( SIZE, 2, svals, 1, 1024, P_MIN|P_ANIMATE);
    cpiAddMenu(OUTPUT, 0, cmenu, 0);
    cpiAddMenu(BITS, 0, bmenu, 0);
}

CPIDSOEXPORT void upiNumberOfInputs( int *min, int *max )
{
    *min = *max = 0;
}

// This tells Chalice that we are going to create a new output
CPIDSOEXPORT int upiResultInput( CPI_ImageContext *result )
{
    return RESULT_SEPARATE;
}

// This tells Chalice that whenever a parameter is changed, the output
// will need to be recooked
void upiParameterChanged(char *name)
{
    cpiInvalidateOutput();
}

// This is where the plugin decides how large an image, and of what
// type, it is supposed to create.

CPIDSOEXPORT int upiOutputContext(CPI_ImageContext *output, float time)
{
    int    chans, pelType, sizeX, sizeY;

    cpiGetIntVector( SIZE, time, 0, &sizeX);
    cpiGetIntVector( SIZE, time, 1, &sizeY);
    output->fullX = sizeX;
    output->fullY = sizeY;

    cpiGetInteger(BITS, 0.0, &pelType);
    if (pelType == 0)
        output->pelType = P_INT8;
    else if (pelType == 1)
        output->pelType = P_INT16;
    else if (pelType == 2)
        output->pelType = P_FLOAT32;
    else
    {
        cpiError("Unknown channel type");
        return 1;
    }

    cpiGetInteger(OUTPUT, 0.0, &chans);
    if (chans == 0)
        output->channels = 4;        // rgba
    else if (chans == 1)
        output->channels = 3;        // rgb
    else if (chans == 2)
        output->channels = 1;        // alpha only
    else
    {
        cpiError("Unknown output type");
        return 1;
    }
    output->offsetX = output->offsetY = 0;

    return 0;
}

CPIDSOEXPORT int upiProcessImage( CPI_Image *result )
{
    int        sizeX, sizeY, type, oval, chans;
    float    radii[2], values[2], time;

    // unload values from UI fields, and pass to ramp making
    // subroutine
    sizeX = result->info.sizeX;
    sizeY = result->info.sizeY;
    chans = result->info.channels;
    time = result->info.time;
    cpiGetFloatVector( RADIUS, time, 0, radii+0);
    cpiGetFloatVector( RADIUS, time, 1, radii+1);
    cpiGetFloatVector( AMOUNT, time, 0, values+0);
    cpiGetFloatVector( AMOUNT, time, 1, values+1);
    cpiGetInteger( OVAL, 0.0, &oval);

    switch( result->info.pelType )
    {
        case P_INT8:
        {
            make_ramp( (unsigned char *)result->data,
                      radii, values, oval, chans,
                      (unsigned char)UCHAR_MAX, sizeX, sizeY);
            break;
        }
        case P_INT16:
        {
            make_ramp( (unsigned short *)result->data,
                      radii, values, oval, chans,
                      (unsigned short)USHRT_MAX, sizeX, sizeY);
            break;
        }
        case P_FLOAT32:
        {
            make_ramp( (float *)result->data,
                      radii, values, oval, chans,
                      (float)1.0F, sizeX, sizeY);
            break;
        }
        default:
            cpiError( "Unknown pixel type" );
            return 1;
    }
    return 0;
}
[Table of Contents] [Index]

Copyright © 1998 Silicon Grail Inc.
710 Seward Street, Hollywood, CA 90038