HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SIM/SIM_GasAdd.C
/*
* Copyright (c) 2018
* 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.
*
*----------------------------------------------------------------------------
*/
#include "SIM_GasAdd.h"
#include <SIM/SIM_Object.h>
using namespace HDK_Sample;
///
/// This is the hook that Houdini grabs from the dll to link in
/// this. As such, it merely has to implement the data factory
/// for this node.
///
void
{
}
/// Standard constructor, note that BaseClass was crated by the
/// DECLARE_DATAFACTORY and provides an easy way to chain through
/// the class hierarchy.
: BaseClass(factory)
{
}
SIM_GasAdd::~SIM_GasAdd()
{
}
/// Used to automatically populate the node which will represent
/// this data type.
SIM_GasAdd::getDopDescription()
{
static PRM_Name theDstFieldName(GAS_NAME_FIELDDEST, "Dest Field");
static PRM_Name theSrcFieldName(GAS_NAME_FIELDSOURCE, "Source Field");
static PRM_Template theTemplates[] = {
PRM_Template(PRM_STRING, 1, &theDstFieldName),
PRM_Template(PRM_STRING, 1, &theSrcFieldName),
};
static SIM_DopDescription theDopDescription(
true, // Should we make a DOP?
"hdk_gasadd", // Internal name of the DOP.
"Gas Add", // Label of the DOP
"Solver", // Default data name
classname(), // The type of this DOP, usually the class.
theTemplates); // Template list for generating the DOP
return &theDopDescription;
}
bool
SIM_Object *obj,
SIM_Time time,
SIM_Time timestep)
{
SIM_ScalarField *srcscalar, *dstscalar;
SIM_VectorField *srcvector, *dstvector;
SIM_MatrixField *srcmatrix, *dstmatrix;
int i, j, k;
// Now for each pair of source and dst fields, we want to add
// src to dst. We want to support scalar, vector, and matrix fields,
// but only compatible operations. We can determine what type we
// have via casting.
for (i = 0; i < dst.entries(); i++)
{
// Check to see if we exceeded our src list.
if (i >= src.entries())
{
addError(obj, SIM_MESSAGE, "Fewer source fields than destination fields.", UT_ERROR_WARNING);
break;
}
// Try each casting option.
dstscalar = SIM_DATA_CAST(dst(i), SIM_ScalarField);
srcscalar = SIM_DATA_CAST(src(i), SIM_ScalarField);
dstvector = SIM_DATA_CAST(dst(i), SIM_VectorField);
srcvector = SIM_DATA_CAST(src(i), SIM_VectorField);
dstmatrix = SIM_DATA_CAST(dst(i), SIM_MatrixField);
srcmatrix = SIM_DATA_CAST(src(i), SIM_MatrixField);
if (dstscalar && srcscalar)
{
addFields(dstscalar->getField(), srcscalar->getField());
}
if (dstvector && srcvector)
{
for (j = 0; j < 3; j++)
addFields(dstvector->getField(j), srcvector->getField(j));
}
if (dstmatrix && srcmatrix)
{
for (j = 0; j < 3; j++)
for (k = 0; k < 3; k++)
addFields(dstmatrix->getField(j, k), srcmatrix->getField(j, k));
}
// Make sure we are flagged as dirty
if (dstscalar)
dstscalar->pubHandleModification();
if (dstvector)
dstvector->pubHandleModification();
if (dstmatrix)
dstmatrix->pubHandleModification();
}
// Successful cook
return true;
}
void
{
// Initialize our iterator to run over our destination field.
vit.setArray(dst->fieldNC());
// When we complete each tile the tile is tested to see if it can be
// compressed, ie, is now constant. If so, it is compressed.
vit.setCompressOnExit(true);
// Restrict our iterator only over part of the range. Using the
// info parameters means each thread gets its own subregion.
vit.setPartialRange(info.job(), info.numJobs());
// Check if we are aligned. If we are aligned, we have a precise
// 1:1 mapping of our voxels so we don't need to do any lookups
// from world space, which is much faster.
if (dst->isAligned(src))
{
probe.setConstArray(src->field());
for (vit.rewind(); !vit.atEnd(); vit.advance())
{
if (vit.isStartOfTile() && boss->opInterrupt())
break;
// Update our read probe to match our current iterator
// position
probe.setIndex(vit);
// Write out the sum of the two fields.
// Instead of using the iterator, we could also
// have built a UT_VoxelRWProbeF.
vit.setValue( vit.getValue() + probe.getValue() );
}
}
else
{
// We need to lookup the world space position of our voxel so we can
// find it in our destination.
for (vit.rewind(); !vit.atEnd(); vit.advance())
{
if (vit.isStartOfTile() && boss->opInterrupt())
break;
dst->indexToPos(vit.x(), vit.y(), vit.z(), pos);
// Read the source field with trilinear interpolation
// according to our world space position, this allows
// us to thus work with misaligned fields.
vit.setValue( vit.getValue() + src->getValue(pos) );
}
}
}