/***************************************************************************
 *                          Zanoza Modeler v2.x                            *
 *      This is unpublished propietary source code of Zanoza Software.     *
 *      The copyright notice does not evidence any actual or intended      *
 *                    publication of such source code.                     *
 *                                                                         *
 *                   Copyright (c) 2002 Zanoza Software.                   *
 *                                                                         *
 *                        All rights reserved.                             *
 ***************************************************************************
 *--------------------------------------------------------------------------
 * @author:   Oleg M.
 *--------------------------------------------------------------------------
 * @purpose:  ZModeler's vertex buffer class. a.k.a. VertexTable
 *--------------------------------------------------------------------------
 * @histroy: 23.04.2003. Created
 */
#ifndef zvertexbuffer_h_included
#define zvertexbuffer_h_included
#include <core/coreTypes.h>

//------------------------------------------------------
//  ZVertexBuf - vertex buffer for editable meshes
//------------------------------------------------------
class DLL_LINKAGE ZVertexBuf
{
  //
  // constructors/destructors
  //
private:
  ZVertexBuf();
public:
  ZVertexBuf(const DWORD dwFormat, const long dwAlloc = 16);
  ZVertexBuf(const ZVertexBuf& vBuf);
  ~ZVertexBuf();

public:
  //
  // operators
  //
  ZVertex& operator [] (const long n);
  ZVertex& operator [] (const long n) const;
  ZVertexBuf& operator = (const ZVertexBuf& vBuf);
  
public:
  //
  // operations
  //
  inline ZVertex& at(const long n) { return (*this)[n]; }
  // provides vertex storage format:
  inline DWORD format() const { return m_dwFormat; }
  // provides supported vertex formats:
  virtual ZRESULT enumFormats(tULongSeq& seqFormats) const;
  // format can be changed at any time but it involves memory reallocation.
  virtual DWORD format(const DWORD dwNewFormat); //VERTEX_HAS_ bit-masked value
  // provides size of allocated buffer (vertices)
  inline DWORD maximum() const    { return m_dwBufSize; }
  // amount of vertices in the buffer
  inline long length() const     { return m_nLength;  }
  // stride (in bytes) of vertices in the buffer
  inline DWORD stride() const     { return m_dwStride;  }
  // provides raw buffer pointer
  inline BYTE* getBuffer() const  { return m_pBuffer;   }
  // sets new length for the buffer
  void length(long newLength);
  //add single item at the end of the buffer
  void add(ZVertex& vert);
  //inserts single item at specified position
  //pos is zero-based; call with pos == m_nLength
  //equal to add(item);
  void insert(ZVertex& vert, long pos);
  //erases single item at specified position.
  void erase(long pos);
  //clears the buffer.
  void clear(bool bForceRelease=false);
  //sets 'invalid' flag to indicate that vertex buffer was changed
  inline void invalidate()  { m_bInvalidate = true; }
  inline bool invalid()     { return m_bInvalidate; }
  //provides IVertexBuffer interface for rendering.
  ZRESULT getVertexBuffer(IVertexBuffer** ppBuffer);

  //
  // mass status alter:
  //
  inline void selectAll(bool bSelect=true) 
    { massStatus(bSelect ? STATUS_SELECTED : 0, bSelect ? 0 : STATUS_SELECTED); }
  inline void showAll(bool bShow=true)
    { massStatus(bShow ? 0 : STATUS_HIDDEN, bShow ? STATUS_HIDDEN : 0); }
  inline void enableAll(bool bEnable=true)
    { massStatus(bEnable ? STATUS_ENABLED : 0, bEnable ? 0 : STATUS_ENABLED); }
  inline void acitvateAll(bool bActivate=true)
    { massStatus(bActivate ? STATUS_ACTIVE : 0, bActivate ? 0 : STATUS_ACTIVE); }
  inline void selectActive() 
    { massStatusChange(STATUS_SELECTED, 0, STATUS_ENABLED | STATUS_ACTIVE); }
  inline void hideSelected() 
    { massStatusChange(STATUS_HIDDEN, 0, STATUS_ENABLED | STATUS_SELECTED); }
  void massStatus(const DWORD dwAdd, const DWORD dwRemove); 
  void massStatusChange(const DWORD dwAdd, const DWORD dwRemove, 
                        const DWORD dwIfHasStatus = STATUS_ENABLED,
                        const DWORD dwIfHasntStatus = STATUS_HIDDEN); 

private:
  //
  // memory management routines:
  //
  BYTE*   allocate(const DWORD dwFormat, const long dwSize) const;
  void    release(BYTE* pBuffer) const;
public:
  // includes caching and aligning.
  static DWORD getFVFStride(const DWORD dwFormat/*not a fvf*/);
  static DWORD getFVF(const DWORD dwFormat);
  static DWORD getFormatStride(const DWORD dwFormat);
  // writes vertex into supplied pointer. pDestPtr should point onto a buffer
  // which is at least getFVFStride(dwFormat) bytes. amount of bytes ACTUALLY
  // written is returned. this value is less or equal getFVFStride(dwFormat).
  static DWORD writeVertex(void* pDestPtr, const DWORD dwFormat, ZVertex& vtx);

private:
  //
  // data members
  //
  BYTE*                   m_pBuffer;    //buffer for storing the data
  DWORD                   m_dwBufSize;  //allocated size (vertices)
  long                    m_nLength;    //used length (vertices)
  DWORD                   m_dwStride;   //vertex stride
  DWORD                   m_dwFormat;   //must be set first
  DWORD                   m_dwHWBufSize;//sizeof IVertexBuffer's buffer in bytes.
  bool                    m_bInvalidate;//true if m_pBuffer's data differs from m_pVBuffer data
#if defined(ZM_NO_DIRECTX) || defined (ZM_NO_COM)
  ZStdPtr<IVertexBuffer>  m_pVBuffer;   //buffer for rendering (write-only)
#else
  ZPtr<IVertexBuffer>     m_pVBuffer;   //buffer for rendering (write-only)
#endif
};


#endif //zvertexbuffer_h_included

