SOP/SOP_BrushHairLen.h

/*
 * Copyright (c) 2013
 *      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>
#include <SOP/SOP_BrushBase.h>

namespace HDK_Sample {
class SOP_BrushHairLen : public SOP_BrushBase
{
public:
             SOP_BrushHairLen(OP_Network *net, const char *, OP_Operator *entry);
    virtual ~SOP_BrushHairLen();

    virtual unsigned     disableParms();

    static OP_Node      *myConstructor(OP_Network  *net, const char *name,
                                       OP_Operator *entry);
    static PRM_Template  myTemplateList[];

    /// This is the callback triggered when a BRUSHOP_CALLBACK is used:
    void                 brushOpCallback(
                            GEO_Point *pt, 
                            const UT_PtrArray<const GEO_Point *> *ptneighbour,
                            GEO_Vertex *vtx,
                            const UT_PtrArray<const GEO_Vertex *> *vtxneighbour,
                            GEO_Primitive *vtx_prim,
                            int prim_vtx_idx,
                            float alpha,
                            GEO_Delta *delta);

protected:
    virtual OP_ERROR     cookMySop   (OP_Context &context);

    /// 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();
    
    /// If the action of the brush will change point positions,
    /// we should set this to 1.  We create geometry, but leave point
    /// positions untouched.
    virtual int         altersGeometry() const
        { return 0; }
    /// We do attribute changes.
    virtual int         altersColor() const
        { return 1; }
    /// This gets the current radius of the brush, unmodulated by the
    /// current pressure amount.
    virtual float       RAWRADIUS(float t)
        { return evalFloat("radius", 0, t); }
    /// This gets the raw radius for the UV space.
    virtual float       RAWUVRADIUS(float t)
        { return evalFloat("uvradius", 0, t); }
    /// This is how much the HITPRESSURE should affect the RADIUS.
    virtual float       RADIUSPRESSURE(float /*t*/)
        { return 1.0f; }
    /// The opacity, hardcoded to 1.0f, for a full replace
    virtual float       RAWOPACITY(float /*t*/)
        { return 1.0f; }
    virtual float       OPACITYPRESSURE(float /*t*/)
        { 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.
    virtual float       DEPTH(float t)
        { return evalFloat("radius", 0, t); }
    virtual float       HEIGHT(float t)
        { return evalFloat("radius", 0, t); }
    /// Whether to use depth clipping at all.
    virtual int         USEDEPTH()
        { return 1; }
    /// Whether to not paint across unconnected seams.  We are using depth
    /// clipping in this tool, so have it off.
    virtual int         USECONNECTIVITY()
        { return 0; }

    /// This needs to map our OP_Menu into SOP_BrushOp.  We leave this
    /// to the C code.
    virtual SOP_BrushOp OP();

    /// Whether accumulate stencil is currently on.  We keep it off.
    virtual int         ACCUMSTENCIL()
        { return 0; }
    /// Projection Type 1 is orient to surface, 0 is to use it flat on.
    /// We hard code it to flat on.
    virtual int         PROJECTIONTYPE()
        { 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.
    virtual int         REALTIME()
        { return 1; }
    /// This returns a SOP_BrushShape.  We hardcode to circle.
    virtual int         SHAPE(float /*t*/)
        { return SOP_BRUSHSHAPE_CIRCLE; }

    /// Protected methods needed by SOP_BrushBase:
protected:
    /// This returns a GU_BrushMergeMode, defined in GU_Brush.h
    /// We just use the standard replace.
    virtual int         MERGEMODE()
        { return GU_BRUSHMERGEMODE_REPLACE; }

    /// Not used:
    virtual void        SCRIPT(UT_String & /*s*/, float /*t*/)
        { }
    
    /// These are used by deformation brush ops:
    virtual int         AXIS()
        { return 0; }
    virtual float       USERX(float /*t*/)
        { return 0.0f; }
    virtual float       USERY(float /*t*/)
        { return 0.0f; }
    virtual float       USERZ(float /*t*/)
        { return 0.0f; }

    /// These query the current raystate.  We read off the cached values...
    virtual float       RAYORIENTX(float /*t*/)
        { return myRayOrient.x(); }
    virtual float       RAYORIENTY(float /*t*/)
        { return myRayOrient.y(); }
    virtual float       RAYORIENTZ(float /*t*/)
        { return myRayOrient.z(); }
    virtual float       RAYHITX(float /*t*/)
        { return myRayHit.x(); }
    virtual float       RAYHITY(float /*t*/)
        { return myRayHit.y(); }
    virtual float       RAYHITZ(float /*t*/)
        { return myRayHit.z(); }
    virtual float       RAYHITU(float /*t*/)
        { return myRayHitU; }
    virtual float       RAYHITV(float /*t*/)
        { return myRayHitV; }
    virtual float       RAYHITPRESSURE(float /*t*/)
        { return myRayHitPressure; }
    virtual int         PRIMHIT(float /*t*/)
        { return myPrimHit; }
    virtual int         PTHIT(float /*t*/)
        { return myPtHit; }
    virtual int         EVENT()
        { 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.
    virtual bool        USE_FOREGROUND()
        { return myUseFore; }
    virtual float       FGR(float t)
        { return evalFloat("flen", 0, t); }
    virtual float       FGG(float /*t*/)
        { return 0.0f; }
    virtual float       FGB(float /*t*/)
        { return 0.0f; }
    virtual float       BGR(float t)
        { return evalFloat("blen", 0, t); }
    virtual float       BGG(float /*t*/)
        { return 0.0f; }
    virtual float       BGB(float /*t*/)
        { 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.
    virtual float       SOFTEDGE(float /*t*/)
        { return 1.0f; }
    /// Which metaball kernel to use as the fall off curve.
    virtual void        KERNEL(UT_String &str, float /*t*/)
        { str = "Elendt"; }
    /// How to determine the upvector, unnecessary with circular brushes.
    virtual int         UPTYPE(float /*t*/)
        { return 0; }
    virtual float       UPX(float /*t*/)
        { return 0.0f; }
    virtual float       UPY(float /*t*/)
        { return 0.0f; }
    virtual float       UPZ(float /*t*/)
        { return 0.0f; }

    /// Alpha noise in the paper space
    virtual float       PAPERNOISE(float /*t*/)
        { return 0.0f; }
    /// Alpha noise in the brush space
    virtual float       SPLATTER(float /*t*/)
        { return 0.0f; }
    /// Name of the bitmap to use if bitmap brush is on, which it isn't.
    virtual void        BITMAP(UT_String & /*str*/, float /*t*/)
        { }
    /// Which channel of the bitmap brush should be used.
    virtual int         BITMAPCHAN(float /*t*/)
        { return 0; }
    /// More hard coded stuff directly from the Nib tab...
    virtual float       ANGLE(float /*t*/)
        { return 0.0f; }
    virtual float       SQUASH(float /*t*/)
        { return 1.0f; }
    virtual int         DOSTAMPING()
        { return 0; }
    virtual int         WRITEALPHA()
        { return 0; }
    /// We explicitly override these parameters as we want the brush
    /// to automatically edit our "hairlen" point attribute.
    virtual int         OVERRIDECD()
        { return 1; }
    virtual void        CDNAME(UT_String &str, float /*t*/)
        { str = "hairlen"; }
    /// As WRITEALPHA is off, this is irrelevant:
    virtual int         OVERRIDEALPHA()
        { return 0; }
    virtual void        ALPHANAME(UT_String & /*str*/, float /*t*/)
        { }
    /// For Comb style brushes, this preserves the normal length.
    virtual int         PRESERVENML()
        { return 0; }
    /// For Comb style brushes this allows overriding the normal attribute.
    virtual int         OVERRIDENML()
        { return 0; }
    virtual void        NMLNAME(UT_String & /*str*/, float /*t*/)
        { }

    /// These methods are used to get the current symmetry operations
    /// that are enabled with the brush.  We don't use any of them here.
    virtual int         DOREFLECTION()
        { return 0; }
    virtual int         DOROTATION()
        { return 0; }
    virtual float       SYMMETRYDIRX(float /*t*/)
        { return 0.0f; }
    virtual float       SYMMETRYDIRY(float /*t*/)
        { return 0.0f; }
    virtual float       SYMMETRYDIRZ(float /*t*/)
        { return 0.0f; }
    virtual float       SYMMETRYORIGX(float /*t*/)
        { return 0.0f; }
    virtual float       SYMMETRYORIGY(float /*t*/)
        { return 0.0f; }
    virtual float       SYMMETRYORIGZ(float /*t*/)
        { return 0.0f; }
    virtual int         SYMMETRYROT(float /*t*/)
        { return 0; }
    virtual float       SYMMETRYDIST(float /*t*/)
        { 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.
    virtual int         ADDATTRIB()
        { return 0; }
    /// This determines if visualization will occur.
    virtual int         VISUALIZE()
        { return 0; }
    virtual int         VISTYPE()
        { return 0; }
    virtual float       VISLOW(float /*t*/)
        { return 0.0f; }
    virtual float       VISHIGH(float /*t*/)
        { return 1.0f; }
    virtual int         VISMODE()
        { return 0; }
    virtual float       ZEROWEIGHTCOLOR_R() 
        { return 1.0f; }
    virtual float       ZEROWEIGHTCOLOR_G() 
        { return 1.0f; }
    virtual float       ZEROWEIGHTCOLOR_B() 
        { return 1.0f; }

    /// This is used by capture brushes to determine if they should
    /// normalize the weights.
    virtual int         NORMALIZEWEIGHT()
        { return 0; }

    /// Should return true if this brush will affect capture regions.
    virtual int         USECAPTURE()
        { return 0; }
    /// Returns the capture region to brush for such brushes.
    virtual int         CAPTUREIDX(float /*t*/)
        { 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.
    virtual bool        hasStrokeChanged(float /*t*/)
        { 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.
    virtual bool        hasStyleChanged(float t);
    /// This determines if the nib file changed.  We don't have a nib file.
    virtual bool        hasNibFileChanged(float /*t*/)
        { return false; }
    /// This returns true if any nib parameters (such as shape, etc) have
    /// changed since the last cook.
    virtual bool        hasNibLookChanged(float /*t*/)
        { return false; }
    /// This returns true if the type of accumulation mode changed.
    virtual bool        hasAccumStencilChanged(float /*t*/)
        { return false; }
    /// This returns true if the capture index has changed.
    virtual bool        hasCaptureIdxChanged(float /*t*/)
        { return false; }
    /// This return strue if the visualization range has changed.
    virtual bool        hasVisrangeChanged(float /*t*/)
        { return false; }

    /// If this returns true, the selection will be cooked as the
    /// group.  We don't want that, so return false.
    virtual bool        wantsCookSelection() const
        { 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.
    virtual void setAccumulateStencil(bool /*yesno*/) {}
    virtual void setRayOrigin(const UT_Vector3 &orig, float /*t*/)
        { myRayHit = orig; myStrokeChanged = true; forceRecook(); }
    virtual void setRayOrientation(const UT_Vector3 &orient, float /*t*/)
        { myRayOrient = orient; myStrokeChanged = true; forceRecook(); }
    virtual void setHitPrimitive(int primidx, float /*t*/)
        { myPrimHit = primidx; myStrokeChanged = true; forceRecook(); }
    virtual void setHitPoint(int ptidx, float /*t*/)
        { myPtHit = ptidx; myStrokeChanged = true; forceRecook(); }
    virtual void setHitUV(float u, float v, float /*t*/)
        { myRayHitU = u; myRayHitV = v; myStrokeChanged = true; forceRecook(); }
    virtual void setHitPressure(float pressure, float /*t*/)
        { myRayHitPressure = pressure; myStrokeChanged = true; forceRecook(); }
    virtual void setBrushEvent(SOP_BrushEvent event)
        { 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.
    virtual void setBrushOp(SOP_BrushOp op);
    /// As we are always returning CIRCLE for SHAPE(), we ignore
    /// requests to change the brush shape.
    virtual void setBrushShape(SOP_BrushShape /*shape*/) {}
    /// As we are locking projection type to not orient to surface,
    /// we can ignore these change requests (see PROJECTIONTYPE)
    virtual void setProjectionType(int /*projtype*/) {}
    virtual void useForegroundColor()
        { myUseFore = true; }
    virtual void useBackgroundColor()
        { myUseFore = false; }
    /// This is used by the eyedropper to write into the current colour
    /// field.
    virtual void setCurrentColor(const UT_Vector3 &cd)
        {
            setFloat(myUseFore ? "flen" : "blen", 0, 0, cd.x());
        }

    /// This is used to update the radii from the state:
    virtual void setRadius(float r, float t)
    {
        setFloat("radius", 0, t, r);
    }
    virtual void setUVRadius(float r, float t)
    {
        setFloat("uvradius", 0, t, r);
    }

protected:
    /// This method handles the erase callback relevant to this type
    /// of brush.
    virtual void        doErase();

private:
    /// Here we cache the current ray hit values...
    UT_Vector3          myRayOrient, myRayHit;
    float               myRayHitU, myRayHitV;
    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;
    GB_AttributeRef     myHairlenOffset;
    double              myTime;
};
} // End HDK_Sample namespace

#endif

Generated on Mon Jan 28 00:26:25 2013 for HDK by  doxygen 1.5.9