#ifndef _cgfxEffectDef_h_
#define _cgfxEffectDef_h_
#include "cgfxShaderCommon.h"
#include "cgfxProfile.h"
#include "cgfxRCPtr.h"
class cgfxEffect;
class cgfxAttrDefList;
#include <maya/MDagPath.h>
#include <maya/MObjectHandle.h>
class cgfxVertexAttribute
{
public:
    cgfxVertexAttribute();
    void addRef() const { ++refcount; }
    void release() const;
    
    
    enum SourceType
    {
        kPosition,
        kNormal,
        kUV,
        kTangent,
        kBinormal,
        kColor,
        kBlindData,
        kUnknown
    }               fSourceType;
    int             fSourceIndex;
    
    cgfxRCPtr<cgfxVertexAttribute> fNext;
private:
    mutable int refcount;    
};
struct sourceStreamInfo
{
    cgfxVertexAttribute::SourceType fSourceType;
    unsigned int fOffset;
    unsigned int fStride;
    unsigned int fDimension;
    unsigned int fElementSize;  
    GLuint fDataBufferId;
};
#define MAX_STRUCTURE_ELEMENTS 16
class cgfxVaryingParameterStructure
{
public:
    
    int             fLength;
    
    int             fSize;
    struct cgfxVaryingParameterElement
    {
        cgfxRCPtr<cgfxVertexAttribute> fVertexAttribute;    
        int                 fSize;
    };
    
    cgfxVaryingParameterElement fElements[ MAX_STRUCTURE_ELEMENTS];
};
class cgfxStructureCache
{
public:
    cgfxStructureCache();
    ~cgfxStructureCache();
    
    
    
    char* addEntry(
const MDagPath& shape, 
const MString& name, 
int stride, 
int count);
 
    void flush();
private:
    
    cgfxStructureCache(const cgfxStructureCache&);
    const cgfxStructureCache& operator=(const cgfxStructureCache&);
    
private:
    struct Entry
    {
        ~Entry();
        
        char*           fData;
        Entry*          fNext;
    };
    Entry* fEntries;
};
class cgfxVaryingParameter
{
private:
    
    
    friend class cgfxPass;
    
    static inline void addRecursive(
        CGparameter parameter,
        cgfxVaryingParameter**& nextParameter
    );
    
    cgfxVaryingParameter( CGparameter parameter);
    ~cgfxVaryingParameter();
    
    cgfxVaryingParameter(const cgfxVaryingParameter&);
    const cgfxVaryingParameter& operator=(const cgfxVaryingParameter&);
    void setupAttributes(
        cgfxRCPtr<cgfxVertexAttribute>& vertexAttributes,
        CGprogram program
    );
    
    cgfxRCPtr<cgfxVertexAttribute> setupAttribute(
        CGparameter             parameter,
        cgfxRCPtr<cgfxVertexAttribute>&   vertexAttributes
    );
    
    void            null() const;
public:
    void            bind( 
const MDagPath& shape, cgfxStructureCache* cache,
 
                        int vertexCount, const float * vertexArray,
                        int normalsPerVertex, int normalCount, const float ** normalArrays,
                        int colorCount, const float ** colorArrays,
                        int texCoordCount, const float ** texCoordArrays) const;
    bool            bind( const float* data, int stride) const;
    
    bool bind(const sourceStreamInfo& source) const;
private:
    
    CGparameter                     fParameter;
    
    
    int                             fGLType;
    int                             fGLIndex;           
    
    
    cgfxRCPtr<cgfxVertexAttribute>            fVertexAttribute; 
    
    cgfxVaryingParameterStructure*  fVertexStructure;
    
    
    cgfxVaryingParameter*           fNext;
};
class cgfxPass
{
private:
    
    
    friend class cgfxTechnique;
    cgfxPass(CGpass                  pass,
             const cgfxProfile*      profile);
    ~cgfxPass();
    
    cgfxPass(const cgfxPass&);
    const cgfxPass& operator=(const cgfxPass&);
    void setupAttributes( cgfxRCPtr<cgfxVertexAttribute>& vertexAttributes) const;
    
    
    
    void setProfile(const cgfxProfile* profile) const;
    
public:
    void setCgState() const { cgSetPassState(fPass); }
    void resetCgState() const { cgResetPassState(fPass); }
    void updateCgParameters() const { cgUpdatePassParameters(fPass); }
    CGpass getCgPass() const { return fPass; }
    
    const cgfxPass* getNext() const { return fNext; }
    
    void bind(
        const MDagPath& shape, cgfxStructureCache* cache,
 
        int vertexCount, const float * vertexArray,
        int normalsPerVertex, int normalCount, const float ** normalArrays,
        int colorCount, const float ** colorArrays,
        int texCoordCount, const float ** texCoordArrays) const;
    
    void bind(const sourceStreamInfo dataSources[], const int sourceCount) const;
    
private:
    
    CGpass          fPass;              
    CGprogram       fProgram;           
    cgfxVaryingParameter* fParameters;  
    cgfxProfile     fDefaultProfile;    
    
    cgfxPass*       fNext;              
};
class cgfxTechnique
{
private:
    
    
    friend class cgfxEffect;
    cgfxTechnique( CGtechnique technique, const cgfxProfile* profile);
    ~cgfxTechnique();
    
    cgfxTechnique(const cgfxTechnique&);
    const cgfxTechnique& operator=(const cgfxTechnique&);
    
    
    
    void setProfile(const cgfxProfile* profile) const;
    void validate() const;
    
    const cgfxProfile* getSupportedProfile(const cgfxProfile* profile) const;
    
    static bool hasBlending(CGtechnique technique);
    
public:
    MString getName()
 const { 
return fName; }
 
    bool isValid() const { return fValid; }
    MString getCompilationErrors()
 const { 
return fErrorString; }
 
    bool hasBlending() const { return fHasBlending; }
    const cgfxPass* getFirstPass() const { return fPasses; }
    const cgfxTechnique* getNext() const { return fNext; }
    int getNumPasses() const { return fNumPasses; }
    
    cgfxRCPtr<cgfxVertexAttribute> getVertexAttributes() const;
private:
    CGtechnique             fTechnique;         
    mutable bool            fValid;             
    bool                    fHasBlending;       
    cgfxPass*               fPasses;            
    int                     fNumPasses;         
    cgfxTechnique*          fNext;              
};
class cgfxEffect
{
public:
    static cgfxRCPtr<const cgfxEffect> loadEffect(
const MString& fileName, 
const cgfxProfile* profile);
 
    bool isValid() const { return fEffect != NULL && fTechniques != 0; }
        
    const cgfxTechnique* getFirstTechnique() const { return fTechniques; }
    
    const cgfxTechnique* getTechnique(
MString techniqueName) 
const;
 
    cgfxRCPtr<cgfxAttrDefList> attrsFromEffect() const;
        
    
    
    
    void setProfile(const cgfxProfile* profile) const;
private:
    
    friend class cgfxRCPtr<const cgfxEffect>;
    
    cgfxEffect(
const MString& fileName, 
const cgfxProfile* profile);
    ~cgfxEffect();
    void addRef() const { ++refcount; }
    void release() const;
    
    cgfxEffect(const cgfxEffect&);
    const cgfxEffect& operator=(const cgfxEffect&);
    mutable int                       refcount;    
    
    CGeffect                          fEffect;      
    const cgfxTechnique*              fTechniques;  
    mutable const cgfxProfile*        fProfile;     
};
#undef VALID
#endif