#include <UT/UT_DSOVersion.h>
#include <UT/UT_Matrix3.h>
#include <UT/UT_Defines.h>
#include <GEO/GEO_PrimPart.h>
#include <GEO/GEO_Point.h>
#include <GU/GU_Detail.h>
#include <GU/GU_PrimTube.h>
#include <PRM/PRM_Include.h>
#include <PRM/PRM_SpareData.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include "POP_CircleForce.h"
using namespace HDK_Sample;
static PRM_Name names[] =
{
PRM_Name("speed", "Speed"),
PRM_Name("falloff", "Fall Off"),
PRM_Name(0),
};
PRM_Range lengthRange(PRM_RANGE_RESTRICTED, 0.001, PRM_RANGE_UI, 5);
PRM_Template
POP_CircleForce::myTemplateList[] =
{
PRM_Template(PRM_FLT_J, 1, &POPactivateName, PRMoneDefaults, 0,
&PRMunitRange),
PRM_Template(PRM_STRING, 1, &POPsourceName, 0,
&POP_Node::pointGroupMenu),
PRM_Template(PRM_ORD, 1, &POPusecontextgeoName, 0,
&POPusecontextgeoMenu),
PRM_Template(PRM_STRING, PRM_TYPE_DYNAMIC_PATH, 1, &POPfullsopName,
0, 0, 0, 0, &PRM_SpareData::sopPath),
PRM_Template(PRM_TOGGLE, 1, &POPignorexformName),
PRM_Template(PRM_FLT, 1, &names[0], PRMoneDefaults),
PRM_Template(PRM_FLT, 1, &names[1], PRMoneDefaults),
PRM_Template()
};
OP_TemplatePair
POP_CircleForce::myTemplatePair (myTemplateList, &POP_LocalVar::myTemplatePair);
OP_VariablePair
POP_CircleForce::myVariablePair (0, &POP_LocalVar::myVariablePair);
void
newPopOperator (OP_OperatorTable* table)
{
table->addOperator(
new OP_Operator("hdk_circleforce",
"CircleForce",
POP_CircleForce::myConstructor,
&POP_CircleForce::myTemplatePair,
1,
1,
&POP_CircleForce::myVariablePair));
}
unsigned
POP_CircleForce::disableParms (void)
{
unsigned changed = 0;
int usecontextgeo = (USECONTEXTGEO() != 0);
changed += enableParm("soppath", !usecontextgeo);
return changed;
}
OP_Node*
POP_CircleForce::myConstructor (OP_Network* net, const char* name,
OP_Operator* entry)
{
return new POP_CircleForce(net, name, entry);
}
int *POP_CircleForce::myIndirect = 0;
POP_CircleForce::POP_CircleForce (OP_Network* net, const char* name,
OP_Operator* entry)
:POP_LocalVar (net, name, entry)
{
if (!myIndirect)
myIndirect = allocIndirect(sizeof(myTemplateList)/sizeof(PRM_Template));
setTemplate(1);
myGuide = new POP_Guide;
myGuideHandle.allocateAndSet(myGuide);
}
POP_CircleForce::~POP_CircleForce (void)
{
}
OP_ERROR
POP_CircleForce::cookPop (OP_Context &context)
{
fpreal t = context.getTime();
int thread = context.getThread();
POP_ContextData* data = (POP_ContextData*) context.getData();
GEO_PrimParticle* part;
POP_FParam speed;
POP_FParam falloff;
UT_String sourceName;
const GA_PointGroup *sourceGroup = NULL;
GU_Detail gdpcopy;
GU_Detail *source;
UT_Interrupt* boss = UTgetInterrupt();
GEO_PointTree pttree;
UT_PtrArray<UT_PtrArray<GEO_Point *> *> ring;
GEO_AttributeHandle sourcevel_gah;
if (doUpdateViewport(data))
{
data->appendGuide(this, myGuideHandle);
}
if (lockInputs(context) >= UT_ERROR_ABORT)
return(error());
setupDynamicVars(data);
if (buildParticleList(context) >= UT_ERROR_ABORT)
goto done;
if (!checkActivation(data, (POP_FParam) &POP_CircleForce::ACTIVATE))
goto done;
source = getGeo(NULL,
data,
t,
1,
IGNOREXFORM(),
&gdpcopy,
0 ,
0 ,
0 ,
0
);
if (!source)
{
addError(POP_NO_SOP_DETAIL);
goto done;
}
if (doUpdateViewport(data))
{
myGuide->merge(*source, 0 , 0 );
}
SOURCE(sourceName);
if (sourceName.isstring())
{
sourceGroup = parsePointGroups((const char*) sourceName,
data->getDetail());
if (!sourceGroup)
{
addError(POP_BAD_GROUP, sourceName);
goto done;
}
}
setupVars(data, sourceGroup);
POP_FCACHE(speed, SPEED, getSpeed, mySpeed, POP_CircleForce);
POP_FCACHE(falloff, FALLOFF, getFallOff, myFallOff, POP_CircleForce);
if (boss->opInterrupt())
goto done;
if (error() >= UT_ERROR_ABORT)
goto done;
sourcevel_gah = source->getPointAttribute("v");
source->buildRingZeroPoints(ring, 0);
pttree.build(source, 0 );
myCurrIter = 0;
if (sourceGroup)
{
#if defined(HOUDINI_11)
FOR_ALL_GROUP_POINTS(data->getDetail(), sourceGroup, myCurrPt)
{
changePoint(myCurrPt, data, t, source, sourcevel_gah, ring, pttree, speed, falloff);
myCurrIter++;
}
#else
GEO_Point *ppt;
GA_FOR_ALL_GROUP_POINTS(data->getDetail(), sourceGroup, ppt)
{
myCurrPtOff = ppt->getMapOffset();
changePoint(ppt, data, t, source, sourcevel_gah, ring, pttree, speed, falloff);
myCurrIter++;
}
#endif
}
else
{
#if defined(HOUDINI_11)
for (part = myParticleList.iterateInit() ;
part ; part = myParticleList.iterateNext())
{
if (boss->opInterrupt())
goto done;
for (pvtx = part->iterateInit() ; pvtx ; pvtx = pvtx->next)
{
myCurrPt = pvtx->getPt();
changePoint(myCurrPt, data, t, source, sourcevel_gah, ring, pttree, speed, falloff);
myCurrIter++;
}
}
#else
for (part = myParticleList.iterateInit() ;
part ; part = myParticleList.iterateNext())
{
if (boss->opInterrupt())
goto done;
GEO_Point *ppt;
for (POP_ParticleIterator it(part); !it.atEnd(); ++it)
{
ppt = part->getParent()->getGEOPoint(*it);
myCurrPtOff = ppt->getMapOffset();
changePoint(ppt, data, t, source, sourcevel_gah, ring, pttree, speed, falloff);
myCurrIter++;
}
}
#endif
}
done:
for (int i = 0; i < ring.entries(); i++)
{
delete ring[i];
}
cleanupDynamicVars();
unlockInputs();
#if defined(HOUDINI_11)
myCurrPt = NULL;
#else
myCurrPtOff = GA_INVALID_OFFSET;
#endif
return error();
}
void
POP_CircleForce::changePoint (GEO_Point* ppt, POP_ContextData* data, fpreal t,
GU_Detail *source,
GEO_AttributeHandle &sourcevel_gah,
UT_PtrArray<UT_PtrArray<GEO_Point *> *> &ring,
GEO_PointTree &pttree,
POP_FParam speed,
POP_FParam falloff)
{
int state;
float thespeed, thefalloff;
GEO_Point *srcpt;
UT_Vector3 pos, newv;
if (data->isGuideOnly())
return;
state = ppt->getValue<int>(data->getStateOffset());
if ((state & PART_STATE_STOPPED) || (state & PART_STATE_DYING))
return;
pos = ppt->getPos();
srcpt = pttree.findNearestPt(pos);
if (!srcpt)
return;
newv = 0;
if (sourcevel_gah.isAttributeValid())
{
sourcevel_gah.setElement(srcpt);
newv = sourcevel_gah.getV3();
}
UT_PtrArray<GEO_Point *> *r;
r = ring(srcpt->getNum());
if (r && r->entries())
{
float mindist = -1, dist;
float minsign = 1;
UT_Vector3 proj, a, b, minb, minproj;
a = srcpt->getPos();
for (int i = 0; i < r->entries(); i++)
{
b = (*r)(i)->getPos();
proj = pos.projectOnSegment(a, b);
dist = distance2(pos, proj);
if (mindist < 0 || dist < mindist)
{
minb = b;
mindist = dist;
if ((*r)(i)->getNum() < srcpt->getNum())
minsign = -1;
else
minsign = 1;
minproj = proj;
}
}
thespeed = POP_PEVAL(speed);
thefalloff = POP_PEVAL(falloff);
if (dist < thefalloff*thefalloff)
{
float weight;
weight = 1.0 - (mindist / (thefalloff*thefalloff));
weight *= weight;
thespeed *= weight;
UT_Vector3 tangent, toline, orbit;
tangent = a - minb;
tangent.normalize();
tangent *= minsign;
toline = pos - minproj;
toline.normalize();
orbit = cross(tangent, toline);
orbit *= thespeed;
newv += orbit;
}
}
ppt->setValue<UT_Vector3>(data->getVelocityOffset(), newv);
}