CVEX/cvexsample.C

/*
 * Copyright (c) 2013
 *      Side Effects Software Inc.  All rights reserved.
 *
 * Redistribution and use of Houdini Development Kit samples in source and
 * binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. The name of Side Effects Software may not be used to endorse or
 *    promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *----------------------------------------------------------------------------
 * Sample of the CVEX interface to call VEX.
 *
 * CVEX is most efficient when operating on arrays of data.  The interface
 * allows you to create a VEX function to perform some computation.  Instead of
 * hard-coding the algorithm in your C++ code, you can alter the algorithm by
 * running different VEX code.  It allows flexibility in design of your code.
 */

#include <CVEX/CVEX_Context.h>
#include <UT/UT_Vector3.h>
#include <UT/UT_StringArray.h>
#include <MOT/MOT_Director.h>

namespace HDK_Sample {

// This is the array length for the sample program.
#define CV_SIZE 8

// Static methods to fill input variables to the VEX function
static void
fillP(UT_Vector3 *P)
{
    int         i;
    fpreal      t;
    for (i = 0; i < CV_SIZE; i++)
    {
        t = (fpreal)i / (CV_SIZE-1);
        P[i].assign(t, SYSsin(t*M_PI), 0);
    }
}

static void
fillN(UT_Vector3 *N)
{
    int         i;
    for (i = 0; i < CV_SIZE; i++)
        N[i].assign(0, 1, 0);
}

static void
fillST(fpreal32 *s, fpreal32 *t)
{
    int         i;
    for (i = 0; i < CV_SIZE; i++)
    {
        s[i] = (fpreal)i / (CV_SIZE-1);
        t[i] = 1-s[i];
    }
}

//
// Convenience methods to print output from the function
//
static void
dumpFloat(const fpreal32 *v, int n)
{
    int         i;

    printf("%g", v[0]);
    for (i = 1; i < n; i++)
        printf(", %g", v[i]);
}

static void
dumpVector(const UT_Vector3 *v, int n)
{
    int         i;
    printf("{%g,%g,%g}", v[0].x(), v[0].y(), v[0].z());
    for (i = 1; i < n; i++)
        printf(", {%g,%g,%g}", v[i].x(), v[i].y(), v[i].z());
}

static void
dumpValue(CVEX_Value *value)
{
    if (!value || !value->isExport())
        return;
    printf("%s = [", value->getName());
    switch (value->getType())
    {
        case CVEX_TYPE_FLOAT:
            dumpFloat((fpreal32 *)value->getData(), value->getArraySize());
            break;
        case CVEX_TYPE_VECTOR3:
            dumpVector((UT_Vector3 *)value->getData(), value->getArraySize());
            break;
        default:
            printf("No output supported currently\n");
    }
    printf("]\n");
}

static void
dumpValueList(const char *label, CVEX_ValueList &list)
{
    int          i;
    CVEX_Value  *value;
    printf("%s:\n", label);
    for (i = 0; i < list.entries(); i++)
    {
        value = list.getValue(i);
        printf("\t%2d.", i+1);
        if (value->isExport())
            printf("export ");
        switch (value->getType())
        {
            case CVEX_TYPE_INTEGER:     printf("int"); break;
            case CVEX_TYPE_FLOAT:       printf("float"); break;
            case CVEX_TYPE_VECTOR3:     printf("vector"); break;
            case CVEX_TYPE_VECTOR4:     printf("vector4"); break;
            case CVEX_TYPE_MATRIX3:     printf("matrix3"); break;
            case CVEX_TYPE_MATRIX4:     printf("matrix"); break;
            case CVEX_TYPE_STRING:      printf("string"); break;
            default:                    printf("unknown"); break;
        }
        printf(" %s[%d]\n", value->getName(), value->getArraySize());
    }
}
}

using namespace HDK_Sample;

int
main(int argc, char *argv[])
{
    CVEX_Context        cvex;

    // Without the following function, CVEX will run in a lean-and-mean mode
    // without some critical functions.  This function needs to be called
    // before any CVEX code is accessed.
    MOT_Director::installFullCVEX();

    // Define storage for the input parameters to the CVEX function.  If the
    // CVEX function accesses these variables by name, we need to make sure
    // they are initialized.  Any parameters which aren't "bound" by inputs,
    // will be handled by the parameters the user specifies.
    UT_Vector3          P[CV_SIZE];
    UT_Vector3          N[CV_SIZE];
    fpreal32            s[CV_SIZE], t[CV_SIZE];
    fpreal32            zero[CV_SIZE];
    int32               seed = 1;
    UT_StringArray      map;

    // When parameters are declared as exports, we can grab the data as
    // computed by VEX.  These buffers are used to store the output of the Cf
    // and Of export parameters.
    UT_Vector3          Cf[CV_SIZE];
    UT_Vector3          Of[CV_SIZE];

    // Before we load the VEX function, we need to declare which variables are
    // defined as input parameters.  We can do "lazy" assignment, or
    // pre-computed assignment.  Lazy assignment just declares the variable
    // without specifying its value.
    //
    // Declare P, N, s, and t without computing their values.
    cvex.addInput("P", CVEX_TYPE_VECTOR3, true);
    cvex.addInput("N", CVEX_TYPE_VECTOR3, true);
    cvex.addInput("s", CVEX_TYPE_FLOAT, true);
    cvex.addInput("t", CVEX_TYPE_FLOAT, true);

    //
    // Declare parameters which have values automatically assigned.  This is
    // more of a convenience for simple parameters.
    map.append("Mandril.pic");
    memset(zero, 0, sizeof(zero));
    // seed is a "uniform" variable -- it has a single value
    // zero is a "varying" variable -- it has a different value for each
    //    element of the array.  Well, not actually, but it could.
    // map is a "uniform" variable since there is only one string in the array
    cvex.addInput("seed", CVEX_TYPE_INTEGER, &seed, 1);
    cvex.addInput("zero", CVEX_TYPE_FLOAT, zero, CV_SIZE);
    cvex.addInput("map", map);

    // Load the VEX function
    if (!cvex.load(argc-1, argv+1))
    {
        fprintf(stderr, "Unable to load cvex function: %s\n", argv[1]);
        return 1;
    }

    // Now that the function is loaded, we can find out all sorts of
    // information about the function.
    dumpValueList("Input Parameters", cvex.getInputList());
    dumpValueList("Output Parameters", cvex.getOutputList());

    // Now, we need to initialize the variables we declared.  But we only have
    // to do this if the variable was specified in the VEX function.
    CVEX_Value  *Pval, *Nval, *sval, *tval;
    Pval = cvex.findInput("P", CVEX_TYPE_VECTOR3);
    Nval = cvex.findInput("N", CVEX_TYPE_VECTOR3);
    sval = cvex.findInput("s", CVEX_TYPE_FLOAT);
    tval = cvex.findInput("t", CVEX_TYPE_FLOAT);

    if (Pval)
    {
        fillP(P);                       // Initialize P
        Pval->setData(P, CV_SIZE);      // Set the parameter value
    }
    if (Nval)
    {
        fillN(N);
        Nval->setData(N, CV_SIZE);
    }
    if (sval || tval)
    {
        fillST(s, t);
        if (sval) sval->setData(s, CV_SIZE);
        if (tval) tval->setData(t, CV_SIZE);
    }

    // We can also find exported parameters.
    CVEX_Value  *CfVal, *OfVal, *sout, *tout;

    CfVal = cvex.findOutput("Cf", CVEX_TYPE_VECTOR3);
    OfVal = cvex.findOutput("Of", CVEX_TYPE_VECTOR3);

    // When an input parameter (like P, N, s or t) is specified as an export
    // parameter, CVEX will _not_ modify the data buffer assigned to the input
    // value.
    sout = cvex.findOutput("s", CVEX_TYPE_FLOAT);
    tout = cvex.findOutput("t", CVEX_TYPE_FLOAT);

    if (!CfVal && !OfVal)
        fprintf(stderr, "%s doesn't seem to write to Cf or Of\n", argv[1]);

    if (CfVal)
        CfVal->setData(Cf, CV_SIZE);
    if (OfVal)
        OfVal->setData(Of, CV_SIZE);

    // To get the output value, you need to grab the output variable and set
    // its data.  You can think of input variables as being "const" for the VEX
    // function.  You can obviously have VEX write to a different buffer, or it
    // can overwrite the input buffer (like below)
    if (sout)
        sout->setData(s, CV_SIZE);
    if (tout)
        tout->setData(t, CV_SIZE);

    // Now, call VEX
    printf("Calling VEX ----------------------------\n\n");
    cvex.run(CV_SIZE, false);
    printf("\n\nFinished VEX ----------------------------\n");

    // And print out the output values
    dumpValue(CfVal);
    dumpValue(OfVal);
    dumpValue(sout);
    dumpValue(tout);

    return 0;
}

Generated on Mon Jan 28 00:26:18 2013 for HDK by  doxygen 1.5.9