Sign in to follow this  
utilae

Index buffers, drawindexedprimitive, etc . . .

Recommended Posts

Hi, I am using C++ and Direct3D9. I have been trying to go from drawprimitive (with a vertex buffer) to draw indexed primitive (with a vertex and index buffer). My code worked with drawprimitive, but it seems that I can't get drawindexedprimitive to work. I have looked at code everywhere on how to implement an index buffer and drawindexedprimitive. My code is exactly like has been suggested, though it still does not work. 1)How do I test to see whether my graphics card supports draw indexed primitive and index buffers? Which members of the D3DCAPS9 caps structure to I test for? 2)Here is my code, in great detail. I hope someone can help me fix this. It crashes on the line drawindexedprimitive. ////VERTEX.cpp //Create the vertex buffer and index buffer
void CVertexManager::SetupVertices(void)
{		
	//create d3d9 vertex buffer
	HRESULT hr=g_pD3DDevice9->CreateVertexBuffer(sizeof(VERTEX)*10920,D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY,g_dwFVF,D3DPOOL_SYSTEMMEM,&g_pVertexBuffer,NULL);
	g_Log<<"SetupVertices() Create Vertex Buffer: "<<DXGetErrorString9(hr)<<endl;

	//create d3d9 index buffer (size=2 triangles * 3 indicies * sizeof(word))
	hr=g_pD3DDevice9->CreateIndexBuffer(6*sizeof(WORD),D3DUSAGE_WRITEONLY,D3DFMT_INDEX16,D3DPOOL_MANAGED,&g_pIndexBuffer,NULL);
	g_Log<<"SetupVertices() Create Index Buffer: "<<DXGetErrorString9(hr)<<endl;

	//fill index buffer
	WORD *usIndices=NULL;
	g_pIndexBuffer->Lock(0,0,(void**)&usIndices,0);//lock index buffer
	usIndices[0]=0;//index buffer data
	usIndices[1]=1;
	usIndices[2]=3;
	usIndices[3]=3;
	usIndices[4]=1;
	usIndices[5]=2;

	g_pIndexBuffer->Unlock();//unlock index buffer

	//set index buffer
	g_pD3DDevice9->SetIndices(g_pIndexBuffer);
}

//Add four vertices to make up a textured rectangle with 2 primitives
void CVertexManager::AddSquare(RECT &recPos,const float &fZOrder,TILE &TilePos)
{	
	if(m_lstVertexList.empty()==true)
	{
		m_nPrimitiveCount=0;
		m_nVertexCount=0;
	}

	//vertices must be sort in order of Z value (0.0 close, 10.0 far). Z values closer to 10 are rendered first.
	//Use RECT coordinates to create vertices
	VERTEX vrtBottomLeft,vrtTopLeft,vrtTopRight,vrtBottomRight;
	vrtTopLeft.x=recPos.left;      vrtTopLeft.y=recPos.top;        vrtTopLeft.z=fZOrder;     vrtTopLeft.tu=TilePos.m_tuLeft;      vrtTopLeft.tv=TilePos.m_tvTop;
	vrtTopRight.x=recPos.right;    vrtTopRight.y=recPos.top;       vrtTopRight.z=fZOrder;    vrtTopRight.tu=TilePos.m_tuRight;    vrtTopRight.tv=TilePos.m_tvTop;
	vrtBottomLeft.x=recPos.left;   vrtBottomLeft.y=recPos.bottom;  vrtBottomLeft.z=fZOrder;  vrtBottomLeft.tu=TilePos.m_tuLeft;   vrtBottomLeft.tv=TilePos.m_TvBottom;
	vrtBottomRight.x=recPos.right; vrtBottomRight.y=recPos.bottom; vrtBottomRight.z=fZOrder; vrtBottomRight.tu=TilePos.m_tuRight; vrtBottomRight.tv=TilePos.m_TvBottom;

	//add six vertices to the list of vertices
	// v1-----v2   //0.0-----0.0 //tu=horizontal
	// |----/-|    //|     /  |  //tv=vertical
	// |---/--|    //|   /    |
	// |--/---|    //| /      |
	// v0-----v3   //0.0-----1.0
	m_lstVertexList.push_back(vrtBottomLeft);
	m_lstVertexList.push_back(vrtTopLeft);
	m_lstVertexList.push_back(vrtTopRight);
	m_lstVertexList.push_back(vrtBottomRight);

	//update how many primitives and vertices there are to render
	++m_nPrimitiveCount;++m_nPrimitiveCount;
	m_nVertexCount+=4;
}

//Fill the vertex buffer with all the vertices in the list
void CVertexManager::FillVertexBuffer(void)
{
	//sort vertices in order of z value
	sort(m_lstVertexList.begin(),m_lstVertexList.end());
	
	//fill vertex buffer
    void *vb_vertices;
    g_pVertexBuffer->Lock(0,0,&vb_vertices,0);
    memcpy(vb_vertices,&(m_lstVertexList[0]),m_lstVertexList.size()*sizeof(VERTEX));
    g_pVertexBuffer->Unlock();
	
	//clear list of vertices
	m_lstVertexList.clear();
}

////MAIN.cpp //app_load
//create vertex buffer and index buffer
VertexManager.SetupVertices();

//set the flexible vertex format and stream source
g_pD3DDevice9->SetFVF(g_dwFVF);
g_pD3DDevice9->SetStreamSource(0,g_pVertexBuffer,0,sizeof(VERTEX));

//note: code that loads textures and other things is not included here

//app_loop
g_pD3DDevice9->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(255,255,0),1.0f,0);

g_pD3DDevice9->BeginScene();

//code showing recSquare and tile related things are not inculded here
VertexManager.AddSquare(recSquare,1.0f,TextureManager.GetTile("Texture1","Tile1"));

VertexManager.FillVertexBuffer();

//crashes on this line
g_pD3DDevice9->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,VertexManager.GetVertexCount(),0,VertexManager.GetPrimitiveCount());

g_pD3DDevice9->EndScene();

g_pD3DDevice9->Present(NULL,NULL,NULL,NULL);

Anyone able to help???

Share this post


Link to post
Share on other sites
Quote:
1)How do I test to see whether my graphics card supports draw indexed primitive and index buffers? Which members of the D3DCAPS9 caps structure to I test for?

All hardware and drivers will support index buffers. The only thing you need to check is the maximum number of primitives, and maybe (if you really need it) support for D3DFMT_INDEX32/32bit indexes. This can be done in the usual enumeration way.

Quote:
2)Here is my code, in great detail. I hope someone can help me fix this. It crashes on the line drawindexedprimitive.

I have to admit, I didn't read any of your code. You almost certainly need to stick the debug runtime on and watch the output. This will tell you why it failed - both the erronous return code and a message explaining it.

I spent quite a lot of time this afternoon writing up a wiki entry for NeXe titled Debugging. Follow it through if it's new to you, it will give you answers[attention]

If you don't understand the debug output, quote that back in this thread and we can help you further [smile]

Sorry to be a pain about the second question - but you'll learn to love the debug runtimes [grin]

Jack

Share this post


Link to post
Share on other sites
Just had a peek at the MSDN for you...

D3DCAPS9 has a couple of properties you want to check: D3DCAPS9::MaxPrimitiveCount and D3DCAPS9::MaxVertexIndex.

For enumeration of 16/32 index buffers look into IDirect3D9::CheckDeviceFormat( ).


if( FAILED( CheckDeviceFormat(
D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
??,
D3DUSAGE_DYNAMIC,
D3DRTYPE_INDEXBUFFER,
D3DFMT_INDEX32 ) ) )
{
//No support for 32bit index buffers, test for 16bit ones instead..?
}


hth
Jack

Share this post


Link to post
Share on other sites
When I run my app, it crashes at the drawindexedprimitive line. DebugView spits out this:
[1056] Direct3D9: (ERROR) :No valid index stream currently set. DrawIndexedPrimitive failed.

Although I am sure my stream source is being set, etc. I just think my graphics card can't do drawindexedprimitive.


I tried checking to see if my GeForce2 MX400 32MB graphics card could do index buffers, drawindexedprimitive, etc.


HRESULT hrhr=g_pD3D9->CheckDeviceFormat(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_A8R8G8B8,D3DUSAGE_DYNAMIC,D3DRTYPE_INDEXBUFFER,D3DFMT_INDEX16);
g_Log<<"Error for Checking whether index buffer works: "<<DXGetErrorString9(hrhr)<<endl;


I get D3DERR_NOTAVAILABLE, so I think my graphics card can't do drawindexedprimitive, which is probably why I am having trouble.

Share this post


Link to post
Share on other sites
If it turns out that it is indeed the case that your current development system does not support something as integral as IBs - I would strongly suggest that you upgrade - if you possibly can. Assuming your reason for coding graphics is a learning experience, you are severely stunting your possible experience in this way...

Share this post


Link to post
Share on other sites
When you call CheckDeviceFormat() you use D3DUSAGE_DYNAMIC as a usage flag - you don't actually create your index buffer with that dynamic flag so that shouldn't be a problem for you.

If your code actually failed to create the index buffer - which it would do if your graphics card didn't support them (which I find unlikely on the GF2, even an MX), then you'd know because of this line:

g_Log<<"SetupVertices() Create Index Buffer: "<<DXGetErrorString9(hr)<<endl;

Check your log to see if those calls actually succeed etc.

You might want to try and make another call to SetIndices() in your main loop. Maybe something is nullifying it without you noticing?

-Mezz

Share this post


Link to post
Share on other sites
Ok, my index buffer was created succesfully, and the indicies have been set successfully. This has how it has always been.

I added another:
g_pD3DDevice9->SetIndices(g_pIndexBuffer);

before the drawindexedprimitive line in the main loop. Now it works. It draws a texture to the screen. However if I try to draw another square from the same texture, the second square is not drawn.

To sort this out I'll need a few questions answered:
1)After calling drawindexedprimitive does the index buffer empty? How can I make it empty?

2)What advantage is there to having a dynamic index buffer?

3)Should I make my index buffer so that it can hold enough indexes for every vertex that is going to be in the vertex buffer?

4)If I have a vector list of vertices and a vector list of indicies and I sort the verticies, will the indicies be in the wrong order and point to the wrong vertices?

[Edited by - utilae on May 25, 2005 10:11:46 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by utilae
1)After calling drawindexedprimitive does the index buffer empty? How can I make it empty?

No, they're not emptied. An index buffer can't be emptied - it has a certain size. It always contains a number of indices. If you want to modify the indices, lock it and do so.

Quote:
2)What advantage is there to having a dynamic index buffer?

As with dynamic vertex buffers, they should be faster to use with frequent updates.

Quote:
3)Should I make my index buffer so that it can hold enough indexes for every vertex that is going to be in the vertex buffer?

Its range should cover the number of vertices. With 16 bit index buffers, you have 65536 vertices, [0, 65535] per DIP call. You can get around this using BaseVertexIndex. With BaseVertexIndex set to 4000, for example, you can now access [4000, 65935] in a single call.

Quote:
4)If I have a vector list of vertices and a vector list of indicies and I sort the verticies, will the indicies be in the wrong order and point to the wrong vertices?

Yes.

Share this post


Link to post
Share on other sites
Quote:
Original post by Coder
No, they're not emptied. An index buffer can't be emptied - it has a certain size. It always contains a number of indices. If you want to modify the indices, lock it and do so.

Hmmmm, I guess I'll have to empty it somehow, by overwriting it with new index data. How would I use memset to clear the index buffer, do I fill it with zeroes or some other character?

Quote:
Original post by Coder
Quote:
Original post by utilae
4)If I have a vector list of vertices and a vector list of indicies and I sort the verticies, will the indicies be in the wrong order and point to the wrong vertices?

Yes.

This is a big problem then. I wonder how I can make the indicies get sorted the same as the vertices. See if I sort the vertices by z value, indicies don't have a z value to sort by. I guess I can make a struct that contains the index and a z value, then sort the list of structs and then fill another list (of shorts) with the indicies (now sorted) and then memcpy the sorted indicies over the existing data in the index buffer.

Share this post


Link to post
Share on other sites
Quote:
Original post by utilae
Hmmmm, I guess I'll have to empty it somehow, by overwriting it with new index data. How would I use memset to clear the index buffer, do I fill it with zeroes or some other character?

You don't need memset. Lock the index buffer, overwrite the old data with the new index data, and unlock it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Coder
This is a big problem then. I wonder how I can make the indicies get sorted the same as the vertices. See if I sort the vertices by z value, indicies don't have a z value to sort by. I guess I can make a struct that contains the index and a z value, then sort the list of structs and then fill another list (of shorts) with the indicies (now sorted) and then memcpy the sorted indicies over the existing data in the index buffer.

This won't work. Consider the following vertices:
<0, 0, 20>
<0, 0, 2.5>
<0, 0, 15>

And the indices: 0, 1, 2

If you sort vertices by Z, and the indices by the Z of their indexed vertices you'd get:
<0, 0, 2.5>
<0, 0, 15>
<0, 0, 20>

Indices: 1, 2, 0

Which is not what you want. You want them to be "2, 0, 1", to preserve the winding (clockwise or anti-clockwise).

EDIT: Why do you want to z-sort the vertices, anyway? It makes sense to z-sort triangles/faces, but not vertices. Unless you're doing point sprites, but then you don't need index buffers for point sprites.

[Edited by - Coder on May 26, 2005 9:33:21 AM]

Share this post


Link to post
Share on other sites
Quote:

You don't need memset. Lock the index buffer, overwrite the old data with the new index data, and unlock it.

Like this:

//fill index buffer
void *vb_indicies;
g_pIndexBuffer->Lock(0,0,&vb_indicies,0);
//lstIndexList is a vector list of WORDS
memcpy(vb_indicies,&(m_lstIndexList[0]),m_lstIndexList.size()*sizeof(WORD));
g_pIndexBuffer->Unlock();


Would that overwrite the index buffer?

Quote:
Why do you want to z-sort the vertices, anyway?

Currently all vertices are in a vector list. I sort them by z value so that things closer to 0 are in the front, etc (this is a 2d app) then I fill the vertex buffer with the sorted vertices.

Share this post


Link to post
Share on other sites
But you don't need to sort the vertices like that even if your logic is sound, becuase with indexing, it's the indices which will do the sorting. So leave the vertices, and then index themv in a way to draw triangles in Z-order if you must. Although I can't see whay you can't z-buffer...

Share this post


Link to post
Share on other sites

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