/* 
 * 
 * Confidential Information of Telekinesys Research Limited (t/a Havok).  Not for disclosure or distribution without Havok's
 * prior written consent.This software contains code, techniques and know-how which is confidential and proprietary to Havok.
 * Level 2 and Level 3 source code contains trade secrets of Havok. Havok Software (C) Copyright 1999-2008 Telekinesys Research Limited t/a Havok. All Rights Reserved. Use of this software is subject to the terms of an end user license agreement.
 * 
 */

#ifndef HK_GRAPHICS_VERTEX_SET
#define HK_GRAPHICS_VERTEX_SET

#include <Common/Base/Types/hkBaseTypes.h>
#include <Graphics/Common/DisplayContext/hkgDisplayContext.h>
#include <Graphics/Common/Geometry/VertexSet/hkgVertexSetDefines.h>

class hkgFaceSet;

/// A vertex set is basically a wrapper for a pure float vertex array. It will 
/// be stored internally in an interleaved format, but the exact layout of that
/// format is left to the implementation. A vertex set is not reference counted 
/// as it is assumed that a face set is the only user.
class hkgVertexSet
{
	public:

		HKG_DECLARE_NONVIRTUAL_CLASS_ALLOCATOR( hkgVertexSet );

			/// Create a platform specific vertex set for the given face set owner and in a given context
		static hkgVertexSet* (HK_CALL *create)(hkgFaceSet* owner, hkgDisplayContext* context); 

			/// Delete the vertex set. This will release all held resources.
		virtual ~hkgVertexSet(); 

			/// Set the number of vertices and which optional components to have. 
			/// Normals are assumed, but this will be changed to be an option in future too.
			/// This will reallocate any held buffers and does not preserve data. If you set the 
			/// numVerts to 0 then it will deallocate all held resources.
		virtual void setNumVerts(int nv, HKG_VERTEX_FORMAT vertexFormat) = 0;

			/// Get the number of vertices represented by the vertex set.
		inline int getNumVerts() const;

		/// Lock the vertex set so that you can alter its values to read
		/// consistent data from the buffers. It locks from 'offset' len vertices.
		/// If len is -1, the lock will be to the end of the buffers and negative offset is
		/// not allowed.
		virtual unsigned char* lock(int offset = 0, int len = -1) = 0;

		/// Lock the vertex set read only so that you can read its values to read
		/// consistent data from the buffers. It locks from 'offset' len vertices.
		/// If len is -1, the lock will be to the end of the buffers and negative offset is
		/// not allowed.
		virtual unsigned char* lockRo(int offset = 0, int len = -1){ return lock(offset,len); };

			/// Normally we use interleaved vertex formats
			/// such that all vertex information is 
		inline bool isInterleaved() const;

		/// Unlock the given range, from 'offset' of 'len' vertices. This should
		/// match what you previously locked. Call this once you no longer require
		/// write access or consistent read access.
		virtual void unlock(int offset = 0, int len = -1) = 0; 

		/// Unlock the given range, from 'offset' of 'len' vertices. This should
		/// match what you previously locked. Call this once you no longer require
		/// write access or consistent read access.
		virtual void unlockRo(int offset = 0, int len = -1){ unlock(offset,len); }; 

			/// Get the distance, or stride, between each vertex component. There are
			/// 4 bytes in a float, so if stride is 12 then the vertex array is 
			/// not interleaved, but all components are split internally so lock()
			/// returns the pure positional vertex array. In DirectX for example, a full format such as:
			/// 
			/// vert{
			///    float x,y,z;
			///    float nx,ny,nz;
			///	   float u,v;
			///    unsigned color;
			/// }
			///    which would have a stride of 8*float + 4 = 36 bytes.
			/// In this case, lock() returns the interleaved buffer of all components
			/// such that buf[i*stride] is the ith vert as above (take out u.v / color as required).
		inline int getStrideInBytes();

			/// Set the client pointers / stream pointers to this data. 
		    /// This will effectively get the hardware to use this vertex set as the current vertex buffers.
		virtual void setStreams() = 0; 
		
			/// Set the vertex component at index i. You must lock the buffer first. Default just sets using the offsets given.
		virtual void setVertexComponentData(HKG_VERTEX_COMPONENT component, int index, const void* data);

		// The PS2 uses a densely packed vertex format with the blending
		// weights and indices packed across multiple components.
		// These components are returned into a pre-allocated 4 byte buffer pointed to by 'data'.

			/// Get the vertex component at index i. You must lock the buffer first.
		inline void* getVertexComponentData( HKG_VERTEX_COMPONENT component, int index, hkUint8* data = HK_NULL );

			/// Get the vertex component at index i. You must lock the buffer first.
		inline const void* getVertexComponentData( HKG_VERTEX_COMPONENT component, int index, hkUint8* data = HK_NULL ) const;

			/// Get the offset from the vertex start addr to the given component;
			/// ulong so that it can encode non interleaved buffer offsets
		hkUlong getVertexComponentOffset(HKG_VERTEX_COMPONENT component) const;

			/// Get vertex format for the vertex set. The return type is
			/// a bit field of enabled components.
			/// The components are at the top of this file.
		inline HKG_VERTEX_FORMAT getVertexFormat() const;

			/// Get the component storage format
		inline HKG_VERTEX_STORAGE getVertexComponentFormat(HKG_VERTEX_COMPONENT component) const;

		inline int getComponentSize( HKG_VERTEX_COMPONENT component ) const;

		void copyExistingVertex( int toThisIndex, int otherIndex, hkgVertexSet* otherSet );

		inline hkgFaceSet* getOwner(); 
		
		inline const hkgFaceSet* getOwner() const; 

		inline hkgDisplayContext* getContext() const;

			/// As we can have vertex specific data (vertex colors, tangents, etc)
			/// by default the material may have chosen the wrong shader (most of the 
			/// time it will have been correct though). This is called before drawing the 
			/// geom, enabling it to chose the correct shader et
		inline HKG_MATERIAL_VERTEX_HINT getMaterialHints() const;

		/// This will count all texcoord slots used plus the tangent and binormals if present (as they are really just tcoords too)
		inline int getNumTextureCoordsUsed() const;


	protected:

		inline hkgVertexSet(hkgFaceSet* owner, hkgDisplayContext* context);
		
		hkgFaceSet*		m_owner;
		hkgDisplayContext* m_context;

		// counters
		int	m_numVerts;
		int	m_stride; 
		bool m_interleaved; // normal true

		HKG_VERTEX_FORMAT	m_vertexFormat; // which componets are used
		hkUlong				m_storageOffsets[HKG_VERTEX_COMPONENT_NUM]; // offsets to the components relative to lockedBuf
		HKG_VERTEX_STORAGE	m_storageFormats[HKG_VERTEX_COMPONENT_NUM]; // the format of each
		static hkUint8	    g_componentSizes[HKG_VERTEX_STORAGE_NUM]; // use HKG_VERTEX_STORAGE to index into this to get the size in bytes
		unsigned char*	m_lockedBuf; // interleaved, default locked buf
};

#include <Graphics/Common/Geometry/VertexSet/hkgVertexSet.inl>

#endif //HK_GRAPHICS_VERTEX_SET

/*
* Havok SDK - NO SOURCE PC DOWNLOAD, BUILD(#20080529)
*
* Confidential Information of Havok.  (C) Copyright 1999-2008 
* Telekinesys Research Limited t/a Havok. All Rights Reserved. The Havok
* Logo, and the Havok buzzsaw logo are trademarks of Havok.  Title, ownership
* rights, and intellectual property rights in the Havok software remain in
* Havok and/or its suppliers.
*
* Use of this software for evaluation purposes is subject to and indicates 
* acceptance of the End User licence Agreement for this product. A copy of 
* the license is included with this software and is also available at
* www.havok.com/tryhavok
*
*/
