Sign in to follow this  

Problem drawing a quad

This topic is 2845 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

Hello everyone, I'm writing a tile engine for a map editor and I now I want to draw a quad on top of my textures tiles to mark which ones are selected. The others tiles (the textured ones) work just fine but when trying to draw my translucent "selection" quad it becomes gigantic and takes the whole window (and beyond). Now, if I use the same vertex buffer that I used to draw my texture tiles, it works just fine which lead me to believe there is a problem in the way I create my other quads and/or vertex buffer but I can't find anything wrong with it... the code is actually pretty much the same for my textured tiles and that work fine.
// Creating the vertex buffer
if (FAILED(m_d3dDevice->CreateVertexBuffer(sizeof(aHighlightVertex) * m_tileCount * 4, 0, HIGHLIGHTVERTEX_FORMAT, D3DPOOL_MANAGED, &m_highlightsVertexBuffer, 0)))
[...]


// Initialization code
void aMapRender::_UpdateHighlights(aHighlightTile *highlights, unsigned int highlightCount)
{
	m_highlightTriangleCount = highlightCount * 2;
	aHighlightVertex *highlightVertices = new aHighlightVertex[highlightCount * 4];

	// Create the highlight tile vertices
	for (unsigned int i = 0; i < highlightCount; ++i)
	{
		aHighlightVertex vertices[] = 
		{
			{32.0f, 0.0f,/*highlights[i].x * m_tileSize +  m_tileSize,	highlights[i].y * m_tileSize,			*/	0.5f,	1.0f,	highlights[i].color}, // Top Right
			{32.0f, 32.0f,/*highlights[i].x * m_tileSize +  m_tileSize,	highlights[i].y * m_tileSize + m_tileSize,*/	0.5f,	1.0f,	highlights[i].color}, // Bottom Right
			{0.0f, 32.0f,/*highlights[i].x * m_tileSize,					highlights[i].y * m_tileSize + m_tileSize,*/	0.5f,	1.0f,	highlights[i].color}, // Bottom Left		
			{0.0f, 0.0f,/*highlights[i].x * m_tileSize,					highlights[i].y * m_tileSize,	*/			0.5f,	1.0f,	highlights[i].color}, // Top Left
		};

		memcpy(&highlightVertices[i * 4], test, sizeof(aHighlightVertex) * 4);
	}

	// Copy this to our vertex buffer
	void *ptr;
	m_highlightsVertexBuffer->Lock(0, 0, &ptr, 0);
	memcpy(ptr, highlightVertices, sizeof(aHighlightVertex) * highlightCount * 4);
	m_highlightsVertexBuffer->Unlock();

	delete[] highlightVertices;
}




// And the drawing code
[...]
if (m_highlightTriangleCount)
{
	m_d3dDevice->SetFVF(HIGHLIGHTVERTEX_FORMAT);
	m_d3dDevice->SetStreamSource(0, m_highlightsVertexBuffer, 0, sizeof(aHighlightTile));
	m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, m_highlightTriangleCount);
}
[...]


Does anyone know what I'm doing wrong? Thanks, -Roxanne

Share this post


Link to post
Share on other sites
Quote:
memcpy(&highlightVertices[i * 4], test, sizeof(aHighlightVertex) * 4);
What's 'test'? Never mind, why are you allocating an array on the heap, writing to it, then copying the array to the vertex buffer? Why not write directly to the vertex buffer? Why is the vertex buffer created without the D3DUSAGE_WRITEONLY flag? You don't seem to be reading back from it.

Quote:
m_d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, m_highlightTriangleCount);

D3DPT_TRIANGLEFAN? To draw a bunch of quads? Use triangle lists instead to draw all the quads in one call. Also, it seems to me all quads have the same color, so why are you storing per-vertex color information unnecessarily?

Share this post


Link to post
Share on other sites
Oups, nevermind that 'test' it should be 'vertices'... I was trying something and forgot to change it back before copying my code here. You are also right about the D3DUSAGE_WRITEONLY flag, I'm not reading from it, I'll add it.

However, aMapRender::_UpdateHighlights is called on every frame update and I read that if you need to lock a vertex buffer during a frame update it was best to leave it lock for the least amount of time as this could degrade performance. Do you think this is unnecessary? I'll try both ways and see what work best. Also, my quads may not have all the same color and are not contiguous so I can't draw them in one call.

Thanks

Share this post


Link to post
Share on other sites
You should draw them in one call. If each tile is 32 pixels in size, and the screen resolution is, say, no more than 1600x1600, then the maximum number of quads you'll have to draw each frame is (1600/32) ^ 2, which is 2500 quads. You certainly don't want to draw each quad in its own draw call, or you'll suffer poor performance for sure. That's why you should use one draw call and a triangle list instead of fan. Them being contiguous has nothing to do with the number of draw calls, but it forces you to use a triangle list instead of strips or fans.

As for reducing the locking time, the advice you spoke of encourages against locking a vertex buffer and then going off performing lengthy computations, but in this case, you aren't doing that. The stuff you are doing here (computing vertex locations) is relatively trivial, so write directly to the VB. Hope this helps.

Share this post


Link to post
Share on other sites
Alright, thanks for the advice I changed the way i create my vertices. However, I don't understand how I can draw non-contiguous quads with only one call using a triangles list. The way I understand it is that all the triangles will be drawn connected to each other. Am I correct? I'll mess up a bit with that and try to understand more how it works. But I still don't understand why it was drawing giant triangles on screen (now there is simply nothing appearing). There must be something wrong with how I initialize my quads (other than the fact that it is not the best possible way to do it) because if i use the same vertex buffer I use to draw my tiles it works fine. But I don't see what wrong... :( Here's a screenshot of my the faulty vertex buffer right before I unlock it:

http://i924.photobucket.com/albums/ad85/roxypinky/quads.png

Any idea?

Thanks a lot for the help :)

Share this post


Link to post
Share on other sites
Use D3DPT_TRIANGLELIST, not FAN. You are then specifying sets of three vertices defining non-connected triangles. If this is producing too many duplicate indices, solve with an index buffer.

The problems you describe with the wildly wrong triangles sounds like the vertex data being misinterpreted to me:


m_d3dDevice->SetStreamSource(0, m_highlightsVertexBuffer, 0, sizeof(aHighlightTile));


Should that not be sizeof(aHighlightVertex)?

Quote:

I read that if you need to lock a vertex buffer during a frame update it was best to leave it lock for the least amount of time as this could degrade performance.


It is more the time taken to lock and unlock the buffer that can degrade performance than the time it is locked. You should avoid too many lock and unlocks per frame, not try to minimise the time it is locked.

Vertex memory may reside on the graphics card. When you unlock a locked buffer, it can be as bad as having to copy all the buffer data from normal memory to graphics memory.

Since the most probable bottleneck is transfer of data from main board to graphics card, you should batch as much as possible over to the card. This also allows you to continue processing on the CPU while the GPU is rendering the provided vertex data.

Share this post


Link to post
Share on other sites
omg lol, you're totally right. Thanks a lot. And I'll switch to D3DPT_TRIANGLELIST... dunno why when Amr0 first suggested this I had D3DPT_TRIANGLESTRIP in mind hence why I was confused as to how I was gonna draw unconnected triangles with that. Anyway thanks a lot you 2, you have been of great help :)

Share this post


Link to post
Share on other sites
The way I do quads to reduce traffic across to the card is to create a big index buffer that is set up like this:


QuadIndices.Acquire(*Gr,1800*2,D3DUSAGE_WRITEONLY,D3DPOOL_DEFAULT);

WORD *W=QuadIndices.Lock(D3DLOCK_DISCARD);

WORD O=0;
for(WORD N=0;N<300*2;++N)
{
*W++=O; *W++=O+1; *W++=O+3; *W++=O+1; *W++=O+2; *W++=O+3;
O+=4;
}

QuadIndices.Unlock();


I'm using my own class wrapper for an index buffer but it is pretty thin so should translate. The important bit is more the values I'm putting in.

If you haven't used index buffers before, there is loads of info in the docs. Just remember to set the index buffer onto the stream and call DrawIndexedPrimitive instead of DrawPrimitive.

I can then just put four vertices into the vertex buffer for each quad, in clockwise order starting from top left.

Since the index buffer does not need to be unlocked, it can sit in memory accessible to the GPU without being moved about and it reduces the vertices required to move over to the card from six to four per quad - a big saving if you are batching a large number of quads per frame.

Obviously you need to keep in mind that you can't put more quads into the vertex buffer than the index buffer can accomodate. I size the index buffer based on the size of the vertex buffer I use for sprite rendering and have the vertex buffer flush to screen when it runs out of space.

Share this post


Link to post
Share on other sites

This topic is 2845 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