#include <UT/UT_DSOVersion.h>
#include <GU/GU_Detail.h>
#include <GU/GU_PrimPoly.h>
#include <PRM/PRM_Include.h>
#include <PRM/PRM_ChoiceList.h>
#include <OP/OP_Operator.h>
#include <OP/OP_OperatorTable.h>
#include <SOP/SOP_Guide.h>
#include "SOP_BrushHairLen.h"
using namespace HDK_Sample;
#define PRM_MENU_CHOICES (PRM_ChoiceListType)(PRM_CHOICELIST_EXCLUSIVE |\
PRM_CHOICELIST_REPLACE)
void
newSopOperator(OP_OperatorTable *table)
{
table->addOperator(new OP_Operator("proto_brushhairlen",
"Brush Hair Length",
SOP_BrushHairLen::myConstructor,
SOP_BrushHairLen::myTemplateList,
1,
1));
}
static PRM_Name sop_names[] = {
PRM_Name("group", "Group"),
PRM_Name("op", "Operation"),
PRM_Name("flen", "FL"),
PRM_Name("blen", "BL"),
PRM_Name("radius", "Radius"),
PRM_Name("uvradius", "UV Radius"),
PRM_Name(0)
};
static PRM_Name sopOpMenuNames[] = {
PRM_Name("paint", "Paint"),
PRM_Name("eyedrop", "Eye Dropper"),
PRM_Name("smoothattrib", "Smooth"),
PRM_Name("callback", "Callback"),
PRM_Name("erase", "Erase Changes"),
PRM_Name(0)
};
static PRM_ChoiceList sopOpMenu(PRM_MENU_CHOICES, sopOpMenuNames);
PRM_Template
SOP_BrushHairLen::myTemplateList[]=
{
PRM_Template(PRM_STRING, 1, &sop_names[0], 0, &SOP_Node::primGroupMenu),
PRM_Template((PRM_Type) PRM_ORD,
PRM_Template::PRM_EXPORT_MAX,
1, &sop_names[1], 0, &sopOpMenu),
PRM_Template(PRM_FLT_J, PRM_Template::PRM_EXPORT_TBX,
1, &sop_names[2], PRMoneDefaults),
PRM_Template(PRM_FLT_J, PRM_Template::PRM_EXPORT_TBX,
1, &sop_names[3], PRMzeroDefaults),
PRM_Template(PRM_FLT_J, PRM_Template::PRM_EXPORT_TBX,
1, &sop_names[4], PRMpointOneDefaults),
PRM_Template(PRM_FLT_J, PRM_Template::PRM_EXPORT_TBX,
1, &sop_names[5], PRMpointOneDefaults),
PRM_Template()
};
OP_Node *
SOP_BrushHairLen::myConstructor(OP_Network *net,const char *name,OP_Operator *entry)
{
return new SOP_BrushHairLen(net, name, entry);
}
SOP_BrushHairLen::SOP_BrushHairLen(OP_Network *net, const char *name, OP_Operator *entry)
: SOP_BrushBase(net, name, entry)
{
myRayOrient = 0.0f;
myRayHit = 0.0f;
myRayHitU = myRayHitV = 0.0f;
myRayHitPressure = 1.0f;
myPrimHit = -1;
myEvent = SOP_BRUSHSTROKE_NOP;
myUseFore = true;
myStrokeChanged = false;
}
SOP_BrushHairLen::~SOP_BrushHairLen()
{
}
unsigned
SOP_BrushHairLen::disableParms()
{
int changed = 0;
return changed;
}
SOP_BrushOp
SOP_BrushHairLen::OP()
{
switch (evalInt("op", 0, 0))
{
case 0: return SOP_BRUSHOP_PAINT;
case 1: return SOP_BRUSHOP_EYEDROP;
case 2: return SOP_BRUSHOP_SMOOTHATTRIB;
case 3: return SOP_BRUSHOP_CALLBACK;
case 4: default: return SOP_BRUSHOP_ERASE;
}
}
void
SOP_BrushHairLen::setBrushOp(SOP_BrushOp op)
{
int iop;
switch (op)
{
case SOP_BRUSHOP_EYEDROP: iop = 1; break;
case SOP_BRUSHOP_SMOOTHATTRIB: iop = 2; break;
case SOP_BRUSHOP_CALLBACK: iop = 3; break;
case SOP_BRUSHOP_ERASE: iop = 4; break;
case SOP_BRUSHOP_PAINT:
default: iop = 0; break;
}
setInt("op", 0, 0, iop);
}
void
SOP_BrushHairLen::doErase()
{
myBrush.eraseAttributes(myPermanentDelta, myCurrentDelta);
if (myBrush.doVisualize())
myBrush.applyVisualizeStencil(gdp);
}
bool
SOP_BrushHairLen::hasStyleChanged(float t)
{
return isParmDirty(1, t) ||
isParmDirty(2, t);
}
const GU_Detail *
SOP_BrushHairLen::getIsectGdp()
{
SOP_Node *sop;
OP_Context context(0.0f);
sop = CAST_SOPNODE(getInput(0));
return sop->getCookedGeo(context);
}
OP_ERROR
SOP_BrushHairLen::cookMySop(OP_Context &context)
{
double t = context.getTime();
GB_AttributeRef aoff;
int i;
GB_Attribute *attrib;
static float zero = 0.0;
if (lockInputs(context) >= UT_ERROR_ABORT) return error();
#define BUILD_HAIR
#ifdef BUILD_HAIR
duplicateSource(0, context);
attrib = gdp->pointAttribs().find("hairlen", GB_ATTRIB_FLOAT);
if (!attrib)
{
gdp->addPointAttrib("hairlen", sizeof(float), GB_ATTRIB_FLOAT, &zero);
attrib = gdp->pointAttribs().find("hairlen", GB_ATTRIB_FLOAT);
}
gdp->addVariableName("hairlen", "HAIRLEN");
myHairlenFound = false;
myTime = t;
processBrushOp(context, true, true);
myStrokeChanged = false;
aoff = gdp->pointAttribs().getOffset("hairlen", GB_ATTRIB_FLOAT);
if (aoff.isInvalid())
{
UT_ASSERT(!"Newly created hairlen disappeared!");
unlockInputs();
return error();
}
int n;
n = gdp->points().entries();
for (i = 0; i < n; i++)
{
GEO_Point *pt, *lpt;
GU_PrimPoly *poly;
pt = gdp->points()(i);
lpt = gdp->appendPoint();
lpt->getPos() = pt->getPos();
lpt->getPos().y() += pt->getValue<float>(aoff);
poly = GU_PrimPoly::build(gdp, 2, GU_POLY_OPEN, 0);
poly->setVertex(0, pt);
poly->setVertex(1, lpt);
}
#else
bool changed_input = false;
bool changed_group = false;
changed_input = checkChangedSource(0, context);
changed_group = isParmDirty(SOP_GDT_GRP_IDX, context.getTime());
if (changed_input)
duplicateChangedSource(0, context, 0, true);
attrib = gdp->pointAttribs().find("hairlen", GB_ATTRIB_FLOAT);
if (!attrib)
{
gdp->addPointAttrib("hairlen", sizeof(float), GB_ATTRIB_FLOAT, &zero);
attrib = gdp->pointAttribs().find("hairlen", GB_ATTRIB_FLOAT);
}
gdp->addVariableName("hairlen", "HAIRLEN");
processBrushOp(context, changed_input, changed_group);
#endif
unlockInputs();
return error();
}
void
SOP_BrushHairLen::brushOpCallback(
GEO_Point *pt,
const UT_PtrArray<const GEO_Point *> * ,
GEO_Vertex * ,
const UT_PtrArray<const GEO_Vertex *> * ,
GEO_Primitive * ,
int ,
float alpha,
GEO_Delta *delta)
{
if (!myHairlenFound)
{
myHairlenFound = true;
myHairlenOffset = gdp->findPointAttrib("hairlen", sizeof(float), GB_ATTRIB_FLOAT);
}
if (myHairlenOffset.isInvalid())
return;
float newhair = (myUseFore ? FGR(myTime) : BGR(myTime));
float oldhair;
if (pt)
{
if (delta) delta->beginPointAttributeChange(*pt);
oldhair = pt->getValue<float>(myHairlenOffset);
pt->setValue<float>(myHairlenOffset, SYSlerp(oldhair, newhair, alpha));
if (delta) delta->endChange();
}
}