HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SOP/SOP_BrushHairLen.h
/*
* Copyright (c) 2024
* 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.
*
*----------------------------------------------------------------------------
*/
#ifndef __SOP_BrushHairLen__
#define __SOP_BrushHairLen__
#include <SOP/SOP_Node.h>
namespace HDK_Sample {
class SOP_BrushHairLen : public SOP_BrushBase
{
public:
SOP_BrushHairLen(OP_Network *net, const char *, OP_Operator *entry);
~SOP_BrushHairLen() override;
static OP_Node *myConstructor(OP_Network *net, const char *name,
OP_Operator *entry);
/// This is the callback triggered when a BRUSHOP_CALLBACK is used:
const UT_Array<GA_Offset> *ptneighbour,
GA_Offset vtx,
const UT_Array<GA_Offset> *vtxneighbour,
float alpha,
GEO_Delta *delta,
const GU_Detail *gdp) override;
protected:
OP_ERROR cookMySop(OP_Context &context) override;
/// These are the many & various methods used by BrushBase to
/// determine the current brush status. We can either hook them
/// up to parameters (via evalFloat) or hard code them. In this
/// case we have hard coded most.
/// Public methods needed by MSS:
public:
/// Finds the geometry to do the intersection with.
const GU_Detail *getIsectGdp(fpreal t) override;
/// If the action of the brush will change point positions,
/// we should set this to 1. We create geometry, but leave point
/// positions untouched.
int altersGeometry() const override
{ return 0; }
/// We do attribute changes.
int altersColor() const override
{ return 1; }
/// This gets the current radius of the brush, unmodulated by the
/// current pressure amount.
fpreal RAWRADIUS(fpreal t) override
{ return evalFloat("radius", 0, t); }
/// This gets the raw radius for the UV space.
{ return evalFloat("uvradius", 0, t); }
/// This is how much the HITPRESSURE should affect the RADIUS.
fpreal RADIUSPRESSURE(fpreal /*t*/) override
{ return 1.0f; }
/// The opacity, hardcoded to 1.0f, for a full replace
fpreal RAWOPACITY(fpreal /*t*/) override
{ return 1.0f; }
fpreal OPACITYPRESSURE(fpreal /*t*/) override
{ return 1.0f; }
/// This is how far along the brush axis it will be able to paint.
/// We tie it directly to the raidus here.
fpreal DEPTH(fpreal t) override
{ return evalFloat("radius", 0, t); }
fpreal HEIGHT(fpreal t) override
{ return evalFloat("radius", 0, t); }
/// Whether to use depth clipping at all.
int USEDEPTH() override
{ return 1; }
/// Whether to not paint across unconnected seams. We are using depth
/// clipping in this tool, so have it off.
int USECONNECTIVITY() override
{ return 0; }
/// This needs to map our OP_Menu into SOP_BrushOp. We leave this
/// to the C code.
SOP_BrushOp OP() override;
/// Whether accumulate stencil is currently on. We keep it off.
int ACCUMSTENCIL() override
{ return 0; }
/// Projection Type 1 is orient to surface, 0 is to use it flat on.
/// We hard code it to flat on.
int PROJECTIONTYPE() override
{ return 0; }
/// In realtime mode, all changes are applied immediately to the
/// gdp, rather than being stored in the CurrentDelta during a brush
/// stroke. Some types of brushing require this behaviour implicitly.
int REALTIME() override
{ return 1; }
/// This returns a SOP_BrushShape. We hardcode to circle.
int SHAPE(fpreal /*t*/) override
/// Protected methods needed by SOP_BrushBase:
protected:
/// This returns a GU_BrushMergeMode, defined in GU_Brush.h
/// We just use the standard replace.
int MERGEMODE() override
/// Not used:
void SCRIPT(UT_String & /*s*/, fpreal /*t*/) override
{ }
/// These are used by deformation brush ops:
int AXIS() override
{ return 0; }
fpreal USERX(fpreal /*t*/) override
{ return 0.0f; }
fpreal USERY(fpreal /*t*/) override
{ return 0.0f; }
fpreal USERZ(fpreal /*t*/) override
{ return 0.0f; }
/// These query the current raystate. We read off the cached values...
fpreal RAYORIENTX(fpreal /*t*/) override
{ return myRayOrient.x(); }
fpreal RAYORIENTY(fpreal /*t*/) override
{ return myRayOrient.y(); }
fpreal RAYORIENTZ(fpreal /*t*/) override
{ return myRayOrient.z(); }
fpreal RAYHITX(fpreal /*t*/) override
{ return myRayHit.x(); }
fpreal RAYHITY(fpreal /*t*/) override
{ return myRayHit.y(); }
fpreal RAYHITZ(fpreal /*t*/) override
{ return myRayHit.z(); }
fpreal RAYHITU(fpreal /*t*/) override
{ return myRayHitU; }
fpreal RAYHITV(fpreal /*t*/) override
{ return myRayHitV; }
fpreal RAYHITW(fpreal /*t*/) override
{ return myRayHitW; }
fpreal RAYHITPRESSURE(fpreal /*t*/) override
{ return myRayHitPressure; }
int PRIMHIT(fpreal /*t*/) override
{ return myPrimHit; }
int PTHIT(fpreal /*t*/) override
{ return myPtHit; }
int EVENT() override
{ return myEvent; }
/// These query the current "colours" of the brush...
/// F is for foreground, B, for background. Up to a 3 vector is
/// possible in the order R, G, B.
/// If USE_FOREGROUND is true, the F will be used, otherwise B.
bool USE_FOREGROUND() override
{ return myUseFore; }
fpreal FGR(fpreal t) override
{ return evalFloat("flen", 0, t); }
fpreal FGG(fpreal /*t*/) override
{ return 0.0f; }
fpreal FGB(fpreal /*t*/) override
{ return 0.0f; }
fpreal BGR(fpreal t) override
{ return evalFloat("blen", 0, t); }
fpreal BGG(fpreal /*t*/) override
{ return 0.0f; }
fpreal BGB(fpreal /*t*/) override
{ return 0.0f; }
/// These control the shape of the nib. We have hard coded
/// most of them...
/// What percentage of the radius to devote to the fall off curve.
fpreal SOFTEDGE(fpreal /*t*/) override
{ return 1.0f; }
/// Which metaball kernel to use as the fall off curve.
void KERNEL(UT_String &str, fpreal /*t*/) override
{ str = "Elendt"; }
/// How to determine the upvector, unnecessary with circular brushes.
int UPTYPE(fpreal /*t*/) override
{ return 0; }
fpreal UPX(fpreal /*t*/) override
{ return 0.0f; }
fpreal UPY(fpreal /*t*/) override
{ return 0.0f; }
fpreal UPZ(fpreal /*t*/) override
{ return 0.0f; }
/// Alpha noise in the paper space
fpreal PAPERNOISE(fpreal /*t*/) override
{ return 0.0f; }
/// Alpha noise in the brush space
fpreal SPLATTER(fpreal /*t*/) override
{ return 0.0f; }
/// Name of the bitmap to use if bitmap brush is on, which it isn't.
void BITMAP(UT_String & /*str*/, fpreal /*t*/) override
{ }
/// Which channel of the bitmap brush should be used.
int BITMAPCHAN(fpreal /*t*/) override
{ return 0; }
/// More hard coded stuff directly from the Nib tab...
fpreal ANGLE(fpreal /*t*/) override
{ return 0.0f; }
fpreal SQUASH(fpreal /*t*/) override
{ return 1.0f; }
int DOSTAMPING() override
{ return 0; }
int WRITEALPHA() override
{ return 0; }
/// We explicitly override these parameters as we want the brush
/// to automatically edit our "hairlen" point attribute.
int OVERRIDECD() override
{ return 1; }
void CDNAME(UT_String &str, fpreal /*t*/) override
{ str = "hairlen"; }
/// As WRITEALPHA is off, this is irrelevant:
int OVERRIDEALPHA() override
{ return 0; }
void ALPHANAME(UT_String & /*str*/, fpreal /*t*/) override
{ }
/// For Comb style brushes, this preserves the normal length.
int PRESERVENML() override
{ return 0; }
/// For Comb style brushes this allows overriding the normal attribute.
int OVERRIDENML() override
{ return 0; }
void NMLNAME(UT_String & /*str*/, fpreal /*t*/) override
{ }
/// These methods are used to get the current symmetry operations
/// that are enabled with the brush. We don't use any of them here.
int DOREFLECTION() override
{ return 0; }
int DOROTATION() override
{ return 0; }
fpreal SYMMETRYDIRX(fpreal /*t*/) override
{ return 0.0f; }
fpreal SYMMETRYDIRY(fpreal /*t*/) override
{ return 0.0f; }
fpreal SYMMETRYDIRZ(fpreal /*t*/) override
{ return 0.0f; }
fpreal SYMMETRYORIGX(fpreal /*t*/) override
{ return 0.0f; }
fpreal SYMMETRYORIGY(fpreal /*t*/) override
{ return 0.0f; }
fpreal SYMMETRYORIGZ(fpreal /*t*/) override
{ return 0.0f; }
int SYMMETRYROT(fpreal /*t*/) override
{ return 0; }
fpreal SYMMETRYDIST(fpreal /*t*/) override
{ return 0.0f; }
/// This determines if the Cd or Normal should be auto-added.
/// We have it off as we add it by hand in our cook.
int ADDATTRIB() override
{ return 0; }
/// This determines if visualization will occur.
int VISUALIZE() override
{ return 0; }
int VISTYPE() override
{ return 0; }
fpreal VISLOW(fpreal /*t*/) override
{ return 0.0f; }
fpreal VISHIGH(fpreal /*t*/) override
{ return 1.0f; }
int VISMODE() override
{ return 0; }
{ return 1.0f; }
{ return 1.0f; }
{ return 1.0f; }
/// This is used by capture brushes to determine if they should
/// normalize the weights.
int NORMALIZEWEIGHT() override
{ return 0; }
/// Should return true if this brush will affect capture regions.
int USECAPTURE() override
{ return 0; }
/// Returns the capture region to brush for such brushes.
int CAPTUREIDX(fpreal /*t*/) override
{ return 0; }
/// These determine if the relevant parameters have changed. They are
/// often used to determine when to invalidate internal caches.
/// hasStrokeChanged should return true if any of the setHit* were called,
/// as it will cause a new dab to be applied.
bool hasStrokeChanged(fpreal /*t*/) override
{ return myStrokeChanged; }
/// This should return true if the style of the brush changed, specifically
/// the foreground or background colours. We test this trhough isParmDirty
/// in the C code.
bool hasStyleChanged(fpreal t) override;
/// This determines if the nib file changed. We don't have a nib file.
bool hasNibFileChanged(fpreal /*t*/) override
{ return false; }
/// This returns true if any nib parameters (such as shape, etc) have
/// changed since the last cook.
bool hasNibLookChanged(fpreal /*t*/) override
{ return false; }
/// This returns true if the type of accumulation mode changed.
bool hasAccumStencilChanged(fpreal /*t*/) override
{ return false; }
/// This returns true if the capture index has changed.
bool hasCaptureIdxChanged(fpreal /*t*/) override
{ return false; }
/// This return strue if the visualization range has changed.
bool hasVisrangeChanged(fpreal /*t*/) override
{ return false; }
/// If this returns true, the selection will be cooked as the
/// group. We don't want that, so return false.
bool wantsCookSelection() const override
{ return false; }
/// public methods used by MSS level to write to this level:
/// The usual brush ops (such as Paint, etc) will set parameters
/// with these values. We just cache them locally here.
public:
/// We are locking off accumulate stencil (ACCUMSTENCIL) so can
/// ignore attempts to turn it on.
void setAccumulateStencil(bool /*yesno*/) override {}
void setRayOrigin(const UT_Vector3 &orig, fpreal /*t*/) override
{ myRayHit = orig; myStrokeChanged = true; forceRecook(); }
void setRayOrientation(const UT_Vector3 &orient, fpreal /*t*/) override
{ myRayOrient = orient; myStrokeChanged = true; forceRecook(); }
void setHitPrimitive(int primidx, fpreal /*t*/) override
{ myPrimHit = primidx; myStrokeChanged = true; forceRecook(); }
void setHitPoint(int ptidx, fpreal /*t*/) override
{ myPtHit = ptidx; myStrokeChanged = true; forceRecook(); }
void setHitUVW(fpreal u, fpreal v, fpreal w, fpreal /*t*/) override
{
myRayHitU = u;
myRayHitV = v;
myRayHitW = w;
myStrokeChanged = true;
}
void setHitPressure(fpreal pressure, fpreal /*t*/) override
{ myRayHitPressure = pressure; myStrokeChanged = true; forceRecook(); }
{ myEvent = event; myStrokeChanged = true; forceRecook(); }
/// This one must map from SOP_BrushOp into our own op menu.
/// Thus it is left to the C file.
void setBrushOp(SOP_BrushOp op) override;
/// As we are always returning CIRCLE for SHAPE(), we ignore
/// requests to change the brush shape.
void setBrushShape(SOP_BrushShape /*shape*/) override {}
/// As we are locking projection type to not orient to surface,
/// we can ignore these change requests (see PROJECTIONTYPE)
void setProjectionType(int /*projtype*/) override {}
void useForegroundColor() override
{ myUseFore = true; }
void useBackgroundColor() override
{ myUseFore = false; }
/// This is used by the eyedropper to write into the current colour
/// field.
void setCurrentColor(const UT_Vector3 &cd) override
{
setFloat(myUseFore ? "flen" : "blen", 0, 0, cd.x());
}
/// This is used to update the radii from the state:
void setRadius(fpreal r, fpreal t) override
{
setFloat("radius", 0, t, r);
}
void setUVRadius(fpreal r, fpreal t) override
{
setFloat("uvradius", 0, t, r);
}
protected:
/// This method handles the erase callback relevant to this type
/// of brush.
void doErase() override;
private:
/// Here we cache the current ray hit values...
UT_Vector3 myRayOrient, myRayHit;
float myRayHitU, myRayHitV, myRayHitW;
float myRayHitPressure;
int myPrimHit;
int myPtHit;
int myEvent;
bool myUseFore;
bool myStrokeChanged;
/// These are cached for the brushop callback to know the attribute
/// indices.
bool myHairlenFound;
GA_RWHandleF myHairlenHandle;
fpreal myTime;
};
} // End HDK_Sample namespace
#endif