
//**************************************************************************/
// Copyright (c) 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.
//
//**************************************************************************/
// DESCRIPTION:
// CREATED: October 2008
//**************************************************************************/

namespace mudbox {

#ifndef MB_NORMALPRECISION
#define MB_NORMALPRECISION 16
#endif

#ifndef MB_NORMALMAX
#if MB_NORMALPRECISION == 16
//typedef short int tnormal;
//typedef qint64 tnormalv;
#define MB_NORMALMAX 32767
#else
#if MB_NORMALPRECISION == 8
//typedef char tnormal;
//typedef int tnormalv;
#define MB_NORMALMAX 127
#else
#error MB_NORMALPRECISION must be either 8 or 16
#endif
#endif
#endif

/// \brief Represents a vertex point on a Mesh with its associated data.

///
/// A Vertex has an x,y,z position in space, a normal, a "Freeze" value between 
/// 0.0 and 1.0, and a boolean flag saying whether or not the vertex is currently 
/// selected.  Each Mesh object contains a list of Vertex objects.
struct MBDLL_DECL Vertex
{
	inline Vertex( void ) { m_iStrokeID = 0; m_iNormal = 0; };

	// data
	Vector m_vPos;
	mutable unsigned int m_iStrokeID;
	union
	{ 
		tnormal m_vNormal[4];
		int m_iNormalIndex;
		tnormalv m_iNormal;
	};

	/// \brief Returns the Freeze value of the Vertex (between 0.0 and 1.0, 
    /// where 0.0 is not frozen)
	///
	/// The freeze value is used to lock parts of the mesh so they are less 
    /// affected by sculpting brushes. It is the responsibility of every sculpt 
    /// brush to take into account the Freeze values on vertices it is modifying.
	inline float Freeze( void ) const 
        { return ((float)(unsigned char)(m_vNormal[3]&0x7f))/0x7f; };
	
	/// \brief Sets the Freeze value of the Vertex (between 0.0 and 1.0, where 
    /// 0.0 is not frozen)	
	///
	/// The freeze value is used to lock parts of the mesh so they are less 
    /// affected by sculpting brushes. It is the responsibility of every sculpt 
    /// brush to take into account the Freeze values on vertices it is modifying.
	inline void SetFreeze( float fFreeze ) 
        { m_vNormal[3] = (m_vNormal[3]&0xff80)+(unsigned int)(0x7f*fFreeze); };
	
	/// Do not use this method.  Layer masks should be accessed via 
    /// LayerMeshData::VertexMask.	
	inline float Mask( void ) const 
        { return ((float)(unsigned char)(m_vNormal[3]>>8))/0xff; };
	
	/// Do not use this method.  Layer masks should be accessed via 
    /// LayerMeshData::VertexMask.	
	inline void SetMask( float fMask ) 
        { m_vNormal[3] = (m_vNormal[3]&0xff)+(((unsigned int)(0xff*fMask))<<8); };
	
	/// Returns the Selected state of the Vertex (true or false)	
	inline bool IsSelected( void ) const { return (m_vNormal[3]&0x80) != 0; };
	
	/// Sets the Selected state of the Vertex (true or false)	
	inline void SetSelected( bool bSelected ) 
        { m_vNormal[3] = (m_vNormal[3]&0xff7f)+bSelected*0x80; };
};

/// \brief Represents Texture Coordinates (UVs) in the mesh.

///
/// A Mesh object may or may not have Texture Coordinates.  If a mesh does have 
/// TCs, you can access them via Mesh::TriangleVertexTC or Mesh::QuadVertexTC.  
/// Although TCs are associated with particular Vertices, they are not part of 
/// the Vertex object.  This is because a single Vertex may have more different 
/// TCs associated with each face that includes the Vertex.
struct MBDLL_DECL TC
{
	TC( void ) {m_fU = m_fV = 0.0f;};
	TC( float fU, float fV ) { m_fU = fU; m_fV = fV; };
	inline bool operator ==( const TC &a ) const { return m_fU == a.m_fU && m_fV == a.m_fV; };
	inline bool operator !=( const TC &a ) const { return !operator==( a ); };
	inline TC operator +( const TC &a ) const { return TC( m_fU + a.m_fU, m_fV + a.m_fV ); };
	inline TC operator -( const TC &a ) const { return TC( m_fU - a.m_fU, m_fV - a.m_fV ); };
	inline TC operator *( float f ) const { return TC( m_fU * f, m_fV * f ); };
	inline TC operator /( float f ) const { return TC( m_fU / f, m_fV / f ); };
	inline TC &operator +=( const TC &a ) { m_fU += a.m_fU, m_fV += a.m_fV; return *this; };
	inline TC &operator -=( const TC &a ) { m_fU -= a.m_fU, m_fV -= a.m_fV; return *this; };
	inline TC &operator *=( float f ) { m_fU *= f, m_fV *= f; return *this; };
	inline TC &operator /=( float f ) { m_fU /= f, m_fV /= f; return *this; };
	inline operator bool( void ) const throw() { return m_fU || m_fV; };
	inline operator Vector( void ) const throw() { return Vector( m_fU, m_fV, 0 ); };
	union
	{
		float m_fU;
		float u;
	};
	union
	{
		float m_fV;
		float v;
	};
};

/// \brief FaceEnumerator is a base class for operations that must be applied 
/// across mesh faces.
///
/// To use this class, derive a new enumerator from it. Override the Operator() 
/// method to perform the operation you need done to the mesh face.  You must 
/// also override the Tester() method to test faces to see if they should be 
/// included in the operation.
///
/// To use your class, call Mesh::EnumerateFaces, specify a starting face, and 
/// pass in your enumerator class.  Starting with the specified face, your 
/// operation will be applied to adjacent faces.  If your Tester method returns 
/// false for a given face, then that face will not be processed, nor will the 
/// operation be propagated to its neighbors.
class MBDLL_DECL FaceEnumerator
{
public:
	/// Override this method to make it perform your desired operation on a face
	virtual void Operator(
		class Mesh *pMesh,			///< [in] pointer to the mesh being processed
		unsigned int iFaceIndex		///< [in] index of the face to be processed
		);
	
	/// Override this method to check a face to see if it should be included in 
    /// the enumeration. Return \b true if it should;  \b false otherwise
	virtual bool Tester(
		class Mesh *pMesh,			///< [in] pointer to the mesh being processed
		unsigned int iFaceIndex		///< [in] index of the face to be processed
		);
};


/// \briefA base class for operations that must be applied across mesh vertices.

///
/// To use this class, derive a new enumerator from it. Override the Operator() 
/// method to perform the operation you need done to the mesh vertex.  You must 
/// also override the Tester() method to test vertices to see if they should be 
/// included in the operation.
///
/// To use your class, call Mesh::EnumerateVertices, specify a starting face 
/// and vertex, and pass in your enumerator class.  Starting with the specified 
/// vertex, your operation will be applied to adjacent vertices.  If your 
/// Tester method returns false for a given vertex, then that vertex will not be
/// processed, nor will the operation be propagated to its neighbors.

class MBDLL_DECL VertexEnumerator
{
public:
	virtual void Operator(
		class Mesh *pMesh,			///< [in] pointer to the mesh being processed
		unsigned int iVertexIndex,	///< [in] index of the vertex being processed
		unsigned int iFaceIndex		///< [in] index of a face associated with the 
                                    /// vertex being processed (chosen at random)
		);
		
	virtual bool Tester(
		class Mesh *pMesh,			///< [in] pointer to the mesh being processed
		unsigned int iVertexIndex,	///< [in] index of the vertex being processed
		unsigned int iFaceIndex		///< [in] index of a face associated with the 
                                    /// vertex being processed (chosen at random)
		);
};


/// \brief AdjacentVertexEnumerator is a base class for operations that must be 
/// applied to all vertices adjacent to a specified one.
///
/// To use this class, derive a new enumerator from it.  Override the 
/// ProcessAdjacentVertex() method to perform the operation you need done to the 
/// mesh vertex.
///
/// To use your class, call Mesh::EnumerateAdjacentVertices, specify a starting 
/// face and vertex, and pass in your enumerator class.  Your operation will be 
/// applied to all adjacent vertices. 
class MBDLL_DECL AdjacentVertexEnumerator
{
public:
	virtual void ProcessAdjacentVertex(
		unsigned int iVertexIndex, 	///< [in] index of the vertex being processed
		unsigned int iFaceIndex		///< [in] index of a face associated with the 
                                    /// vertex being processed (chosen at random)
		);
		
	bool m_bEdge;  /// This is set to \b true if the original vertex passed in 
                   /// to Mesh::EnumerateAdjacentVertices() is on the edge of the mesh.
};


/// \brief A Mesh is a collection of vertices organized into faces, and optional 
/// Texture Coordinate information.
///
/// Mudbox models are represented by objects of the class Geometry.  Each 
/// Geometry object contains a list of Meshes, one for each subdivision level.  
/// Each mesh is either entirely triangles, or entirely quads.
class MBDLL_DECL Mesh : public Topology
{
	DECLARE_CLASS;

protected:
	/// \brief Constructor.  Do not use directly.
	///
	/// Instead of constructing Meshes directly, you should use CreateInstance()
	/// like this:
	/// \code
	///		Mesh *myNewMesh = CreateInstance<Mesh>();
	/// \endcode
	Mesh(
		FaceType eFaceType = typeQuadric	///< [in] Must be one of Topology::typeQuadric 
                                            /// or Topology::typeTriangular
		);

public:
	/// Returns a pointer to the Geometry object that this mesh belongs to.
	virtual class Geometry *Geometry( void ) const;

	/// Returns a pointer to a MeshRenderer with the desired level-of-detail 
    /// (see MeshRenderer for more information)
	virtual class MeshRenderer *Renderer(
		float fLODLevel = 1.0f	///< [in] the desired level-of-detail
		);

	/// Copy the content of this mesh to another one.
	virtual void CopyTo( Mesh *pDestination ) const;
	
	/// Returns a pointer to the Material associated with this mesh.
	virtual class Material *Material( void ) const;

	/// Returns the number of vertices in the mesh.
	inline unsigned int VertexCount( void ) const { return m_iVertexCount; };
	
	/// Sets the number of vertices in the mesh. Any existing data (that fits) will be kept.
	void SetVertexCount(
		unsigned int iVertexCount	///< [in] the number of vertices that should be in the mesh
		);
	
	/// Returns the number of texture coordinates in the mesh.
	inline unsigned int TCCount( void ) const { return m_pTCs.ItemCount(); };

	/// Sets the number of texture coordinate vertices in the mesh.
	virtual void SetTCCount( 
		unsigned int iTCCount ///< [in] the number of texture coordinate vertices in the mesh
		);

	/// \brief This method returns a pointer to the actual array data.
	///
	/// This is used in cases where very fast access to the array data is required (i.e. not
	/// going through methods)
	inline const Vertex *VertexArray( void ) const { return &m_pVertices[0]; };

	/// Returns a vertex
	inline const Vertex &VertexData(
		unsigned int iVertexIndex	///< [in] index of the vertex to be retrieved
		) const { return m_pVertices[iVertexIndex]; };
	
	/// Returns a vertex
	inline Vertex &VertexData(
		unsigned int iVertexIndex	///< [in] index of the vertex to be retrieved
		) { return m_pVertices[iVertexIndex]; };
		
	/// Returns the x,y,z position of the vertex with the given index.
	inline const Vector &VertexPosition(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].m_vPos; };
	
	/// Returns the x,y,z position of the vertex with the given index.
	inline Vector &VertexPosition(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) { return m_pVertices[iVertexIndex].m_vPos; };
	
	/// \brief Returns the position of the vertex before the current sculpting-brush stroke.
	///
	/// If no stroke is in progress, result is the same as VertexPosition().
	virtual const Vector &VertexOriginalPosition(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].m_vPos; };
	
	/// Returns the specified texture coordinate
	inline const TC &VertexTC(
		unsigned int iVertexTCIndex	///< [in] index of the texture coordinate (not the same as a vertex index)
		) const { return m_pTCs[iVertexTCIndex]; };
	
	/// Returns the normal of the vertex with the given index.
	inline Vector VertexNormal(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return Vector( m_pVertices[iVertexIndex].m_vNormal ); };
		
	/// Internal use only. Do not call this method.
	inline unsigned int VertexStrokeID( unsigned int iVertexIndex ) const 
        { return m_pVertices[iVertexIndex].m_iStrokeID; };
	
	/// \brief Returns the layer mask of the vertex with the given index for the 
    /// current sculpt layer.
	///
	/// Each sculpt layer contains vertex offsets for some subset of vertices in 
    /// the mesh. Each vertex in a mesh has a mask value for each sculpt layer 
    /// associated with it.  This mask determines how much the vertex offset of 
    /// that sculpt layer contributes to the final position of the vertex when 
    /// all the sculpt layers are composited together. This mask is a multiplier, 
    /// so 0.0 means the layer offset is completely masked, and 1.0 means it is 
    /// not masked at all.
	inline float VertexMask(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].Mask(); };
	
	/// \brief Returns the freeze value of the vertex with the given index. 
    /// (0.0 is not frozen;  1.0 is completely frozen)
	///
	/// The freeze value is used to lock parts of the mesh so they are less 
    /// affected by sculpting brushes. It is the responsibility of every sculpt 
    /// brush to take into account the Freeze values on vertices it is
	/// modifying.
	inline float VertexFreeze(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].Freeze(); };
	
	/// Returns the number of vertices having a non-zero freeze value.  
    /// If the result is 0, no part of the mesh is frozen.
	unsigned int FrozenVertexCount( void ) const;
	
	/// Returns the normal of the vertex with the given index as an array of 
    /// 16-bit signed values.
	inline const tnormal *VertexNormalArray(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].m_vNormal; };
	
	/// Returns the normal of the vertex with the given index as a single 
    /// 64-bit signed value.
	inline tnormalv VertexNormalValue(
		unsigned int iVertexIndex	///< [in] index of the vertex
		) const { return m_pVertices[iVertexIndex].m_iNormal; };
	
	// Do not use.  This obsolete method will be removed.
	inline unsigned int VertexNormalIndex( unsigned int iVertexIndex ) const 
        { return m_pVertices[iVertexIndex].m_iNormalIndex; };
	
	/// Returns the bounding box of the mesh in local space.
	virtual AxisAlignedBoundingBox BoundingBox( void ) const;

	/// Sets the position of the vertex with the given index.
	inline void SetVertexPosition(
		unsigned int iVertexIndex,	///< [in] index of the vertex
		const Vector &vPosition		///< [in] the new vertex x,y,z position in local space
		) { m_pVertices[iVertexIndex].m_vPos = vPosition; };
		
	/// Adds vPosition to the current position of the vertex with the given index.
	inline void AddVertexPosition(
		unsigned int iVertexIndex,	///< [in] index of the vertex
		const Vector &vPosition		///< [in] x,y,z offset to be added to the current position in local space
		)
    { m_pVertices[iVertexIndex].m_vPos += vPosition; };
	
	/// Internal use only.  Do not call.
	inline void SetVertexNormal( unsigned int iVertexIndex,	int *pNormal)
	{
		m_pVertices[iVertexIndex].m_vNormal[0] = tnormal(pNormal[3]);
		m_pVertices[iVertexIndex].m_vNormal[1] = tnormal(pNormal[2]);
		m_pVertices[iVertexIndex].m_vNormal[2] = tnormal(pNormal[1]);
	};
	
	/// Sets the normal of the vertex with the given index.
	inline void SetVertexNormal(
		unsigned int iVertexIndex,	///< [in] index of the vertex
		const Vector &vNormal		///< [in] the new vertex normal in local space
		)
        {
        	m_pVertices[iVertexIndex].m_vNormal[0] = tnormal(vNormal.x * MB_NORMALMAX);
        	m_pVertices[iVertexIndex].m_vNormal[1] = tnormal(vNormal.y * MB_NORMALMAX);
        	m_pVertices[iVertexIndex].m_vNormal[2] = tnormal(vNormal.z * MB_NORMALMAX);
        };
		
	// Adds vNormal to the current normal of the vertex with the given index.
	//void AddVertexNormal(
	//	unsigned int iVertexIndex,	///< [in] index of the vertex
	//	const Vector &vNormal		///< [in] x,y,z offset to be added to the normal
	//	);
	
	/// Internal use only.  Do not call.
	inline void SetVertexNormal( unsigned int iVertexIndex, int iNormal )
        { m_pVertices[iVertexIndex].m_iNormalIndex = iNormal; };
	
	/// \brief Sets the freeze value for the vertex with the given index.
	void SetVertexFreeze(
		unsigned int iVertexIndex,	///< [in] index of the vertex
		unsigned int iFaceIndex,	/// WHY DO WE NEED A FACE INDEX HERE?
		float fFreeze				///< [in] New freeze value, ranging from 0.0 
                                    /// (not frozen) to 1.0 (completely frozen)
		);
		
	/// Internal use only. Do not call.
	void SetVertexMask( unsigned int iVertexIndex, float fFMask );
	
	/// Internal use only. Do not call.
	inline void SetVertexStrokeID( unsigned int iVertexIndex, unsigned int iStrokeID ) const 
        { m_pVertices[iVertexIndex].m_iStrokeID = iStrokeID; };

	/// \brief Mark a particular vertex.
	///
	/// This method, along with Mesh::IsVertexMarked() and Mesh::ClearVertexMarks() 
    /// is used to aid in traversing all the vertices in a mesh. An algorithm can 
    /// mark the vertices as it visits them to ensure that it don't visit any 
    /// twice, and then clear all the marks when complete.
	virtual void MarkVertex(
		unsigned int iVertexIndex	///< [in] index of the vertex to mark
		);
		
	/// \brief Returns \b true if a particular vertex is marked.
	///
	/// This method, along with Mesh::MarkVertex() and Mesh::ClearVertexMarks() 
    /// is used to aid in traversing all the vertices in a mesh. An algorithm 
    /// can mark the vertices as it visits them to ensure that it don't visit 
    /// any twice, and then clear all the marks when complete.
	virtual bool IsVertexMarked(
		unsigned int iVertexIndex	///< [in] index of the vertex
		);
	
	/// \brief Clears all vertex marks.
	///
	/// This method, along with Mesh::MarkVertex() and Mesh::IsVertexMarked() is 
    /// used to aid in traversing all the vertices in a mesh. An algorithm can 
    /// mark the vertices as it visits them to ensure that it don't visit any 
    /// twice, and then clear all the marks when complete. This is a very fast 
    /// function.
	virtual void ClearVertexMarks( void );

	/// Returns the position of a corner of a mesh face. 
    /// Can be used for triangular meshes only.
	inline const Vector &TriangleVertexPosition(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexPosition( TriangleIndex( iTriangleIndex, iCornerIndex ) ); };

	/// Returns the position of a corner of a mesh face. Can be used for quadric meshes only.
	inline const Vector &QuadVertexPosition(
		unsigned int iQuadIndex,	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexPosition( QuadIndex( iQuadIndex, iCornerIndex ) ); };
		
	/// Returns the texture coordinates of a corner of a mesh face. 
    /// Can be used for triangular meshes only.
	const TC &TriangleVertexTC(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexTC( TriangleTCI( iTriangleIndex, iCornerIndex ) ); };
		
	/// Returns the texture coordinates of a corner of a mesh face. Can be used for quadric meshes only.
	const TC &QuadVertexTC(
		unsigned int iQuadIndex,	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexTC( QuadTCI( iQuadIndex, iCornerIndex ) ); };

	/// Returns the normal of a corner of a mesh face. Can be used for triangular meshes only.
	inline Vector TriangleVertexNormal(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexNormal( TriangleIndex( iTriangleIndex, iCornerIndex ) ); };

	/// Returns the normal of a corner of a mesh face. Can be used for quad meshes only.
	inline Vector QuadVertexNormal(
		unsigned int iQuadIndex,	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexNormal( QuadIndex( iQuadIndex, iCornerIndex ) ); };

	/// Returns the freeze value of a corner of a mesh face. Can be used for triangular meshes only.
	inline float TriangleVertexFreeze(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexFreeze( TriangleIndex( iTriangleIndex, iCornerIndex ) ); };

	/// Returns the freeze value of a corner of a mesh face. (0.0 is not frozen, 
    /// 1.0 is completely frozen) Can be used for quadric meshes only.
	inline float QuadVertexFreeze(
		unsigned int iQuadIndex, 	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexFreeze( QuadIndex( iQuadIndex, iCornerIndex ) ); };

	/// Returns the normal of a corner of a triangle mesh face as an array of 16-bit signed values.
	inline const tnormal *TriangleVertexNormalArray(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexNormalArray( TriangleIndex( iTriangleIndex, iCornerIndex ) ); };

	/// Returns the normal of a corner of a quad mesh face as an array of 16-bit signed values.
	inline const tnormal *QuadVertexNormalArray(
		unsigned int iQuadIndex, 	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexNormalArray( QuadIndex( iQuadIndex, iCornerIndex ) ); };

	/// Returns the normal a corner of a triangle mesh face as a single 64-bit signed value.
	inline tnormalv TriangleVertexNormalValue(
		unsigned int iTriangleIndex,	///< [in] index of a triangular face
		unsigned int iCornerIndex		///< [in] index of a corner in that face (0, 1, or 2)
		) const { return VertexNormalValue( TriangleIndex( iTriangleIndex, iCornerIndex ) ); };

	/// Returns the normal a corner of a quad mesh face as a single 64-bit signed value.
	inline tnormalv QuadVertexNormalValue(
		unsigned int iQuadIndex, 	///< [in] index of a quad face
		unsigned int iCornerIndex	///< [in] index of a corner of that face (0, 1, 2, or 3)
		) const { return VertexNormalValue( QuadIndex( iQuadIndex, iCornerIndex ) ); };

	/// \brief This method takes an operation that you define (derived from 
    /// FaceEnumerator) and applies it to the specified face, and sequentially 
    /// to its neighbors, then the neighbors of those faces, until the mesh 
    /// has been covered.
	///
	/// In normal use, the entire mesh would not be covered.  The FaceEnumerator's 
    /// \b Tester() function returns false to limit the spread to a particular area.  
    /// For example, this is used by sculpt operations to touch all the faces inside
	/// the brush ring.
	///
	/// See FaceEnumerator for more details.
	virtual void EnumerateFaces(
		unsigned int iFaceIndex,		///< [in] the index of the starting face
		FaceEnumerator *pEnumerator,	///< [in] a pointer to a FaceEnumerator that you define
		bool bSymmetry = false			///< [in] make the enumerator follow the defined symmetry.  
                                        /// This will probably be removed in future; you should set this to \b false.
		);

	/// \brief This method takes an operation that you define (derived from 
    /// FaceEnumerator) and applies it to the specified face, and sequentially 
    /// to its immediate neighbours.
	///
	/// See FaceEnumerator for more details.
	virtual void EnumerateNearestFaces(
		unsigned int iFaceIndex,		///< [in] the index of the starting face
		FaceEnumerator *pOperation		///< [in] a pointer to a FaceEnumerator that you define
		);

	/// \brief This method takes an operation that you define (derived from VertexEnumerator) 
    /// and applies it to all the vertices of the specified face.
	///
	/// See VertexEnumerator for more details.
	virtual void EnumerateVertices(
		unsigned int iFaceIndex,		///< [in] the index of the starting face
		VertexEnumerator *pEnumerator	///< [in] a pointer to a VertexEnumerator that you define
		);

	/// \brief This method takes an operation that you define (derived from 
    /// VertexEnumerator) and applies it to all the vertices adjacent to the 
    /// specified one.  It returns the number of vertices that were visited.
	///
	/// See VertexEnumerator for more details.
	unsigned int EnumerateAdjacentVertices(
		AdjacentVertexEnumerator *pEnumerator,	///< [in] a pointer to a VertexEnumerator that you define
		unsigned int iVertexIndex,				///< [in] the index of the starting vertex
		unsigned int iFaceIndex					///< [in] index of any face adjacent to that vertex
		);

	/// Obsolete method;  do not use.
	virtual int MeshVersion( void ) const;

	/// Obsolete method;  do not use.
	virtual void SmoothTextureCoordinates( float fStrength);

	/// Recalculates all the vertex normals.  This is called after the mesh shape has changed.
	virtual void RecalculateNormals(
		bool bKeep = false	///< Not used
		);

	/// Causes the mesh to build internal adjacency tables, if they don't exist already
	virtual void RecalculateAdjacency( 
		bool bForce = true	///< [in] Force the tables to be re-built, even if they already exist.
		);

	/// Obsolete method;  do not use.
	virtual unsigned int CollectionID( void ) const;

	/// Obsolete method;  do not use.
	virtual void IncreaseCollectionID( void );

	/// Returns true if the whole mesh is selected.
	virtual bool IsSelected( void );

	/// Selects or unselects the whole mesh.
	virtual void SetSelected( bool bOn = true );

	/// Creates and returns a new empty sculpt layer for this mesh, and makes it current.
	virtual class LayerMeshData *AddLayer( void );

	/// Returns a pointer to the current sculpt layer for this mesh.
	virtual class LayerMeshData *ActiveLayer( void ) const;

	/// Returns \b true if this mesh is the currently displayed mesh of the Geometry object it is part of.
	virtual bool IsActiveLevel( void ) const;

	/// \brief Locks the mesh for exclusive modifications.
	///
	/// The caller of this function will get exclusive rights to modify the data stored in the mesh if the return value is true.
	/// In other words, mudbox guarantees that no other code will modify the mesh until it is unlocked. The caller can pass
	/// the address of a MeshUnlocker objects, which will be used to determine if the mesh can be unlocked, and can perform
	/// actions before the unlock happens.
	virtual bool Lock( 
		class MeshUnlocker *pUnlocker = NULL ///< [in] Address of the unlocker object. If this parameter is NULL, the object 
			/// can be unlocked any time
		);

	/// \brief Unlock the mesh.
	///
	/// Returns true if the operation was executed successfully, or if the mesh was unlocked at the time of the call.
	/// If the mesh was locked, and a MeshUnlocker object was specified by the Lock call, that MeshUnlocker object will be used
	/// to determine if the mesh can be unlocked.
	virtual bool Unlock( void );

	/// Returns true if the mesh is locked.
	virtual bool IsLocked( void );

	/// \brief This method must be called by any plugin before it modifies vertex data.
	///
	/// It returns a MeshChange object that will hold the needed undo information.
	class MeshChange *StartChange( void );

	/// Returns if the mesh contains non tri or quad faces
	virtual bool IsNSided( void );

	/// Returns if the mesh has edge bleeded TC layout.
	/// Can be used instead of the normal TC layot if we want to modify texture without artifact at shell borders.
	virtual bool HasExpandedTCs( void ) const;
	/// Calculates the edge bleeded TC layout.
	virtual void CreateExpandedTCs( void );
	/// Returns the Expanded TC value for the given vertex
	virtual TC &ExpandedTC( unsigned int index );

	Store<TC> m_pTCs;

protected:
	Store<Vertex> m_pVertices;
	unsigned int m_iVertexCount;
};

/// \brief TangentGenerator is a class that defines the tangent space used by 
/// Mesh objects.
///
/// "Tangent space" is a coordinate system defined per vertex on a mesh, with 
/// its coordinate basis defined by the normal vector (which points away from 
/// the mesh), and the binormal and tangent vectors which are all orthagonal 
/// to each other.  They can be calculated in different ways.
///
/// TangentGenerator is derived from TreeNode, so that it can be made a child 
/// of the mesh.
///
/// If your graphics pipeline demands its own particular way of defining tangent 
/// space, you can override this class and its methods.  To create your own:
///
/// 1. Write a plug-in that defines your own class derived from TangentGenerator.
///
/// 2. If you need to, override the TreeNode::OnLinked() method.  This will be 
///    called when your TangentGenerator node is linked to a mesh object.  
///    You can initialize any internal data.
///
/// 3. Delete the existing TangentGenerator plugin, and copy yours into the 
///    plug-in folder.
///
/// On OSX, this plugin (TangentGenerator.dylib) is found in the Mudbox 2010 
/// package,  under Contents>MacOS>plugins.  On the PC, it is found in the 
/// \b work dir folder, under "plugins"
class MBDLL_DECL TangentGenerator : public TreeNode
{
	DECLARE_CLASS;
public:
	/// Convert an object space vector to tangent space.
	virtual Vector ConvertToTangent(
		unsigned int iVertexIndex,	///< [in] index of the associated vertex
		const Vector &vVector		///< [in] object space vector to be converted to tangent space
		) const;
	
	/// Convert a tangent space vector to object space.
	virtual Vector ConvertToObject(
		unsigned int iVertexIndex,	///< [in] index of the associated vertex
		const Vector &vVector		///< [in] tangent space vector to be converted to object space
		) const;
		
	/// Returns the Base of the tangent space for a face vertex (a=tangent, b=normal, c=binormal).
	virtual const Base& LocalBase(
		unsigned int iFaceIndex,	///< [in] index of the face
		unsigned int iCornerIndex	///< [in] corner index of the vertex in question (0 to 2 for triangular faces, 0 to 3 for quads)
		);
	
	/// Turns normalization for the tangent and binormal vectors on or off 
	virtual void SetNormalization(
		bool bNormalize		///< [in] If \b true, tangent and binormal vectors will be normalized.
		);
};


/// \brief Describes a location somewhere on the surface of a Mesh. 

///
/// SurfacePoint objects are generally returned by Picker objects, who have 
/// interpreted a user action that involves selecting a point on the mesh.  
/// Meshs are defined as having an inside (back face) and an outside (front face).
struct MBDLL_DECL SurfacePoint
{
	Mesh *m_pMesh;				///< the mesh that has been picked
	unsigned int m_iFaceIndex;	///< the index of the face that has been picked
	float m_fRelativeRange;		///< position of a mesh-line intersection relative to the line.  Ranges from 0.0 (at the beginning of the line) to 1.0 (at the end).
	Vector m_vLocalPosition;	///< position of the point in local space
	Vector m_vLocalNormal;		///< the normal vector of the mesh at the picked point, in local space
	bool m_bSide;				///< if \b true, the backside of the face was selected.  (This is not supported; use at your own risk.)

	/// Void Constructor
	SurfacePoint( void );
	
	/// Constructor
	SurfacePoint(
		Mesh *pMesh,				///< [in] the mesh
		unsigned int iVertexIndex,	///< [in] the index of a vertex on the mesh
		unsigned int iFaceIndex		///< [in] the index of a face on the mesh
		);
		
	/// Returns the position of the SurfacePoint in world space.
	Vector WorldPosition( void ) const;
	
	/// Returns the normal of the selected face in world space.
	Vector WorldNormal( void ) const;

	/// Returns a 2d vector indicating the position of the selected point within its face.
	Vector FaceCoordinates( void ) const;

	/// Returns the normal at the selected point interpolated from the surrounding 
    /// Vertex normals in local space.
	Vector InterpolatedNormal( void ) const;

	/// \brief Set the SurfacePoint values based on a line in local space.
	///
	/// This method looks at the line defined by vStart and vEnd and sees if it 
    /// intersects the specified mesh and face.  If it does, the remainder of 
    /// the SurfacePoint values are filled in.  The line in local space might 
    /// represent the vector defined by the user clicking a point on the screen.
	bool Fill(
		const Mesh *pMesh,			///< [in] the mesh
		unsigned int iFaceIndex,	///< [in] the index of a face
		const Vector &vStart,		///< [in] start point of a line defined in local space
		const Vector &vEnd,			///< [in] end point of a line defined in local space
		bool bTwoSide = false		///< [in] if \b true, allow both sides of the face to be considered
		);

	mutable Vector m_vFaceCoordinates;
};

/// \brief Picker objects are used as part of the map extraction process, to find 
/// points on one mesh that most closely correspond to points on another. This is 
/// used for creating displacement maps, normal maps, color maps, etc.
///
/// If you need to control the algorithm by which points are picked from a vector, 
/// you can override this class in a plug-in, and replace Mudbox's version, which 
/// is in the plugin called "BTreePicker".  To create your own:
///
/// 1. Write a plug-in that defines your own class derived from Picker.
///
/// 2. Delete the existing BTreePicker plugin, and copy yours into the plug-in folder.
///
/// On OSX, this plugin is found in the Mudbox 2010 package, under 
/// Contents>MacOS>plugins.  On the PC, it is found in the 
/// \b work dir folder, under "plugins"
class MBDLL_DECL Picker : public TreeNode
{
	DECLARE_CLASS;

public:
	virtual void SetMesh(
		Mesh *m_pMesh		///< [in] Specify the mesh from which SurfacePoints can be picked
		);
	
	virtual bool Pick(
		const Vector &vLocalStart,	///< [in] Start point of the picking vector, in object space
		const Vector &vLocalEnd,	///< [in] End point of the picking vector, in object space
		bool bBothSides,			///< [in] If \b true, allow the mesh to be picked from either side (front or back of faces)
		SurfacePoint &cResult,		///< [out] The calculated SurfacePoint
		float fTarget = 0.5f		///< [in] This value, ranging from 0 to 1, represents a position on the line between vLocalStart and vLocalEnd.  If there are multiple selection points, the one closes to this value is returned. 
		);
};

/// \brief ScreenSpacePicker objects are used to translate the user action of 
/// clicking in the view into a picked point on the surface of a mesh.
///
/// If you need to control the algorithm by which points are picked, you can 
/// override this class in a plug-in, and replace Mudbox's version, which is 
/// in the plugin called "HWPicker".  To create your own:
///
/// 1. Write a plug-in that defines your own class derived from ScreenSpacePicker.
///
/// 2. Delete the existing HWPicker plugin, and copy yours into the plug-in folder.
///
/// On OSX, this plugin is found in the Mudbox 2010 package,
/// under Contents>MacOS>plugins.  On the PC, it is found in the \b work dir 
/// folder, under "plugins"
class MBDLL_DECL ScreenSpacePicker : public Node
{
	DECLARE_CLASS;

public:
	/// This is called by Mudbox to inform the object of the size of the visible framebuffer
	virtual void SetFramebufferSize(
		unsigned int iWidth,	///< [in] The width of the frame buffer in pixels
		unsigned int iHeight	///< [in] The height of the frame buffer in pixels
		);
	
	/// Translates the x,y coordinates of a user mouse-click to a point on surface in the scene
	virtual bool Pick(
		const class Camera *pCamera,	///< [in] A pointer to the camera that was used to display this view
		float fXPosition,				///< [in] The X position of the point the user clicked (in pixels)
		float fYPosition,				///< [in] The Y position of the point the user clicked (in pixels)
		SurfacePoint &sResult			///< [out] The selected point on the surface
		);
};

/// \brief The MeshGrid class is an interface for dividing the surface of a mesh 
/// to grids. 
///
/// A grid is a collection of quad faces over the surface in a grid pattern with 
/// the size of 1x1, 2x2, 4x4, 8x8 ... This class is responsible to suply a list 
/// of grids on the surface with the following rules:
/// 
/// 1. The grids should be disjoint, one face can only belong to one grid and no more.
/// 2. These grids should cover the whole surface.
/// 
/// This interface is used by Mudbox when it is rendering meshes with high polygon counts 
/// using level of detail. This object is always created as the child of the mesh object, 
/// so the MeshGrid object can obtain a pointer to the mesh by calling TreeNode::Parent().
///
/// If you need to control the algorithm by which these grids are created, you can 
/// override this class in a plug-in, and replace Mudbox's version, which is in the 
/// plugin called "MeshGrid".  To create your own:
///
/// 1. Write a plug-in that defines your own class derived from MeshGrid.
///
/// 2. Delete the existing MeshGrid plugin, and copy yours into the plug-in folder.
///
/// On OSX, this plugin is found in the Mudbox 2009 package,
/// under Contents>MacOS>plugins.  On the PC, it is found in the \b work dir folder, 
/// under "plugins"
class MBDLL_DECL MeshGrid : public TreeNode
{
	DECLARE_CLASS;

public:
	/// This function should return the number of grids.
	virtual unsigned int MeshGridCount( void ) const;
	
	/// This function returns the level of the specified grid. When the level 
    /// of a grid is N then it's size is 2^N x 2^N
	virtual unsigned int MeshGridLevel( 
		unsigned int iMeshGridIndex ///< [in] The index of the grid
		) const;
	
	/// This function returns the index of faces which are forming a 
    /// specific grid.
	virtual unsigned int MeshGridFaceIndex( 
		unsigned int iMeshGridIndex, ///< [in] The index of the grid
		unsigned int iX,			///< [in] Horizontal position of the face within the grid
		unsigned int iY			///< [in] Vertical position of the face within the grid
		) const;
	
	/// Returns the index of vertices for a grid.
	virtual unsigned int MeshGridVertexIndex( 
		unsigned int iMeshGridIndex, ///< [in] The index of the grid
		unsigned int iX,			///< [in] Horizontal position of the vertex inside the grid
		unsigned int iY			///< [in] Vertical position of the vertex inside the grid
		) const;
	
	/// Returns the texture coordinate index of the vertices in the grid.
	virtual unsigned int MeshGridTCIndex( 
		unsigned int iMeshGridIndex, ///< [in] The index of the grig
		unsigned int iX,			///< [in] Horizontal position of the vertex inside the grid
		unsigned int iY			///< [in] Vertical position of the vertex inside the grid
		) const;
	
	/// This function returns the grid index which contains the specified face.
	virtual unsigned int MeshGridIndexByFaceIndex( 
		unsigned int iFaceIndex		///< [in] Index of the face
		) const;
};

/// \brief This is an interface for a SurfaceSmoother object, which is responsible 
/// to provide information about the limit surface of a mesh.
///
/// Mudbox uses this object to obtain information about the limit surface without 
/// actually calculating additional subdivision levels for the meshes. This limit 
/// surface is used during map extraction. If you need to control the algorithm by 
/// which this limit surface is calculated, you can override this class in a 
/// plug-in, and replace Mudbox's version, which is in the plugin called 
/// "CCSurfaceSmoother".  To create your own:
///
/// 1. Write a plug-in that defines your own class derived from SurfaceSmoother.
///
/// 2. Delete the existing CCSurfaceSmoother plugin, and copy yours into the 
///    plug-in folder.
///
/// On OSX, this plugin is found in the Mudbox 2009 package,
/// under Contents>MacOS>plugins.  On the PC, it is found in the 
/// \b work dir folder, under "plugins"
class MBDLL_DECL SurfaceSmoother : public TreeNode
{
	DECLARE_CLASS;

public:
	/// This function must return the position of a point on the surface.
	virtual Vector SmoothPosition( 
		unsigned int iFaceIndex, ///< [in] Index of the face which contains the surface point
		double fUCoordinate, ///< [in] Location in U direction of the point inside the face (must be within 0-1)
		double fVCoordinate ///< [in] Location in V direction of the point inside the face (must be within 0-1)
		) const;
	
	/// This function must return the surface nomal of a point on the surface.
	virtual Vector SmoothNormal( 
		unsigned int iFaceIndex, ///< [in] Index of the face which contains the surface point
		double fUCoordinate, ///< [in] Location in U direction of the point inside the face (must be within 0-1)
		double fVCoordinate ///< [in] Location in V direction of the point inside the face (must be within 0-1)
		) const;
	
	/// This function must return the smoothed texture coordinate on the surface.
	virtual Vector SmoothTextureCoordinate( 
		unsigned int iFaceIndex, ///< [in] Index of the face which contains the surface point
		double fUCoordinate, ///< [in] Location in U direction of the point inside the face (must be within 0-1)
		double fVCoordinate ///< [in] Location in V direction of the point inside the face (must be within 0-1)
		) const;
};

/// \brief This class represents a change to a mesh, and is used when an operation 
/// which modifies mesh vertices should be undoable.
///
/// When you want to change the position of vertices in a mesh, and you want this 
/// change to be undoable, you should first call the function Mesh::StartChange 
/// to create a MeshChange object.
class MBDLL_DECL MeshChange : public Node
{
	MeshChange( Mesh *m_pMesh );

public:
	/// \brief This struct holds the change information about a single vertex.
	struct VertexChange
	{
		/// The position of the vertex before the change.
		Vector m_vPosition;
		/// This variable is used internally.
		unsigned int m_iID;
		/// Surface normal of the vertex.
		union
		{
			tnormalv m_iNormal;
			tnormal m_vNormal[4];
		};
		/// This variable can be used freely to store a float value for the vertex.
		float m_fData;
		/// Index of the vertex.
		unsigned int m_iVertexIndex;
		/// Index of a face which uses the vertex.
		unsigned int m_iFaceIndex;
		/// Index of the vertex within the current sculpt layer.
		unsigned int m_iLayerVertexIndex;
	};
	
	/// This function returns the position of a vertex before this change.
	inline const Vector &OriginalPosition( 
		unsigned int iVertexIndex ///< [in] Index of the vertex
		) const
	{
		Vertex &v = m_pMesh->VertexData( iVertexIndex );
		if ( v.m_iStrokeID < m_iVertexCount && m_pArray[v.m_iStrokeID].m_iVertexIndex == iVertexIndex )
			return m_pArray[v.m_iStrokeID].m_vPosition;
		else
			return v.m_vPos;
	};
	
	/// This function returns the surface normal before the change for a specified vertex.
	inline Vector OriginalNormal( 
		unsigned int iVertexIndex ///< [in] Index of the vertex
		) const
	{
		Vertex &v = m_pMesh->VertexData( iVertexIndex );
		if ( v.m_iStrokeID < m_iVertexCount && m_pArray[v.m_iStrokeID].m_iVertexIndex == iVertexIndex )
			return m_pArray[v.m_iStrokeID].m_vNormal;
		else
			return v.m_vNormal;
	};
	

    // this function is not being inlined as it is too big, si it is split into a small inlined part,
    // and the larger not inlined part...
    private:
    VertexChange &Add_uncached(     // see arg list of Add just below....
		unsigned int  iVertexIndex, 
		unsigned int  iFaceIndex,
        Vertex       &v, 
		bool          bPrecalculateLayerIndex = false );

    public:
    /// Register a vertex for the change, and returns the corresponding VertexChange structure. 
    /// This function must be called before modifying the position of a vertex.
	inline VertexChange &Add( 
		unsigned int iVertexIndex, ///< [in] Index of the vertex
		unsigned int iFaceIndex,   ///< [in] Index of any face which uses the vertex
		bool bPrecalculateLayerIndex = false ///< [in] When this parameter is true, the function will 
                                             /// precalculate the layer index of the vertex.
		)
	{
		Vertex &v = m_pMesh->VertexData( iVertexIndex );
		if ( v.m_iStrokeID < m_iVertexCount && 
             m_pArray[v.m_iStrokeID].m_iVertexIndex == iVertexIndex )
			return m_pArray[v.m_iStrokeID]; // 80% of the time it hits this...
        else 
            return Add_uncached(iVertexIndex, iFaceIndex, v, bPrecalculateLayerIndex);
    };

	/// This function must be called when no more vertices will be changed within the operation.
	void Finish( 
		bool bUndo = true	///< [in] When this parameter is true, the changes made to the vertex positions are automatically stored
			/// in the undo buffer, and becomes undoable
		);

private:
	Mesh *m_pMesh;

	Store<VertexChange> &m_pArray;
	unsigned int &m_iVertexCount;

	friend class Mesh;
};

/// \brief This object is used to manage the lock on a mesh.
///
/// When a mesh is locked for exclusive write access, an instance of this class can be used as the guard for the mesh.
/// When someone is trying to unlock the mesh, this class is used to determine if the mesh can be unlocked. The guard
/// can deny the unlock, or can perform cleanup on the mesh before letting other code modify the mesh.
class MBDLL_DECL MeshUnlocker
{
public:
	/// \brief This function is called when someone wants to remove a lock from a mesh.
	///
	/// This function can allow or deny removing the lock from the mesh. It can also perform some operations on the mesh
	/// before passing it to another code to modify.
	virtual bool Unlock( 
		Mesh *pMesh ///< [in] Address of the mesh which is being unlocked.
		);
};

}; // end of namespace mudbox


