SOP/SOP_TimeCompare.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.
 *
 *----------------------------------------------------------------------------
 * The TimeCompare SOP.  This SOP TimeCompares the geometry onto a plane.
 */

#include <UT/UT_DSOVersion.h>
#include <UT/UT_Math.h>
#include <UT/UT_Matrix3.h>
#include <UT/UT_Matrix4.h>
#include <GEO/GEO_AttributeHandle.h>
#include <GU/GU_Detail.h>
#include <GU/GU_PrimPoly.h>
#include <PRM/PRM_Include.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <OP/OP_Director.h>
#include <SOP/SOP_Error.h>
#include "SOP_TimeCompare.h"

using namespace HDK_Sample;

void
newSopOperator(OP_OperatorTable *table)
{
     table->addOperator(new OP_Operator("hdk_timecompare",
                                        "Time Compare",
                                         SOP_TimeCompare::myConstructor,
                                         SOP_TimeCompare::myTemplateList,
                                         2,     // Must have at least 2 inputs
                                         2,     // Max 2 inputs
                                         0));
}

static PRM_Default      frameDefault(0, "$FF");

static PRM_Name        names[] = {
    PRM_Name("attrib",  "Comparison Point Attribute"),
    PRM_Name("resultattrib",    "Result Attribute"),
    PRM_Name("frame",   "Second Input Frame"),
};

PRM_Template
SOP_TimeCompare::myTemplateList[] = {
    PRM_Template(PRM_STRING,    1, &PRMgroupName, 0, &SOP_Node::pointGroupMenu),
    PRM_Template(PRM_STRING,    1, &names[0]),
    PRM_Template(PRM_STRING,    1, &names[1]),
    PRM_Template(PRM_FLT_J,     1, &names[2], &frameDefault),
    PRM_Template(),
};


OP_Node *
SOP_TimeCompare::myConstructor(OP_Network *net, const char *name, OP_Operator *op)
{
    return new SOP_TimeCompare(net, name, op);
}

SOP_TimeCompare::SOP_TimeCompare(OP_Network *net, const char *name, OP_Operator *op)
        : SOP_Node(net, name, op), myGroup(0)
{
}

SOP_TimeCompare::~SOP_TimeCompare() {}

OP_ERROR
SOP_TimeCompare::cookInputGroups(OP_Context &context, int alone)
{
    // The SOP_Node::cookInputPointGroups() provides a good default
    // implementation for just handling a point selection.
    return cookInputPointGroups(context, myGroup, myDetailGroupPair, alone);
}

OP_ERROR
SOP_TimeCompare::cookMySop(OP_Context &context)
{
    GEO_Point           *ppt;
    fpreal               t = context.getTime();
    fpreal               secondinput_t;
    OP_Context           secondinput_context;
    GEO_AttributeHandle  dst_gah, a_gah, b_gah;
    UT_String            attribname, resultname;
    const GU_Detail     *agdp, *bgdp;

    // Note we only lock our first input here as it is the one
    // we want to evaluate at context.getTime().
    if (lockInput(0, context) >= UT_ERROR_ABORT)
        return error();

    // Now compute our second input's time.
    secondinput_context = context;

    // This is the frame number we want to evaluate
    secondinput_t = FRAME(t);

    // The context takes seconds, not frame, so we convert.
    secondinput_t = OPgetDirector()->getChannelManager()->getTime(secondinput_t);

    // Adjust our cooking context to reflect this
    secondinput_context.setTime(secondinput_t);

    // And lock our second input at this specified time.
    // Note if we fail we still have to unlock our first input before
    // returning!
    if (lockInput(1, secondinput_context) >= UT_ERROR_ABORT)
    {
        unlockInput(0);
        return error();
    }

    // Duplicate our incoming geometry 
    duplicateSource(0, context);

    // Fetch our attribute names
    ATTRIB(attribname, t);
    RESULTATTRIB(resultname, t);

    // We do some simple validation here.  If no attribute names
    // are specified, we treat it as a no-op.
    if (!attribname.isstring() || !resultname.isstring())
    {
        unlockInput(0);
        unlockInput(1);
        return error();
    }

    // Attributes need to follow certain naming conventions for
    // compatibility with other houdini tools.  
    attribname.forceValidVariableName();
    resultname.forceValidVariableName();

    // Find the specified attribute in our source geometry
    agdp = inputGeo(0);
    bgdp = inputGeo(1);
    a_gah = agdp->getPointAttribute(attribname);
    b_gah = bgdp->getPointAttribute(attribname);

    // If source attribute doesn't exist, error.
    if (!a_gah.isAttributeValid() ||
        !b_gah.isAttributeValid())
    {
        addError(SOP_ATTRIBUTE_INVALID, (const char *) attribname);
        unlockInput(0);
        unlockInput(1);
        return error();
    }

    // Create a destination attribute on our own gdp.
    // First see if it already exists.
    dst_gah = gdp->getPointAttribute(resultname);
    if (!dst_gah.isAttributeValid())
    {
        // Clone our source attribute
        // If our source attribute was P we have to do special processing
        // since we have no actual getAttribute() data.
        if (a_gah.isP())
        {
            // Difference of points is vector, thus our choice here.
            gdp->addFloatTuple(GA_ATTRIB_POINT, resultname, 3);
        }
        else
        {
            gdp->getAttributes().cloneAttribute(GA_ATTRIB_POINT,
                            resultname, *a_gah.getAttribute(), true);
        }

        // Fetch newly built attribute
        dst_gah = gdp->getPointAttribute(resultname);
        if (!dst_gah.isAttributeValid())
        {
            addError(SOP_ATTRIBUTE_INVALID, (const char *) resultname);
            unlockInput(0);
            unlockInput(1);
            return error();
        }
    }

    int                 i, alen;

    // Get the length of our vector.  We use the length of the destination
    // attribute as it might have already existed with a shorter
    // length than the source.
    alen = dst_gah.entries();

    // Here we determine which groups we have to work on.  We only
    //  handle point groups.
    if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT)
    {
        GA_FOR_ALL_OPT_GROUP_POINTS(gdp, myGroup, ppt)
        {
            const GEO_Point     *apt, *bpt;

            // Fetch the corresponding point from our inputs.  We know
            // we have a corresponding point in agdp since we duplicated
            // from it, but bgdp might have fewer points.  We just
            // ignore them in this case.
            apt = agdp->points()(ppt->getNum());
            if (ppt->getNum() >= bgdp->points().entries())
                continue;
            bpt = bgdp->points()(ppt->getNum());

            // Bind our attribute handles to our specific points
            a_gah.setElement(apt);
            b_gah.setElement(bpt);
            dst_gah.setElement(ppt);

            for (i = 0; i < alen; i++)
            {
                dst_gah.setF( a_gah.getF(i) - b_gah.getF(i), i );
            }
        }
    }
    unlockInput(0);
    unlockInput(1);
    
    return error();
}

Generated on Thu Jan 31 00:24:22 2013 for HDK by  doxygen 1.5.9