Skip to main content
GameDev.net gamedev.net
🔒 Locked

Sprite rendering optimization help

Started by DarkSaint May 11, 2004 at 3:49 PM 5 replies 700+ views
Original Post
DarkSaint
DarkSaint
Like many, I''m currently workin on a 2d tile engine game for one of my first games, although I''m having some issues with my sprite renderer. Currently I unlock the vertex buffer and copy in vertex data once for every sprite that''s on screen then render that data which I don''t really want to do since word on the street is it''s bad to unlock the vertex buffer many times in a program. What I want to do is create a verticie array that can vary in size depending on how many sprites are on the screen while only copying all the vertex data into the vertex buffer for all the sprites on screen at once instead of a sprite by sprite basis. After that I would render the vertex buffer with an offset depending on what sprite the renderer was on. The problem is I don''t know how I would go about creating an array that can vary in in elements. Does any one know how I could modify my current code to do what I want it to?
//-----------------------------------------------------------------------------

// Name: RenderSprites(void)

// Desc: Renders Sprites to the screen.

//-----------------------------------------------------------------------------

void RenderSprites (void)
{

	short SVertCurPosX[4];
	short SVertCurPosY[4];

// This group of statements runs through and renders sprites from the top of the screen to the bottom so sprites on lower tiles appear to be in front of sprites on higher tiles.

	for (int y = 0; y < ScreenTilesY; y++)
	{
		for (int i = 0; i < MapSprites; i++)
		{
			if ((sprite[i].MapLocX <= CamBndryPosiX) && (sprite[i].MapLocX >= CamBndryNegX) && (sprite[i].MapLocY <= CamBndryPosiY) && (sprite[i].MapLocY >= CamBndryNegY))
			{


				if (sprite[i].MapLocY == RenderLocY[y])
				{
					sprite[i].SprScrnLocY = ScreenLocY[y] + sprite[i].SprOffsetY;

					SVertCurPosY[0] = sprite[i].SprScrnLocY;
					SVertCurPosY[1] = sprite[i].SprScrnLocY + sprite[i].SprHeight;
					SVertCurPosY[2] = sprite[i].SprScrnLocY;
					SVertCurPosY[3] = sprite[i].SprScrnLocY + sprite[i].SprHeight;

					if (sprite[i].FramesInSequence[sprite[i].CurrentSequence] > 1)
					{
						AnimateSprites(i);
					}

				if (sprite[i].SprFrame < MaxCellsX)
					{
						sprite[i].SprLeftCell = ((1.0 / sprite[i].SprNumFrames) * sprite[i].SprFrame);
						sprite[i].SprRightCell = ((1.0 / sprite[i].SprNumFrames) * (sprite[i].SprFrame + 1));
						sprite[i].SprTopCell = 0;
						sprite[i].SprBottomCell = 1;
					}

				if (sprite[i].SprFrame >= MaxCellsX)
					{
						sprite[i].SprLeftCell = ((1.0 / MaxCellsX) * (sprite[i].SprFrame - MaxCellsX));
						sprite[i].SprRightCell = ((1.0 / MaxCellsX) * ((sprite[i].SprFrame + 1) - MaxCellsX));
					}

					for(int x = 0; x < ScreenTilesX; x++)
					{
						if (sprite[i].MapLocX == RenderLocX[x])
						{
							sprite[i].SprScrnLocX = ScreenLocX[x] + sprite[i].SprOffsetX;

							sprite[i].SprLeftBorder = sprite[i].SprScrnLocX - (sprite[i].SprWidth / 2);
							sprite[i].SprRightBorder = sprite[i].SprScrnLocX + (sprite[i].SprWidth / 2);

							SVertCurPosX[0] = sprite[i].SprLeftBorder;
							SVertCurPosX[1] = sprite[i].SprLeftBorder;
							SVertCurPosX[2] = sprite[i].SprRightBorder;
							SVertCurPosX[3] = sprite[i].SprRightBorder;

							vertices[0].position = D3DXVECTOR3 (SVertCurPosX[0], SVertCurPosY[0], 0.5f);
							vertices[0].normal = D3DXVECTOR3 (SVertCurPosX[0], SVertCurPosY[0], 1.0f);
							vertices[0].tu = sprite[i].SprLeftCell;
							vertices[0].tv = sprite[i].SprBottomCell;

							vertices[1].position = D3DXVECTOR3 (SVertCurPosX[1], SVertCurPosY[1], 0.5f);
							vertices[1].normal = D3DXVECTOR3 (SVertCurPosX[1], SVertCurPosY[1], 1.0f);
							vertices[1].tu = sprite[i].SprLeftCell;
							vertices[1].tv = sprite[i].SprTopCell;

							vertices[2].position = D3DXVECTOR3 (SVertCurPosX[2], SVertCurPosY[2], 0.5f);
							vertices[2].normal = D3DXVECTOR3 (SVertCurPosX[2], SVertCurPosY[2], 1.0f);
							vertices[2].tu = sprite[i].SprRightCell;
							vertices[2].tv = sprite[i].SprBottomCell;

							vertices[3].position = D3DXVECTOR3 (SVertCurPosX[3], SVertCurPosY[3], 0.5f);
							vertices[3].normal = D3DXVECTOR3 (SVertCurPosX[3], SVertCurPosY[3], 1.0f);
							vertices[3].tu = sprite[i].SprRightCell;
							vertices[3].tv = sprite[i].SprTopCell;

							g_pd3dDevice->SetTexture( 0, sprite[i].pSTexture );
							g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
							g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
							g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
							g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );

							void* pVertices;
							( g_pVB->Lock( 0, sizeof(vertices), (void**)&pVertices, 0 ) );
							memcpy( pVertices, vertices, sizeof(vertices) );
								g_pVB->Unlock();

							g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(VERTSTRUCT) );
							g_pd3dDevice->SetFVF( D3DFVF_VERTSTRUCT );
							g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

							
						}
					}
				}
			}
		}

	}
}
fatmatt81
fatmatt81
"I don''t know how I would go about creating an array that can vary in in elements"

Sounds like you need a linked list to me.
ouelletf
ouelletf
Make it bigger, fill it until its full. Then Draw. Fill it again, Draw....

I suggest you make it bigger than what you need for one frame.
Look at Lock(NOOVERWRITE) and Lock(DISCARD). for a DYNAMIC Buffer.

You should use IndexBuffer too, to share vertexes.

If you are in DX9b, you should look at ID3DXSprite too.
GroZZleR
GroZZleR
Basically whats been said, you make your buffer bigger and fill it until its full.

Its called a Vertex Cache, and heres a good article on them:
http://www.mvps.org/directx/articles/vcache.htm

If you use tilesets (instead of single textures), it becomes optimized even further.
Jiia
Jiia
You could use transforms to move your objects instead. And anytime you have textures that blit the entire image, why not use a single mesh to draw them all?

If your copying per sprite is efficient, you won't get a performance increase by copying all of them at once. The problem isn't "locking" the buffer, it's reading and copying data to it. To increase performance, reduce the amount of data transferred per frame. memcpy or a similar function will not increase your frame rate (unless you're doing something really dumb when you copy the data).

EDIT - By having a system memory version and doing all operations on them, then copying them to the video buffer when they change, you may increase performance. That would be because you don't have to "read" the buffer, only write to it.

[edited by - Jiia on May 12, 2004 5:27:52 AM]
The Frugal Gourmet
The Frugal Gourmet
This is the hottest thing to do right now with sprite engines, but frankly I think it''s a giant waste of time. I did it myself, and I experienced a little speed increase but spent many precious programming hours doing it.

My advice is to make big buffers for tiled backgrounds and particle systems, but for your average sprite objects I wouldn''t bother. In fact, the speed boost you''ll gain in these situations are more a result of limiting SetTexture() calls than anything else.
Co-creator of Star Bandits -- a graphical Science Fiction multiplayer online game, in the style of "Trade Wars'.
Dreddnafious Maelstrom
Dreddnafious Maelstrom
i''ll second the gourmet''s opinion, while i havent developed a 2d game i have developed a pretty complete DX GUI system, and tortured myself with trying to batch my geometry for a while. because your coordinated change per frame and you have alot of unique textures, its generally not worth it. so my advice, batch your render states, batch your textures, but dont sweat the small stuff. having said that, i realize its not the best code practice per se, but in reality it works out just fine.

Dredd
________________________________________

"To die with your sword still in its sheath is most regrettable" -- Miyomoto Musashi


"Let Us Now Try Liberty"-- Frederick Bastiat

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.