cgfxAttrDef.h

//
// Copyright (C) 2002-2003 NVIDIA 
// 
// File: cgfxAttrDef.h
//
// Utilities for dealing with CgFX shaders
//
// Author: Jim Atkinson
//
// Changes:
//  12/2003  Kurt Harriman - www.octopusgraphics.com +1-415-893-1023
//           - Added cgfxAttrDef members:  fNumericSoftMin, fNumericSoftMax,
//             fSemantic, fTweaked, fInitOnUndo, typeName(),
//             compoundAttrSuffixes(), attrFromNode(), initializeAttributes(),
//             isInitialValueEqual(), setInitialValue(), purgeMObjectCache(),
//             validateMObjectCache(), getExtraAttrSuffix()
//           - Deleted members: fMustInit, setDefaultValues()
//           - Changed members: fTextureId
//           - Added cgfxAttrDefList member: findInsensitive()
//           - Use MDGModifier instead of MDagModifier
//           - Minimizing unnecessary #includes so other Maya tools can
//             borrow this header without pulling in extra dependencies.
//
//-
// ==========================================================================
// Copyright 1995,2006,2008 Autodesk, Inc. All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk
// license agreement provided at the time of installation or download,
// or which otherwise accompanies this software in either electronic
// or hard copy form.
// ==========================================================================
//+
#ifndef _cgfxAttrDef_h_
#define _cgfxAttrDef_h_

// This class holds the definition of a single attribute
// as it has been extracted from the CGeffect interface.
// All the data has been stored in native Maya format for
// simplicity of use.
//

#include <maya/MObject.h>
#include <maya/MString.h>
#include <maya/MMatrix.h>
#include <maya/MImage.h>
#include <maya/MMessage.h>
#include <maya/MDistance.h>

#include "cgfxRCPtr.h"

#include <Cg/cg.h>
#include <Cg/cgGL.h>

class  cgfxAttrDefList;                // below
class  cgfxEffect;                     // in "cgfxEffectDef.h"
class  cgfxShaderNode;                 // in "cgfxShaderNode.h"
class  cgfxTextureCacheEntry;
class  MDGModifier;                    // in <maya/MDGModifier.h>
class  MFnDependencyNode;              // in <maya/MFnDependencyNode.h>
#define kNullCallback 0

//--------------------------------------------------------------------//
//                            cgfxAttrDef                             //
//--------------------------------------------------------------------//
// Hold the definition of an attribute.

class cgfxAttrDef
{
public:
    enum cgfxAttrType
    {
        // Unknown.
        //
        kAttrTypeUnknown,

        // Boolean value.  Create with MFnNumericAttribute; set default
        // value
        //
        kAttrTypeBool,

        // Integer value.  Create with MFnNumericAttribute; set min,
        // max, default value
        //
        kAttrTypeInt,

        // Float value.  Create with MFnNumericAttribute; set min, max,
        // default value
        //
        kAttrTypeFloat,

        // String value.  Create with MFnTypedAttribute; set default
        // value
        //
        kAttrTypeString,

        // 2, 3, and 4 element vectors. Create with MFnNumericAttribute;
        // children are *X, *Y, *Z, and (maybe) *W; set min, max,
        // default for each child.
        //
        kAttrTypeVector2,
        kAttrTypeVector3,
        kAttrTypeVector4,

        kAttrTypeObjectDir,     // Object coordinates
        kAttrTypeFirstDir = kAttrTypeObjectDir,
        kAttrTypeWorldDir,      // World coordinates
        kAttrTypeViewDir,       // Eye coordinates
        kAttrTypeProjectionDir, // Clip coordinates
        kAttrTypeScreenDir,     // Screen coordinates
        kAttrTypeLastDir = kAttrTypeScreenDir,

        kAttrTypeObjectPos,     // Object coordinates
        kAttrTypeFirstPos = kAttrTypeObjectPos,
        kAttrTypeWorldPos,      // World coordinates
        kAttrTypeViewPos,       // Eye coordinates
        kAttrTypeProjectionPos, // Clip coordinates
        kAttrTypeScreenPos,     // Screen coordinates
        kAttrTypeLastPos = kAttrTypeScreenPos,

        // Color value.  Create with MFnCompoundAttribute; children are
        // *R, *G, *B, and (maybe) *A; set min, max, default for each
        // child.
        //
        kAttrTypeColor3,
        kAttrTypeColor4,

        // Matrix value.  Create with MFnMatrixAttribute; default is
        // identity.
        //
        kAttrTypeMatrix,
        kAttrTypeFirstMatrix = kAttrTypeMatrix,
        kAttrTypeWorldMatrix,
        kAttrTypeViewMatrix,
        kAttrTypeProjectionMatrix,
        kAttrTypeWorldViewMatrix,
        kAttrTypeWorldViewProjectionMatrix,
        kAttrTypeLastMatrix = kAttrTypeWorldViewProjectionMatrix,

        // Texture types.  Create as a color connected to a new file
        // texture node.
        //
        kAttrTypeColor1DTexture,
        kAttrTypeFirstTexture = kAttrTypeColor1DTexture,
        kAttrTypeColor2DTexture,
        kAttrTypeColor3DTexture,
        kAttrTypeColor2DRectTexture,
        kAttrTypeNormalTexture,
        kAttrTypeBumpTexture,
        kAttrTypeCubeTexture,
        kAttrTypeEnvTexture,
        kAttrTypeNormalizationTexture,
        kAttrTypeLastTexture = kAttrTypeNormalizationTexture,

#ifdef _WIN32
        // Time
        kAttrTypeTime,
#endif
        // Other value.  This is for attributes that have odd type or
        // dimensionality.  Create them as multi, multi, multi
        // attributes as needed; default is zero.
        //
        kAttrTypeOther,

        // Last value.
        _kAttrTypeLast
    };

    // Static methods to return useful info about a cgfxAttrType.
    static const char*  typeName( cgfxAttrType eAttrType );
    static const char** compoundAttrSuffixes( cgfxAttrType eAttrType );

    // These are hints as to what might be connected to a direction or
    // position input.
    //
    enum cgfxVectorHint
    {
        kVectorHintNone,
        kVectorHintDirLight,
        kVectorHintPointLight,
        kVectorHintSpotLight,
        kVectorHintEye,

        _kVectorHintLast
    };

    //----------------------------------------------------------------//

    MString         fName;
    cgfxAttrType    fType;
    int             fSize;          // The number of elements, not bytes.
    MObject         fAttr;          // The attribute itself
    cgfxVectorHint  fHint;

    // Vector4 or Color4 types use an extra Maya attribute to hold W or Alpha.
    MObject         fAttr2;         // An extra attribute if necessary.

    double*         fNumericMin;    // we use doubles even for int data.
    double*         fNumericMax;
    double*         fNumericSoftMin;
    double*         fNumericSoftMax;
    double*         fNumericDef;    // Numeric initial value
    MDistance::Unit fUnits;

    MString         fStringDef;     // String initial value

    MString         fDescription;   // Description (if supplied)
    MString         fSemantic;      // Semantic (if supplied)

    CGparameter     fParameterHandle;

    cgfxRCPtr<cgfxTextureCacheEntry> fTexture;
    MCallbackId     fTextureMonitor;
    MString         fTextureUVLink; // A string value for texture UV link.

    bool            fInvertMatrix;  // Matrix elements should be inverted.
    bool            fTransposeMatrix;//Matrix elements should be transposed.

    bool            fTweaked;       // true => user has changed attr value
    bool            fInitOnUndo;    // true => set attr to initial value when
    //   changing back to this effect on undo

private:
    bool            fIsConvertedToInternal;
    // the symbol to mark if the unit is converted to internal one
    const static char fSymbol;

    //----------------------------------------------------------------//

public:
    // Constructor
    cgfxAttrDef(CGparameter cgParameter);
    cgfxAttrDef(
        const MString&          sAttrName,
        const cgfxAttrType      eAttrType,
        const MString&          sDescription,
        const MString&          sSemantic,
        MObject                 obNode,
        MObject                 obAttr
    );

    // Destructor
    ~cgfxAttrDef();

private:
    // Prohibited and not implemented.
    cgfxAttrDef(const cgfxAttrDef&);
    const cgfxAttrDef& operator=(const cgfxAttrDef&);

public:
    // Release any associated resources
    void            release();
    void            releaseTexture();
    void            releaseCallback();

    // Return a string representation of fType.
    MString         typeName() const { return typeName( fType ); }

    static cgfxRCPtr<cgfxAttrDefList> attrsFromNode(MObject& node);
    
    static void     updateNode(
        const cgfxRCPtr<const cgfxEffect>& effect,
        cgfxShaderNode*                     pNode, 
        MDGModifier*                        dgMod,
        cgfxRCPtr<cgfxAttrDefList>&         attrDefList,
        MStringArray&                       attributeList);
    static void buildAttrDefList(MObject& node);
    static void     initializeAttributes(
        MObject&                            node, 
        const cgfxRCPtr<cgfxAttrDefList>&   list,
        bool                                bUndoing,
        MDGModifier*                        dgMod );
    static void     purgeMObjectCache(const cgfxRCPtr<cgfxAttrDefList>& list);
    static void     validateMObjectCache(const MObject&   obCgfxShader, 
                                         const cgfxRCPtr<cgfxAttrDefList>& list);
    
    static cgfxAttrDef* attrFromNode(
        const MFnDependencyNode& fnNode,
        const MString&           sAttrName,
        const cgfxAttrType       eAttrType,
        const MString&           sDescription,
        const MString&           sSemantic);

    // Return suffix for Color4/Vector4 extra attribute, or NULL.
    const char*     getExtraAttrSuffix() const;

    bool            createAttribute(const MObject& oNode, MDGModifier* mod, cgfxShaderNode*   pNode);
    bool            destroyAttribute(MObject& oNode, MDGModifier* mod);

protected:

    // setTextureType
    //
    // Description:
    //
    // Parameters:
    //      param - parameter
    //
    // Returns:
    //      None
    //
    void setTextureType(CGparameter param);

    void setSamplerType(CGparameter param);


    void setMatrixType(CGparameter param);

    // setVectorType
    //
    // Description:
    //  
    // Parameters:
    //      param - parameter
    //
    // Returns:
    //      None
    //
    void 

        setVectorType(CGparameter param);

    // Return true if initial value of 'this' is same as 'that'.
    bool            isInitialValueEqual( const cgfxAttrDef& that ) const; 

    // Copy initial value from given attribute.
    void            setInitialValue( const cgfxAttrDef& from );

    // Set attribute flag
    void setAttributeFlags();

public:
    // These routines all get the value of the attribute referenced by 
    // this cgfxAttrDef object.
    //
    void            getValue( MObject& oNode, bool& value ) const;
    void            getValue( MObject& oNode, int& value ) const;
    void            getValue( MObject& oNode, float& value ) const;
    void            getValue( MObject& oNode, MString& value ) const;
    void            getValue( MObject& oNode, float& v1, float& v2 ) const;
    void            getValue( MObject& oNode,
        float& v1, float& v2, float& v3 ) const;
    void            getValue( MObject& oNode,
        float& v1, float& v2, float& v3, float& v4 ) const;
    void            getValue( MObject& oNode, MMatrix& value ) const;
    void            getValue( MObject& oNode, MImage& value ) const;

    // This routine finds the DG input to this attribute (e.g. texture
    // node connections)
    //
    void            getSource( MObject& oNode, MPlug& src) const;


    // These routines all set the value of the attribute referenced by 
    // this cgfxAttrDef object.
    //
    void            setValue( MObject& oNode, bool value );
    void            setValue( MObject& oNode, int value );
    void            setValue( MObject& oNode, float value );
    void            setValue( MObject& oNode, const MString& value );
    void            setValue( MObject& oNode, float v1, float v2 );
    void            setValue( MObject& oNode, float v1, float v2, float v3 );
    void            setValue( MObject& oNode,
        float v1, float v2, float v3, float v4 );
    void            setValue( MObject& oNode, const MMatrix& v );
    void            setTexture( MObject& oNode, const MString& value, MDGModifier* dgMod);

    void            setUnitsToInternal(CGparameter& cgParameter);
};

#define VALID(ptr) (ptr == 0 || _CrtIsValidHeapPointer(ptr))


//--------------------------------------------------------------------//
//                          cgfxAttrDefList                           //
//--------------------------------------------------------------------//
// Hold a list of cgfxAttrDef* objects that can be searched by name

class cgfxAttrDefList
{
protected:
    class element;
    friend class element;

public:
    class iterator;
    friend class iterator;

protected:
    class element
    {
    public:
        element*        prev;
        element*        next;
        cgfxAttrDef*    data;

        element()
            : prev(0)
            , next(0)
            , data(0)
        { /* nothing */ };

        ~element()
        {
#ifdef _WIN32
            _ASSERTE(VALID(prev));
            _ASSERTE(VALID(next));
            _ASSERTE(VALID(data));
#endif
            if (prev)
            {
                prev->next = next;
            }
            if (next)
            {
                next->prev = prev;
            }
            delete data;
        };
    };

    element* head;
    element* tail;
    int refcount;

public:
    class iterator
    {
        friend class cgfxAttrDefList;

    protected:
        element*        item;

    public:
#ifdef _WIN32
        cgfxAttrDef* operator *() { _ASSERTE(VALID(item)); _ASSERTE(VALID(item->data)); return item->data; };
        iterator& operator ++ () { _ASSERTE(VALID(item)); _ASSERTE(VALID(item->next)); item = item->next; return *this; };
#else
        cgfxAttrDef* operator *() { return item->data; };
        iterator& operator ++  () { item = item->next; return *this; };
#endif

        iterator operator ++ (int)
        {
            iterator tmp = *this;
#ifdef _WIN32
            _ASSERTE(VALID(item));
            _ASSERTE(VALID(item->next)); 
#endif
            item = item->next;
            return tmp;
        };

        operator bool() { return (item != 0); };

        iterator(): item(0) { /* nothing */ };
        iterator(cgfxAttrDefList& list): item(list.head)
        {
#ifdef _WIN32
                _ASSERTE(VALID(item));
#endif
        };
        iterator(const cgfxRCPtr<cgfxAttrDefList>& list)
        {
#ifdef _WIN32
            _ASSERTE(VALID(list.operator->()));
            item = list.isNull() ? 0 : list->head;
            _ASSERTE(VALID(item));
#else
            item = list.isNull() ? 0 : list->head;
#endif
        };
        void reset() { item = 0; };

    protected:
        iterator(element* e): item(e) { /* nothing */ };
    };

    cgfxAttrDefList()
        :   head(0)
        ,   tail(0)
        ,   refcount(0)
    { /* nothing */ };

private:

    friend class cgfxRCPtr<cgfxAttrDefList>;
    
    ~cgfxAttrDefList()
    {
        clear();
    };

    void addRef()
    {
        ++refcount;
    };

    void release();

    // Prohibited and not implemented.
    cgfxAttrDefList(const cgfxAttrDefList&);
    const cgfxAttrDefList& operator=(const cgfxAttrDefList&);

public:

    void releaseTextures();
    
    void clear()
    {
#ifdef _WIN32
        _ASSERTE(VALID(head));
#endif
        if (head)
        {
            element *tmp = new element;
            tmp->next = head;
            head->prev = tmp;

            while (tmp->next)
            {
                delete tmp->next;
            }
            delete tmp;
        }

        head = tail = 0;
    };

    bool empty() { return (head == 0); };

    iterator find(const MString& name)
    {
        iterator it(*this);

        while (it)
        {
            if ((*it)->fName == name)
            {
                break;
            }
            ++it;
        }

        return it;
    };

    iterator        findInsensitive( const MString& name );

    void add(cgfxAttrDef* aDef)
    {
        element * e = new element;
        e->data = aDef;
        if (tail)
        {
            tail->next = e;
            e->prev = tail;
        }
        else
        {
            head = e;
        }
        tail = e;
    }

    iterator begin()
    {
        return iterator(*this);
    };

    void dump(const char* name);
};

#undef VALID
#endif /* _cgfxAttrDef_h_ */