Sign in to follow this  

Dynamic vertex buffer sizes? (DX9 C++)

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 prototype

SomeMethod(reinterpret_cast<void*>(&(List[0])));


HTH

Share this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by zyrolasting
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.

*** 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 this post


Link to post
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<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.


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 );

d) - Added and ready.

Many thanks for your help!

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

Share this post


Link to post
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.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this