SOP/SOP_Surface.C

/*
 * Copyright (c) 2009
 *    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 Surface SOP.  This SOP Surfaces the volume into polygons.
 */

#include <UT/UT_DSOVersion.h>
#include <UT/UT_Math.h>
#include <UT/UT_Matrix3.h>
#include <UT/UT_Matrix4.h>
#include <UT/UT_VoxelArray.h>
#include <GU/GU_Detail.h>
#include <GU/GU_Surfacer.h>
#include <GU/GU_PrimPoly.h>
#include <GU/GU_PrimVolume.h>
#include <PRM/PRM_Include.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <SOP/SOP_Guide.h>
#include "SOP_Surface.h"

using namespace HDK_Sample;

void
newSopOperator(OP_OperatorTable *table)
{
     table->addOperator(new OP_Operator("hdk_surface",
                    "Surface",
                     SOP_Surface::myConstructor,
                     SOP_Surface::myTemplateList,
                     1,
                     1,
                     0));
}

static PRM_Name        names[] = {
    PRM_Name("iso",    "Iso Value"),
};

PRM_Template
SOP_Surface::myTemplateList[] = {
    PRM_Template(PRM_FLT_J,    1, &names[0], PRMzeroDefaults),
    PRM_Template(),
};


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

SOP_Surface::SOP_Surface(OP_Network *net, const char *name, OP_Operator *op)
    : SOP_Node(net, name, op)
{
}

SOP_Surface::~SOP_Surface() {}

unsigned
SOP_Surface::disableParms()
{
    unsigned changed = 0;

    return changed;
}


OP_ERROR
SOP_Surface::cookMySop(OP_Context &context)
{
    double         t;
    float         iso;
    const GU_Detail    *volgdp;
    const GEO_Primitive *prim;
    const GEO_PrimVolume *vol;

    // Before we do anything, we must lock our inputs.  Before returning,
    //    we have to make sure that the inputs get unlocked.
    if (lockInputs(context) >= UT_ERROR_ABORT)
        return error();

    t = context.getTime();
    iso = ISO(t);

    // Erase our gdp but keep it around for reuse
    // This is the same as clearAndDestroy() in terms of the result
    // but keeps a list of all the points and polygons around so
    // if you immediately recreate the same thing it can be done
    // very fast.
    gdp->stashAll();

    // Get first input
    volgdp = inputGeo(0);

    prim = 0;
    vol = 0;
    if (volgdp->primitives().entries() > 0)
    {
        prim = volgdp->primitives()(0);
        if (prim->getPrimitiveId() == GEOPRIMVOLUME)
            vol = (GEO_PrimVolume *) prim;
    }

    if (vol)
    {
        UT_Vector3    pos, size;
        int           rx, ry, rz, x, y, z, d;
        bool          isless, ismore;
        fpreal          density[8];
        UT_VoxelArrayReadHandleF    vox(vol->getVoxelHandle());

        // This is only a rough approximation of the volume size.
        // It does not take into account the rotation of the box.
        UT_BoundingBox          bbox;
        vol->getBBox(&bbox);
        pos = bbox.minvec();
        size = bbox.size();
        vol->getRes(rx, ry, rz);

        GU_Surfacer    surfacer(*gdp, pos, size, rx, ry, rz, false);
        
        for (z = 0; z < rz; z++)
        {
            for (y = 0; y < ry; y++)
            {
                for (x = 0; x < rx; x++)
                {
                    isless = ismore = false;

                    // The surfacer wants the eight corner points
                    // of the cube to surface.
                    for (d = 0; d < 8; d++)
                    {
                        density[d] = vox->getValue(x + ((d&1)?1:0),
                                       y + ((d&2)?1:0),
                                       z + ((d&4)?1:0));
                        density[d] -= iso;
                        if (density[d] < 0.0)
                            isless = true;
                        else
                            ismore = true;
                    }
                    // We don't need to surface voxels that don't have
                    // a crossing point.
                    // If your data structure supports sparse volumes,
                    // this can be used to avoid even reading the values.
                    if (isless && ismore)
                    {
                        surfacer.addCell(x, y, z, density, 0);
                    }
                }
            }
        }
    }

    // free anything not reused
    gdp->destroyStashed();

    unlockInputs();

    return error();
}

const char *
SOP_Surface::inputLabel(unsigned) const
{
    return "Geometry to Surface";
}

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