#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 <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include "POP_LocalForce.h"
using namespace HDK_Sample;
static PRM_Name names[] =
{
PRM_Name("origin", "Origin"),
PRM_Name("dir", "Direction"),
PRM_Name("radius", "Radius"),
PRM_Name("length", "Length"),
PRM_Name("strength", "Strength"),
PRM_Name(0),
};
PRM_Range lengthRange(PRM_RANGE_RESTRICTED, 0.001, PRM_RANGE_UI, 5);
static PRM_Default dirDefaults[] =
{
PRM_Default(0), PRM_Default(0), PRM_Default(1)
};
PRM_Template
POP_LocalForce::myTemplateList[] =
{
PRM_Template(PRM_FLT_J, 1, &POPactivateName, PRMoneDefaults, 0,
&PRMunitRange),
PRM_Template(PRM_STRING, 1, &POPsourceName, 0,
&POP_Node::pointGroupMenu),
PRM_Template(PRM_XYZ_J, 3, &names[0]),
PRM_Template(PRM_DIRECTION, 3, &names[1], dirDefaults),
PRM_Template(PRM_FLT_J, 1, &names[2], PRMoneDefaults),
PRM_Template(PRM_FLT_J, 1, &names[3], PRMoneDefaults, 0, &lengthRange),
PRM_Template(PRM_FLT_J, 1, &names[4], PRMoneDefaults),
PRM_Template(PRM_TOGGLE, 1, &POPignoremassName),
PRM_Template(PRM_TOGGLE, 1, &POPoverridemassName),
PRM_Template(PRM_FLT_J, 1, &POPmassName, PRMoneDefaults, 0,
&POPmassRange),
PRM_Template()
};
OP_TemplatePair
POP_LocalForce::myTemplatePair (myTemplateList, &POP_LocalVar::myTemplatePair);
OP_VariablePair
POP_LocalForce::myVariablePair (0, &POP_LocalVar::myVariablePair);
void
newPopOperator (OP_OperatorTable* table)
{
table->addOperator(
new OP_Operator("localforce",
"LocalForce",
POP_LocalForce::myConstructor,
&POP_LocalForce::myTemplatePair,
1,
1,
&POP_LocalForce::myVariablePair));
}
unsigned
POP_LocalForce::disableParms (void)
{
unsigned changed = 0;
int ignoremass = IGNOREMASS();
int overridemass = OVERRIDEMASS();
changed += enableParm("mass", overridemass && !ignoremass);
changed += enableParm("overridemass", !ignoremass);
return changed;
}
OP_Node*
POP_LocalForce::myConstructor (OP_Network* net, const char* name,
OP_Operator* entry)
{
return new POP_LocalForce(net, name, entry);
}
int *POP_LocalForce::myIndirect = 0;
POP_LocalForce::POP_LocalForce (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_LocalForce::~POP_LocalForce (void)
{
}
OP_ERROR
POP_LocalForce::cookPop (OP_Context &context)
{
float t = context.myTime;
int thread = context.getThread();
POP_ContextData* data = (POP_ContextData*) context.getData();
GEO_PrimParticle* part;
GEO_ParticleVertex* pvtx;
UT_Matrix4 xform;
UT_Vector3 origin;
UT_Vector3 dir;
float radius;
float length;
POP_FParam strength;
POP_FParam mass;
int massOffset;
UT_String sourceName;
const GB_PointGroup *sourceGroup = NULL;
GU_PrimTubeParms parms;
GU_CapOptions caps;
UT_Interrupt* boss = UTgetInterrupt();
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;
allowVar(0);
origin.assign(ORIGINX(t), ORIGINY(t), ORIGINZ(t));
dir.assign(DIRX(t), DIRY(t), DIRZ(t));
dir.normalize();
radius = RADIUS(t);
radius = UTabs(radius);
length = LENGTH(t);
allowVar(1);
if (doUpdateViewport(data))
{
parms.taper = 1.0f;
buildQuadricXform(parms.xform, 0, 0, length / 2,
radius, radius, length, 'x');
xform.instance(origin, dir, 1.0,
0, 0, 0, 0, 0);
parms.xform *= xform;
parms.gdp = myGuide;
GU_PrimTube::build(parms, caps, GEOPRIMTUBE);
}
if (!checkActivation(data, (POP_FParam) &POP_LocalForce::ACTIVATE))
goto done;
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(strength, STRENGTH, getStrength, myStrength, POP_LocalForce);
if (OVERRIDEMASS())
{
massOffset = -1;
POP_FCACHE(mass, MASS, getMass, myMass, POP_LocalForce);
}
else
{
massOffset = data->getMassOffset();
if (massOffset < 0)
{
myMass = 1.0f;
mass = (POP_FParam) &POP_LocalForce::getMass;
}
}
if (IGNOREMASS())
{
massOffset = -1;
myMass = 1.0f;
mass = (POP_FParam) &POP_LocalForce::getMass;
}
if (boss->opInterrupt())
goto done;
if (error() >= UT_ERROR_ABORT)
goto done;
myCurrIter = 0;
if (sourceGroup)
{
FOR_ALL_GROUP_POINTS(data->getDetail(), sourceGroup, myCurrPt)
{
changePoint(myCurrPt, data, t, origin, dir, radius, length,
strength, massOffset, mass);
myCurrIter++;
}
}
else
{
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, origin, dir, radius, length,
strength, massOffset, mass);
myCurrIter++;
}
}
}
done:
cleanupDynamicVars();
unlockInputs();
myCurrPt = NULL;
return error();
}
void
POP_LocalForce::changePoint (GEO_Point* ppt, POP_ContextData* data, float t,
const UT_Vector3& origin, const UT_Vector3& dir,
float radius, float length,
POP_FParam strength,
int massOffset, POP_FParam mass)
{
int* state;
UT_Vector3* accel;
UT_Vector3 D;
float s;
float m;
float dist;
state = ppt->castAttribData<int>(data->getStateOffset());
if ((*state & PART_STATE_STOPPED) || (*state & PART_STATE_DYING))
return;
if (massOffset >= 0)
m = *( ppt->castAttribData<float>(massOffset));
else
m = POP_PEVAL(mass);
D = ppt->getPos();
D -= origin;
dist = D.normalize();
t = dot(D, dir);
if (t < 0 || t * dist > length)
return;
D *= dist;
D -= dir * t;
if (D.length() < radius)
{
accel = ppt->castAttribData<UT_Vector3>(data->getAccelOffset());
s = POP_PEVAL(strength);
if (UTequalZero(m))
m = 0.01;
s /= m;
if (!data->isGuideOnly())
{
accel->x() += dir.x() * s;
accel->y() += dir.y() * s;
accel->z() += dir.z() * s;
}
if (doUpdateViewport(data))
addAccelGuide(ppt, dir.x() * s, dir.y() * s, dir.z() * s,
data->myTimeInc);
}
}