Class wrapper for a vertex buffer

Started by
5 comments, last by Bonehed316 18 years, 10 months ago
Hi guys! I'm trying to wrap a class around a IDirect3DVertexBuffer9. My goal is to be able to hold a copy of an array of vertices and to simplify drawing routines. So I declared the following class :

class CVertexBuffer
{
private:
        // Pointer to the array of custom vertices
	void *vData;
        
	IDirect3DVertexBuffer9* pVertexBuffer;
        // Information about the array, and the custom vertices
	UINT nSize, nVertices;
        // Format of a vertex
	DWORD FVF_Filter;

public:
	CVertexBuffer();
	~CVertexBuffer();

	HRESULT InitVertexBuffer(void* vertexData, UINT numVertices, UINT sizeVertices, DWORD FVF);
	HRESULT Draw(D3DPRIMITIVETYPE type);
	HRESULT Draw(D3DPRIMITIVETYPE type, UINT startVertex, UINT vertexCount);
};

Seems to be ok so far... Now, I have some problems with the initialization. Everytime I try to run it, it enters an endless loop. I've successfully used the same vertex buffer initialization routine in a rendering function. I'm not sure if my use of the vData pointer is correct... Take a look! :)
HRESULT CVertexBuffer::InitVertexBuffer(void *vertexData, UINT numVertices, UINT sizeVertices, DWORD FVF)
{
	// First, make sure we have a clean pVertexBuffer
	if(pVertexBuffer != NULL)
	{
		pVertexBuffer->Release();
	}

	// Create a VertexBuffer from the d3d device
	HRESULT hRes = g_pD3DDevice->CreateVertexBuffer(
		numVertices*sizeVertices,
		0,
		FVF,
		D3DPOOL_DEFAULT,
		&pVertexBuffer,
		0);

	// Error checking
	if(FAILED(hRes))
	{
		DXTRACE_ERR("Couldn't create Vertex Buffer!", hRes);
		return hRes;
	}

	// Lock the vertex buffer into vData
	hRes = pVertexBuffer->Lock(0, 0, &vData, 0);

	// Error checking
	if(FAILED(hRes))
	{
		DXTRACE_ERR("Couldn't lock Vertex Buffer!", hRes);
		return hRes;
	}

	// Copy data from parameter
	memcpy(vData, vertexData, numVertices*sizeVertices);

	// Unlock the vertex buffer to let D3D use it later
	pVertexBuffer->Unlock();

	// Remember the data for drawing calls
	nSize = sizeVertices;
	nVertices = numVertices;

	return D3D_OK;
}
Every comment will be greatly appreciated! :D
Advertisement
It looks good to me. I dont see anything that would cause an infinate loop, maybe you should walk through it with a debugger?
How do you mean an infinite loop?
I do not see any place where you can trap yourself in a loop in that function.

My guess you are doing something like using the copy constructor to call the copy constructor which results in an infinite loop and eventually a stack flood.

My first guess was to find a while() {} statement, but.... there is none.

You are probably in some un-seeable way causing your class to continuely do something.
How does your constructor work?

Also, your usage parameter should be D3DUSAGE_WRITEONLY. Dx9 Debug will complain on D3DPOOL_DEFAULT without the usage D3DUSAGE_WRITEONLY. That still means you can lock it and render it.
It tried to put breakpoints in various places, following Bonehed316's advice. It turns out that I could see everything up to the point where the D3D device was created. After that, I wouldn't be able to see my program and VC++ .NET would freeze...

I tried running my program outside VC++, and it worked fine! So I guess I had IDE issue more than a DirectX issue.

Thanks for your advice, Halsafar and Bonehed316!
This is one i finished working on a good while ago:

#ifndef _DYNAMIC_VERTEX_BUFFER_H_#define _DYNAMIC_VERTEX_BUFFER_H_#include <vector>#include <d3dx9.h>namespace{	const unsigned int	grow_default = 1000;	const unsigned int	size_default = 1000;}struct Dynamic_Vertexbuffer_Props{	LPDIRECT3DDEVICE9	device;	DWORD				fvf;	D3DPOOL				pool;	DWORD				usage;};template <class T>class DynamicVertexBuffer{public:	DynamicVertexBuffer( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props );	~DynamicVertexBuffer();	void Add( T& vertex );	void Add( T vertices[], unsigned int size );	void Add( const std::vector<T>& vec );	void Add( const DynamicVertexBuffer<T>& dvb );	void			Extract ( unsigned int first, unsigned int last, std::vector<T>& out );	void			Clear();	unsigned int	Size() const;	unsigned int	Capacity() const;	void			Grow();	void			Reset();	void			Reset( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props );	IDirect3DVertexBuffer9* operator&()	{		if ( m_vertexBuffer )			return m_vertexBuffer;		else			return NULL;	}	const IDirect3DVertexBuffer9&	operator*()	{		if ( m_vertexBuffer )			return *m_vertexBuffer;	}	inline void operator+=( T& vertex )						{	Add( vertex	); };	inline void operator+=( const std::vector<T>& vec )			{	Add( vec	); };	inline void operator+=( const DynamicVertexBuffer& dib ) {	Add( dib	); };	const LPDIRECT3DVERTEXBUFFER9&		Const_Ref() { return m_vertexBuffer; };private:	Dynamic_Vertexbuffer_Props	m_props;	LPDIRECT3DVERTEXBUFFER9		m_vertexBuffer;    unsigned int				m_size;	unsigned int				m_capacity;	bool						m_validProps;	bool						m_made;	unsigned int				m_grow;	void Create(unsigned int size);	bool ValidateProperties(const Dynamic_Vertexbuffer_Props* props);};template<class T>DynamicVertexBuffer<T>::DynamicVertexBuffer( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props ) 	:	m_capacity(0), 		m_size(0), 		m_made(false),		m_validProps(false),		m_vertexBuffer(NULL){	Reset( grow, capacity, props );}template<class T>DynamicVertexBuffer<T>::~DynamicVertexBuffer(){	Reset();}template<class T>void DynamicVertexBuffer<T>::Add( T& vertex ){	if ( m_made == true )	{		if ( 1 <= (m_capacity - m_size ) )		{			void* pDest;			m_vertexBuffer->Lock( m_size*sizeof(T), sizeof(T), &pDest, 0);			memcpy( pDest, &vertex, sizeof( T ) );			m_vertexBuffer->Unlock();			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Single vertex added\n");			#endif				m_size++;		}		else		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for single vertex\n");			#endif			Grow();			Add( vertex );		}	}}template<class T>void DynamicVertexBuffer<T>::Add( T vertices[], unsigned int size ){	if ( m_made == true )	{		if ( size <= (m_capacity - m_size ) )		{			void* pDest;			m_vertexBuffer->Lock( m_size * sizeof(T), size *sizeof( T ), &pDest, 0);			memcpy( pDest, &vertices[0], size * sizeof( T ) );			m_vertexBuffer->Unlock();			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Vertex array added\n");			#endif			m_size += size;		}		else		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for vertex array\n");			#endif			Grow();			Add(vertices, size);		}	}}template<class T>void DynamicVertexBuffer<T>::Add( const std::vector<T>& vec ){	if ( m_made == true )	{		if ( vec.size() <= (m_capacity - m_size ) )		{			void* pDest;			void* pMCRet = NULL;			m_vertexBuffer->Lock( m_size * sizeof(T), (unsigned int) vec.size() * sizeof(T), &pDest, 0);			pMCRet = memcpy( pDest, &vec[0], vec.size() * sizeof( T ) );			if ( pMCRet == NULL )			{				MessageBox(NULL, "pMCRET","", MB_OK );			}			m_vertexBuffer->Unlock();			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Vertex std::vector added\n");			#endif			m_size += (unsigned int) vec.size();		}		else		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Grow needed for vertex std::vector\n");			#endif			Grow();			Add( vec );		}	}}template<class T>void DynamicVertexBuffer<T>::Add( const DynamicVertexBuffer<T>& dvb ){	std::vector<T> tempVertices(dvb.Size());	Extract(0, dvb.Size(), tempVertices);	Add(tempVertices);}template<class T>unsigned int DynamicVertexBuffer<T>::Size() const{	return m_size;}template<class T>unsigned int DynamicVertexBuffer<T>::Capacity() const{	return m_capacity;} template<class T>void DynamicVertexBuffer<T>::Grow(){	if ( m_made == true )	{		Create( m_capacity + m_grow );	}}template<class T>void DynamicVertexBuffer<T>::Reset(){	m_made = false;	m_size = 0;	m_capacity = 0;	m_validProps = false;	if ( m_vertexBuffer != NULL )		m_vertexBuffer->Release();	#ifdef DYNAMICVB_DEBUG	OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Reset\n");	#endif}template<class T>void DynamicVertexBuffer<T>::Reset( unsigned int grow, unsigned int capacity, const Dynamic_Vertexbuffer_Props* props ){	m_made = false;	m_size = 0;	m_capacity = 0;	m_validProps = false;	if ( m_vertexBuffer != NULL )		m_vertexBuffer->Release();	#ifdef DYNAMICVB_DEBUG	OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Reset\n");	#endif	if ( ValidateProperties( props ) )	{				#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (INFO) Properties valid\n");		#endif		this->m_props = ( *props );		if ( grow == 0 )		{			m_grow = grow_default;			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Default grow used\n");			#endif		}		else		{			m_grow = grow;			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Custom grow used\n");			#endif				}		if ( capacity != 0 )		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Custom capacity used\n");			#endif				Create( capacity );		}		else		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Default capacity used\n");			#endif				Create( size_default );		}	}}template<class T>void DynamicVertexBuffer<T>::Clear(){	m_size = 0;	#ifdef DYNAMICVB_DEBUG	OutputDebugString("DynamicVertexBuffer: (INFO) DynamicVertexBuffer Clear\n");	#endif}template<class T>void DynamicVertexBuffer<T>::Create( unsigned int capacity ){	if ( m_validProps == true )	{		if ( m_vertexBuffer != NULL )		{			void* pSource;			void* pDest;			// create a vector to hold the verts			std::vector<T> tempVerts(m_size);			// HERE: Only backup of vertices if m_size > 0;			if ( m_size > 0 )			{				// Lock the current vertex buffer, copy, unlock				m_vertexBuffer->Lock( 0, m_size, &pSource, 0);				memcpy( &tempVerts[0], pSource, m_size * sizeof(T) );				m_vertexBuffer->Unlock();				#ifdef DYNAMICVB_DEBUG				OutputDebugString("DynamicVertexBuffer: (INFO) Vertices backed up before grow\n");				#endif			} // BACKUP MADE			// release the old buffer			m_vertexBuffer->Release();			// create a new one			m_props.device->CreateVertexBuffer(		capacity * sizeof(T),													m_props.usage,													m_props.fvf,													m_props.pool,													&m_vertexBuffer,													NULL);			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Larger vertex buffer created\n");			#endif			// set the new size			m_capacity = capacity;			// HERE: Restore the vertices			if ( m_size > 0 )			{				// Lock the current vertex buffer, copy, unlock				m_vertexBuffer->Lock( 0, m_size, &pDest, 0);				memcpy( pDest, &tempVerts[0], m_size * sizeof(T) );				m_vertexBuffer->Unlock();				#ifdef DYNAMICVB_DEBUG				OutputDebugString("DynamicVertexBuffer: (INFO) Vertices restored after grow\n");				#endif			}		}		else if ( m_vertexBuffer == NULL )		{			m_props.device->CreateVertexBuffer(	(capacity) * sizeof(T),												m_props.usage,												m_props.fvf,												m_props.pool,												&m_vertexBuffer,												NULL);						#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (INFO) Vertex buffer created\n");			#endif			m_capacity = capacity;			m_made = true;		}	}}template<class T>bool DynamicVertexBuffer<T>::ValidateProperties(const Dynamic_Vertexbuffer_Props* props){	bool valid = true;	if ( props->device == NULL )	{		valid = false;		#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (ERROR) Device invalid!\n");		#endif	}	if ( props->fvf    == NULL )	{		// This is now acceptable for elements		//valid = false;		#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (ERROR) FVF invalid!\n");		#endif	}	if ( ( props->pool   <  0 ) || ( props->pool   >  3 ) ) 	{		valid = false;		#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (ERROR) Pool invalid!\n");		#endif	}	if ( props->usage  < 0 )	{		valid = false;		#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (ERROR) Usage invalid!\n");		#endif	}	if ( valid == true )	{		m_validProps = true;	}		return valid;}template<class T>void DynamicVertexBuffer<T>::Extract ( unsigned int first, unsigned int last, std::vector<T>& out ){	// check to see if the buffer is writeonly, if so dont allow this and throw a warning to debug out	if ( !(this->m_props.usage & D3DUSAGE_WRITEONLY) )	{		if ( out.capacity() >= m_size )		{			if ( ( last > first ) && (last <= m_size) )			{				void* pSource;				m_vertexBuffer->Lock( first * sizeof( T ), ( (last-first) * sizeof( T ) ), &pSource, 0);				memcpy( &out[0], pSource, (last-first) * sizeof( T ) );				m_vertexBuffer->Unlock();				#ifdef DYNAMICVB_DEBUG				OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - successful\n");				#endif			}		}		else		{			#ifdef DYNAMICVB_DEBUG			OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - target std::vector bad size\n");			#endif		}	}	else	{		#ifdef DYNAMICVB_DEBUG		OutputDebugString("DynamicVertexBuffer: (ERROR) Extract call - Write only buffer specified\n");		#endif	}}#endif


ace
Quote:Original post by Amazed
It tried to put breakpoints in various places, following Bonehed316's advice. It turns out that I could see everything up to the point where the D3D device was created. After that, I wouldn't be able to see my program and VC++ .NET would freeze...

I tried running my program outside VC++, and it worked fine! So I guess I had IDE issue more than a DirectX issue.


You have to run in windowed mode or use multiple monitors. Break points will freeze your program if you're in full-screen "top-most" mode. Was that the problem?
That's a good point! You always need a windowed mode so you can debug yourself. If you want to debug in fullscreen, you need to send info to the debug window at runtime, or to a seperate log file, or whatever. I know there is a function for outputting to the debug window, but I cant remember it right off hand.

Also make sure you enable the DX DEBUG runtime (in your control panel), so you can see dx outputs easier. There are also debug lib files you can link to (d3dx9d.lib I believe) which give you debug ability on dx variables.

This topic is closed to new replies.

Advertisement