- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Examples

# cgfxShaderNode.h

    #ifndef _cgfxShaderNode_h_
    #define _cgfxShaderNode_h_
    //
    // Copyright (C) 2002-2003 NVIDIA
    //
    // File: cgfxShaderNode.h
    //
    // Dependency Graph Node: cgfxShaderNode
    //
    // Author: Jim Atkinson
    //
    // Changes:
    //  10/2003  Kurt Harriman - www.octopusgraphics.com +1-415-893-1023
    //           - Multiple UV sets; user-specified texcoord assignment;
    //             error handling.
    //  12/2003  Kurt Harriman - www.octopusgraphics.com +1-415-893-1023
    //           - attrDefList() no longer calls fAttrDefList->addRef()
    //           - Added members: fTechniqueList, getTechniqueList()
    //           - Deleted members: fCallbackSet, callbackSet(),
    //             setCallback(), technique()
    //           - Deleted class cgfxShaderNode::InternalError.
    //           - Made protected instead of public: setShaderFxFile,
    //             setTechnique, setTexCoordSource
    //
    //-
    // ==========================================================================
    // 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.
    // ==========================================================================
    //+
    #include "cgfxShaderCommon.h"

    #include <maya/MFnNumericAttribute.h>
    #include <maya/MNodeMessage.h>
    #include <maya/MObjectArray.h>
    #include <maya/MCallbackIdArray.h>
    #include <maya/MPxHwShaderNode.h>
    #include <maya/MPxNode.h>
    #include <maya/MStateManager.h>
    #include <maya/MStringArray.h>
    #include <maya/MTypeId.h>

    // Viewport 2.0 includes
    #include <maya/MPxShaderOverride.h>

    #include "cgfxRCPtr.h"
    #include "cgfxEffectDef.h"
    #include "cgfxAttrDef.h"

    #include <set>
    #include <map>

    class cgfxProfile;
    class cgfxPassStateSetter;

    // Largest possible number of texture units (GL_MAX_TEXTURE_UNITS) for any
    // OpenGL implementation, according to the OpenGL 1.2 multitexture spec.
    #define  CGFXSHADERNODE_GL_TEXTURE_MAX  32       // GL_TEXTURE31-GL_TEXTURE0+1
    #define  CGFXSHADERNODE_GL_COLOR_MAX 1

    class cgfxShaderNode : public MPxHwShaderNode
    {
        friend class cgfxAttrDef; // For setTexturesByName().
        friend class cgfxShaderOverride;

    public:

        cgfxShaderNode();
        virtual void        postConstructor();
        virtual             ~cgfxShaderNode();

        // Typically, hardware shaders to not need to compute any outputs.
        //
        virtual MStatus compute( const MPlug& plug, MDataBlock& data );

        // Create the node ...
        //
        static  void*       creator();

        // ... and initialize it.
        //
        static  MStatus     initialize();
        static  void        initializeNodeAttrs();

        // We want to track the changes to the shader attribute because
        // it causes us a large amount of work every time it is modified
        // and we want to do that work as rarely as possible.
        //
        virtual void copyInternalData( MPxNode* pSrc );
        virtual bool getInternalValueInContext( const MPlug&,
                                                  MDataHandle&,
                                                  MDGContext&);
        virtual bool setInternalValueInContext( const MPlug&,
                                                  const MDataHandle&,
                                                  MDGContext&);

        // Tell Maya that Cg effects can be batched
        virtual bool    supportsBatching() const;

        // Tell Maya we require inverted texture coordinates
        virtual bool    invertTexCoords() const;

        // Indicate pass transparency options
        virtual bool    hasTransparency();
        virtual unsigned int    transparencyOptions();

        // Set up the graphics pipeline for drawing with the shader
        //
        virtual MStatus glBind(const MDagPath& shapePath);
        void            bindAttrValues();
        void            bindViewAttrValues(const MDagPath& shapePath);

    #if MAYA_API_VERSION >= 700
        #define _SWATCH_RENDERING_SUPPORTED_ 1
    #endif
    #if defined(_SWATCH_RENDERING_SUPPORTED_)
        // Render a swatch
        virtual MStatus renderSwatchImage( MImage & image );
    #endif

        // Restore the graphics pipeline back to its original state
        //
        virtual MStatus glUnbind(const MDagPath& shapePath);

        // Put the pixels on the screen
        //
        virtual MStatus     glGeometry( const MDagPath& shapePath,
            int prim,
            unsigned int writable,
            int indexCount,
            const unsigned int * indexArray,
            int vertexCount,
            const int * vertexIDs,
            const float * vertexArray,
            int normalCount,
            const float ** normalArrays,
            int colorCount,
            const float ** colorArrays,
            int texCoordCount,
            const float ** texCoordArrays);

        // Return the desired number of texture coordinates per vertex
        //
        virtual int     getTexCoordSetNames( MStringArray& names );

        // Return the desired colours per vertex
        //
    #if MAYA_API_VERSION >= 700
        virtual int     getColorSetNames( MStringArray& names );
    #else
        virtual int     colorsPerVertex();
    #endif

        // Return the desired number of normals per vertex
        //
        virtual int     normalsPerVertex();

        virtual MStatus getAvailableImages( const MString& uvSetName,
                                            MStringArray& imageNames);

        virtual MStatus renderImage( const MString& imageName,
                                    floatRegion region,
                                    const MPxHwShaderNode::RenderParameters& parameters,
                                    int& imageWidth,
                                    int& imageHeight);

        // Data accessor for the attrDefList
        //
        const cgfxRCPtr<cgfxAttrDefList>& attrDefList() const { return fAttrDefList; };

        void setAttrDefList(const cgfxRCPtr<cgfxAttrDefList>& list);

        // Data accessor for the .fx file name (the value of the shader
        // attribute).
        //
        MString shaderFxFile() const { return fShaderFxFile; };
        bool shaderFxFileChanged() const { return fShaderFxFileChanged; }
        void setShaderFxFileChanged(bool val) { fShaderFxFileChanged = val; if (val) ++fGeomReqDataVersionId; }

        // Data accessor for the name of the chosen technique.
        MString         getTechnique() const { return fTechnique; };
        const MStringArray& getTechniqueList() const { return fTechniqueList; }

        // Data accessor for the name of the chosen profile.
        MString         getProfile() const { return fProfileName; };

        // Data accessor the attribute list string (the value of the
        // attributeList attribute).
        //
        void getAttributeList(MStringArray& attrList) const;
        void setAttributeList(const MStringArray& attrList);

        // Set the current per-vertex attributes the shader needs (replacing any existing set)
        void                setVertexAttributes( cgfxRCPtr<cgfxVertexAttribute> attributeList);

        // Set the data set names that will be populating our vertex attributes
        void                setVertexAttributeSource( const MStringArray& sources);

        // Analyse the per-vertex attributes to work out the minimum set of data we require
        void                analyseVertexAttributes();

        // Data accessor for the texCoordSource attribute.
        const MStringArray& getTexCoordSource() const;

        // Data accessor for the colorSource attribute.
        const MStringArray& getColorSource() const;

        // Data accessor for list of empty UV sets.
        const MStringArray& getEmptyUVSets() const;
        const MObjectArray& getEmptyUVSetShapes() const;

        // Data accessor for whether to use nodes for textures
        inline bool getTexturesByName() const { return fTexturesByName; };

        // // Data accessor for the effect itself.
        // //
        const cgfxRCPtr<const cgfxEffect>& effect() { return fEffect; };
        void setEffect(const cgfxRCPtr<const cgfxEffect>& effect);

        MStatus shouldSave ( const MPlug & plug, bool & ret );

        // Get cgfxShader version string.
        static MString  getPluginVersion();

    protected:

        // Try and create a missing effect (e.g. once a GL context is available)
        bool            createEffect();

        // Set internal attributes.
        void            setShaderFxFile( const MString& fxFile )
        {
            if (fxFile != fShaderFxFile)
            {
                // Mark when the shader has changed
                fShaderFxFile = fxFile;
                fShaderFxFileChanged = true;
                ++fGeomReqDataVersionId;
            }
        };
        void            setTechnique( const MString& techn );
        void            setProfile( const MString& profileName );
        void            setProfile( const cgfxProfile* profile );
        void            setDataSources( const MStringArray* texCoordSources, const MStringArray* colorSources );
        void            updateDataSource( MStringArray& sources, MIntArray& typeList, MIntArray& indexList );
        void            setTexturesByName( bool texturesByName, bool updateAttributes = false);
        void            updateTechniqueList();

        // Error reporting
        void            reportInternalError( const char* function, size_t errcode);

    public:

        // The typeid is a unique 32bit indentifier that describes this node.
        // It is used to save and retrieve nodes of this type from the binary
        // file format.  If it is not unique, it will cause file IO problems.
        //
        static  MTypeId sId;

        // There needs to be a MObject handle declared for each attribute that
        // the node will have.  These handles are needed for getting and setting
        // the values later.
        //
        // Input shader attribute
        //
        static  MObject sShader;
        static  MObject sTechnique;
        static  MObject sProfile;

        // Input list of attributes that map to CgFX uniform parameters
        //
        static  MObject sAttributeList;

        // Input list of attributes that map to CgFX varying parameters
        //
        static  MObject sVertexAttributeList;

        // Input list of where to get vertex attributes
        static  MObject sVertexAttributeSource;

        // Input list of where to get texcoords
        static  MObject sTexCoordSource;

        // Input list of where to get colors
        static  MObject sColorSource;

        // Should we use string names or file texture nodes for textures?
        static  MObject sTexturesByName;

        // Cg Context
        static  CGcontext   sCgContext;

        // Cg error callback
        static void         cgErrorCallBack();

        // Cg error handler
        static void         cgErrorHandler(CGcontext cgContext, CGerror cgError, void* userData);

    protected:

        // Description of the effect and it's varying parameters
        cgfxRCPtr<const cgfxEffect> fEffect;

        // The (merged) set of varying parameters the current technique requires
        // and the mapping onto Maya geometry data sets
        cgfxRCPtr<cgfxVertexAttribute>  fVertexAttributes;

        // This is a mapping of names to cgfxAttrDef pointers.  Each cgfxAttrDef
        // defines one dynamic attribute
        cgfxRCPtr<cgfxAttrDefList> fAttrDefList;

        // Values of internal attributes
        MString                 fShaderFxFile;
        bool                    fShaderFxFileChanged;
        MString                 fTechnique;
        const cgfxTechnique*    fCurrentTechnique;
        MString                 fProfileName;
        MStringArray            fAttributeListArray;
        MStringArray            fVertexAttributeListArray;
        MStringArray            fVertexAttributeSource;
        bool                    fTexturesByName;

        // Backward compatibility: these are the old versions of fVertexAttributeSource
        MStringArray    fTexCoordSource;
        MStringArray    fColorSource;

        // The list of maya data we need
        MStringArray    fUVSets;
        MStringArray    fColorSets;
        int             fNormalsPerVertex;

        // These values are derived from the fTexCoordSource value
        // For each texture coord / colour unit, we describe what kind of
        // data should go in there (i.e. should this data be populated with
        // a uv set, a colour set, tangent, normal, etc) AND which set of
        // data to use (i.e. put uv set 0 in texcoord1, and colour set 2 in
        // texcoord 5)
        MIntArray       fTexCoordType;
        MIntArray       fTexCoordIndex;
        MIntArray       fColorType;
        MIntArray       fColorIndex;
        MStringArray    fDataSetNames;

        // Cached info derived from the current cgfxEffect.
        MStringArray    fTechniqueList;

        // Cache of bound data streams. Used only by the non-VP2.0
        // implementation.
        cgfxStructureCache fBoundDataCache;

        // Pass state setter used in the VP2.0 implementation.
        cgfxPassStateSetter* fPassStateSetters;

        // Rendering state (only valid between glBind and glUnbind)
        GLboolean       fDepthEnableState;
        GLint           fDepthFunc;
        GLint           fBlendSourceFactor;
        GLint           fBlendDestFactor;

        // Error handling
        bool            fConstructed;      // true => ok to call MPxNode member functions
        short           fErrorCount;
        short           fErrorLimit;

        // Maya event callbacks
        MCallbackIdArray fCallbackIds;

        // Version Id for data that influences the geometry requirements
        // computed by the cgfxShaderOverride node. It is incremented each
        // time, one of the associated data changes.
        int             fGeomReqDataVersionId;

    public:
        typedef std::set<cgfxShaderNode*> NodeList;
        static void getNodesUsingEffect(const cgfxRCPtr<const cgfxEffect>& effect, NodeList &nodes);

    private:
        // Keep track of all the effect-node association
        typedef std::map<const cgfxEffect*, NodeList> Effect2NodesMap;
        static Effect2NodesMap sEffect2NodesMap;

        static void addAssociation(cgfxShaderNode* node, const cgfxRCPtr<const cgfxEffect>& effect);
        static void removeAssociation(cgfxShaderNode* node, const cgfxRCPtr<const cgfxEffect>& effect);

        // Watch for attribute removals to avoid crashes
        static void attributeAddedOrRemovedCB(MNodeMessage::AttributeMessage msg, MPlug& plug, void* clientData);
    };

    // ===================================================================================
    // viewport 2.0 implementation
    // ===================================================================================

    namespace MHWRender
    {
        class MDrawContext;
    }

    // Override for the cgfxShaderNode
    class cgfxShaderOverride : public MHWRender::MPxShaderOverride
    {
    public:
        static MHWRender::MPxShaderOverride* Creator(const MObject& obj);

        virtual ~cgfxShaderOverride();

        // Initialize phase
        virtual MString initialize(MObject shader);

        // Update phase
        virtual void updateDG(MObject object);
        virtual void updateDevice();
        virtual void endUpdate();

        // Draw phase
        virtual void activateKey(MHWRender::MDrawContext& context);
        virtual bool draw(MHWRender::MDrawContext& context,
                          const MHWRender::MRenderItemList& renderItemList) const;
        virtual void terminateKey(MHWRender::MDrawContext& context);

        // Override properties
        virtual MHWRender::DrawAPI supportedDrawAPIs() const;
        virtual bool isTransparent();
        virtual bool overridesDrawState();

        virtual bool rebuildAlways()
        {
            return !fShaderNode ||
                fShaderNode->fGeomReqDataVersionId != fGeomReqDataVersionId;
        }

    public:
        static const MString drawDbClassification;
        static const MString drawRegistrantId;

    protected:
        cgfxShaderOverride(const MObject& obj);

        // bind uniform attributes
        bool bindAttrValues() const;

        // bind varying attributes
        void bindViewAttrValues(const MHWRender::MDrawContext& context) const;

        cgfxShaderNode *fShaderNode;
        int fGeomReqDataVersionId;
        mutable bool fNeedPassSetterInit;

        const MHWRender::MBlendState* fOldBlendState;
        const MHWRender::MDepthStencilState* fOldDepthStencilState;
        const MHWRender::MRasterizerState* fOldRasterizerState;

        static cgfxShaderNode* sActiveShaderNode;
        static cgfxShaderNode* sLastDrawShaderNode;
    };

    #endif /* _cgfxShaderNode_h_ */