• 13
• 18
• 19
• 27
• 9

# Dynamic vertex buffer sizes? (DX9 C++)

This topic is 3406 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm reading a tutorial on Terrains, and I'm trying to figure out how to define a vertex/Index buffer without having my compiler complain it's making an array of unknown size, especially since I want the flexibility of writing a function with the width and height of the initial terrain plane (in vertices) for parameters. How can I accomplish this?

##### Share on other sites
a vertex buffer needs a size, you either have to take the width and depth in the constructor, or create the vertex buffer in the function that takes these arguements.

##### Share on other sites
Wouldn't I get the same compiler error regarding unknown size if I assigned the values in the constructor? It seemed that I would only remove the error if I #define'd a constant or actually wrote a number in there.

I think I see what you mean about the buffer creation itself though.
If I did that, I'd still have the issue of allocating the right array size.

##### Share on other sites
can you post a code sample? I think i misunderstood what you were saying, the LPDIRECT3DVEREXBUFFER9 object isn't the one with hte problem, it's the array you're using to set the vertices?

in c++, if you use a normal array, it's size must be constant known at run time, you'd have to dynamicly allocate the array.

VertexFormat* TerrainVertexList = new VertexFormat[numVerticesInTerrain];

##### Share on other sites
I think I remember trying something like that when attempting to make a struct for controlling meshes, namely the textures.

But yes, I was referring to an array where vertex coordinates are stored.
I'm going to type a quick struct right here. I'm still really new to manually managing allocated memory. Would something like this be appropriate/close to what you are talking about?

struct CustVertex { float x, y, z; };struct tTerrain{     LPDIRECT3DVEREXBUFFER9 Buffer;     CustVertex* List;     tTerrain(int size)     {         List = new CustVertex[size];     }     ~tTerrain()     {          delete[] List;     }};

##### Share on other sites
struct Terrain{private:    std::vector<CustVertex> List;public:    Terrain(int size) : List(size) { }};

Will save you managing the memory manually.

You could even do away with specifiying the size at initialisation like that and just push_back() your vertices into the vector - the memory management under the hood will almost certainly be efficient enough.

If you need to pass a pointer to the data to a D3D method, you can use:

void SomeMethod(void *Data); // example prototypeSomeMethod(reinterpret_cast<void*>(&(List[0])));

HTH

##### Share on other sites
That did help a lot. I wrote this to try the basics. This is still a new area for me, so can I impose any of you to see if I'm on the right track? I'm trying this to get the jist of it.

bool CIsoDev_Terrain::CreateTerrain(char* Filename){	// Vector list in struct definition.	CustVertex entry; //The vertex structure. The Vector list is of the same type.	int i; // Will be used to determine how many vertices were added.	ifstream terrainFile(Filename);	if (terrainFile.fail())	{		OutputDebugString("QE - (ERROR)(D3D) - CreateTerrain() - Failed to open file containing vertex data.\n");		return false;	}	// Input the data from file into a vertex entry, then add that entry to the List.	// i starts at 1 to remain consistent with the number of entries.	for (i = 1; !terrainFile.eof(); ++i)	{		terrainFile >> entry.x >> entry.y >> entry.z >> entry.color;		List.push_back(entry);    }	//Create the buffer.	if (FAILED(QE.D3D_Device->CreateVertexBuffer(i*sizeof(CustVertex), 0, VERTEX_FVF, D3DPOOL_DEFAULT, &VertBuffer, NULL)))	{		OutputDebugString("QE - (ERROR)(D3D) - tIsoDevBasicMesh::CreateTerrain() - Failed to create vertex buffer.\n");		return false;	}    void* pVoid;	// Lock the buffer and input vertices.    if (FAILED(VertBuffer->Lock(0, i*sizeof(CustVertex), (void**)&pVoid, 0)))	{		OutputDebugString("QE - (ERROR)(D3D) - tIsoDevBasicMesh::CreateTerrain() - Failed to lock buffer.\n");		return false;	}    memcpy(pVoid, VertexCoords, i*sizeof(CustVertex));	VertBuffer->Unlock();	return true;}

[Edited by - zyrolasting on November 19, 2008 7:53:40 AM]

##### Share on other sites
Quote:
 Original post by zyrolastingThat did help a lot. I wrote this to try the basics. This is still a new area for me, so can I impose any of you to see if I'm on the right track? I'm trying this to get the jist of it.*** Source Snippet Removed ***

All looks pretty good. Just a couple of points.

a) Rather than maintain that i variable for the number of vertices added, you can just query List.size() at any point. std::vector<> "remembers" its current size.

b) What's VertexCoords in that memcpy line? I was expecting:

memcpy(pVoid, reinterpret_cast<void*>(&(List[0])), i*sizeof(CustVertex));

to copy the data from your std::vector of vertices into the vertex buffer.

c) You might like to look at std::copy() over memcpy for C++ - it doesn't make any difference with a POD type like a vertex, but it respects copy-constructors for more complex class types and should be equivalent to memcpy for a POD so it is a good habit to get into using it for everything.

d) You should guard against loading a file with zero vertices in - several lines above will probably cause a crash if the List is empty.

##### Share on other sites
Quote:
 All looks pretty good. Just a couple of points.a) Rather than maintain that i variable for the number of vertices added, you can just query List.size() at any point. std::vector<> "remembers" its current size.b) What's VertexCoords in that memcpy line? I was expecting:memcpy(pVoid, reinterpret_cast(&(List[0])), i*sizeof(CustVertex));to copy the data from your std::vector of vertices into the vertex buffer.c) You might like to look at std::copy() over memcpy for C++ - it doesn't make any difference with a POD type like a vertex, but it respects copy-constructors for more complex class types and should be equivalent to memcpy for a POD so it is a good habit to get into using it for everything.d) You should guard against loading a file with zero vertices in - several lines above will probably cause a crash if the List is empty.

a) - Ah, noted.

b) - Right, Just a slip up on my part. the struct was originally called VertexCoords, and I renamed them to CustVertex as I was posting here for the sake of readability. I actually started to do the same for my source, since it did help. I missed a spot.

c) - Noted again, I take it using List.Begin() and .End() would be safe for this? EDIT: Whoa, what was that example doing?
Sorry, apparently those aren't even members. I was looking at an online example that implied they were. That being the case, is this call correct?
I know this is a simplistic question, but I have no access to my compiler at this moment. Is my memory hazed, or isn't there supposed to be something template related to this call?

std::copy( List, ( List.size() )*sizeof(CustVertex), pVoid );

[Edited by - zyrolasting on November 20, 2008 12:39:23 AM]

##### Share on other sites
b) Putting the name of the structure won't work. You need to supply a pointer to the start of the data, hence the &(List[0]). std::vector<>'s data is contiguous so you can take the address of the first element to effectively get a pointer to the data.

c) You need to change your Lock call a bit:

CustVertex *Buffer;VertBuffer->Lock(0,List.size()*sizeof(CustVertex),reinterpret_cast<void**>(&Buffer),0);std::copy(List.begin(),List.end(),Buffer);

This way, the pointer that the Lock returns is of the correct type, so pointer arithmetic will work correctly. I've omitted the fail check just for brevity - it is of course a good idea. I'm using the C++ style reinterpret_cast rather than the C style cast as it is a clearer statement of the intent.

Note the lower case on begin() and end() methods of the vector.

The relevant overload of std::copy takes input iterators to the beginning and one-past-the-end of the source and an output iterator to the beginning of the destination. How it is implemented is irrelevant, but imagine it is something like:

template<class In,class Out> void copy(In start,In end,Out dest){    while(start!=end) *dest++=*start++;}

This is probably nonsense and just to give an example of the concept - a clever compiler should be able to translate std::copy for POD types down to a memcpy.