Problem coding own SpriteBatchRenderer class

Started by
2 comments, last by CdrTomalak 11 years, 2 months ago

Hi,

As an exercise I have put togther a really basic SpriteBatchRenderer class, but what I've found is that far from improving performance when rendering, I have actually gone backwards. Oh no!

I am basing it on the following principles:

Constructor(Direct3D11.Device graphicsIn, Direct3D11.DeviceContext contextIn):

- Create empty indices and vertices data streams

- Create Index Buffer

- Set standard texture positions (I'm drawing simple textures for now on all sprites)

- Create Vertex Buffer

- Create otho matrix

- Create an array of textures for each sprite

Begin()

- Rewind data stream positions to 0

Add(vector3[] positionIn, string texturePath)

- Transform vectors passed in

- Write vectors to vertices data stream

- Write indices array to indices data stream

- Store texture for this sprite

- noOfSprites++;

End()

- Rewind data stream positions to 0

Draw()

- Set index buffer binding

- Set vertex buffer binding

- Draw each sprite in sprite array using corresponding texture in texture array

ResetSpriteCount()

- noOfSprites = 0;

Dispose()

- Does nothing at present

When I use this class, calling Begin(), a series of Add() calls, then End(), Draw(), and then ResetSpriteCount(), nothing appears at all. I've debugged this to see if even one frame is drawn, and it is not.

As an experiement I created another version of the SpriteBatchRenderer() class, which doesn't create the index or vertex buffers in the Constructor. Instead it creates them, and sets the bindings, in the End() method. This WORKS, but is apallingly slow, as each frame new vertex buffers are created - which I think is what is slowing things down.

What I am trying to do is just create the index and vertex data streams ONCE, and the same for the index and vertex buffers, as I thought that it is the declaration of these structures that causes a performance hit. I want to work with the same vertex buffer for the entire lifetime of the game.

Clearly I'm doing something very wrong indeed.

Advertisement

Could you post some of the actual code, or describe in some more detail the specifics of how you're setting the contents of your vertex/index buffers?

No probbs. Attached are two zip files.

6a is the version which results in everything displaying, but being incredibly slow.

8a is the version which seems look correct, but results in nothing appearing at all.

The calling function from my game class is:


		// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		// Method DrawGameBoard_AddToBatch
		// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		public void DrawGameBoard_AddToBatch()
		{
			// Method which will add to the SpriteBatchRenderer all board tile for which drawing is applicable
			// i.e. we don't need to draw blank tiles.
			
			
			// --------------------------------------------------------------------------------------------------------------
			// Debug
			// -------------------------
			bool debug = true;
			string debugFileName = null;
			
			if(debug)
			{
				// Build timestamp string                                           
				DateTime currentDateTime = DateTime.Now;
				string timeStampString = currentDateTime.ToString("ddMMyyyy_HHmmss");
				
				// Build filename, concat timestamp and .txt extension.
				debugFileName = "D:\\Programming\\PacmanLogs\\DrawGameBoard_AddToBatch"+timeStampString+".txt";
				
				// Create filestream and pass this to a stream writer, setting a nice big buffer.
				using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
				{
					// Write to the file:
					DrawGameBoard_AddToBatch.WriteLine(DateTime.Now);
					DrawGameBoard_AddToBatch.WriteLine("timeStampString = {0}",timeStampString);
					DrawGameBoard_AddToBatch.WriteLine("DrawGameBoard_AddToBatch()...");
					DrawGameBoard_AddToBatch.WriteLine("Rows(x) = [{0}]",gameBoard.getRows());
					DrawGameBoard_AddToBatch.WriteLine("Columns(y) = [{0}]",gameBoard.getColumns());
					
				}
			}
			// ----------------------------------------------------------------------------------------------------------------
			
			string textureString = null;
		
			// BEGIN -----------------------------------------------------------------------------------------------------
			spriteBatchRenderer.Begin();		
		
			// Now loop through all cells and set texture paths.
			for(int x=0;x<gameBoard.getColumns();x++)
			{
				for(int y=0;y<gameBoard.getRows();y++)
				{
				
					if(debug)
					{
						using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
						{
							DrawGameBoard_AddToBatch.WriteLine("x = [{0}], y = [{1}]",x,y);
						}
					}
						
					switch(gameBoard.whatIsHere(new Vector2(x,y)))
					{
						case "p":
							// Normal Pill
							if(debug)
							{
								using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
								{
									DrawGameBoard_AddToBatch.WriteLine(">>> Normal Pill <<<");
									DrawGameBoard_AddToBatch.WriteLine("Vectors we would add are:");
									
									// Get the vectors
									Vector3[] tempVectors = new Vector3[4];
									tempVectors = gameBoard.getPreTransformedSpriteVectors(x,y);
									
									for(int a=0;a<4;a++)
									{
										DrawGameBoard_AddToBatch.WriteLine("tempVectors[{0}] = [{1}]",a,tempVectors[a]);
									}
								}
							}
							
							// Add to Batch
							textureString = "D:\\Programming\\GFX\\PNG\\Pills\\pill20x20_B.PNG";
							spriteBatchRenderer.Add(gameBoard.getPreTransformedSpriteVectors(x,y),textureString);
							
							break;
						case "W":
							// Wall
							if(debug)
							{
								using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
								{
									DrawGameBoard_AddToBatch.WriteLine(">>> Wall <<<");
									DrawGameBoard_AddToBatch.WriteLine("Vectors we would add are:");
									
									// Get the vectors
									Vector3[] tempVectors = new Vector3[4];
									tempVectors = gameBoard.getPreTransformedSpriteVectors(x,y);
									
									for(int a=0;a<4;a++)
									{
										DrawGameBoard_AddToBatch.WriteLine("tempVectors[{0}] = [{1}]",a,tempVectors[a]);
									}
								}
							}

							// Add to Batch
							textureString = "D:\\Programming\\GFX\\PNG\\GameBoard\\blueblock20x20.PNG";
							spriteBatchRenderer.Add(gameBoard.getPreTransformedSpriteVectors(x,y),textureString);							
							
							break;
						case "P":
							// Power Pill
							if(debug)
							{
								using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
								{
									DrawGameBoard_AddToBatch.WriteLine(">>> Power Pill <<<");
									DrawGameBoard_AddToBatch.WriteLine("Vectors we would add are:");
									
									// Get the vectors
									Vector3[] tempVectors = new Vector3[4];
									tempVectors = gameBoard.getPreTransformedSpriteVectors(x,y);
									
									for(int a=0;a<4;a++)
									{
										DrawGameBoard_AddToBatch.WriteLine("tempVectors[{0}] = [{1}]",a,tempVectors[a]);
									}
								}
							}
							
							
							// Add to Batch
							textureString = "D:\\Programming\\GFX\\PNG\\Pills\\powerPill20x20.PNG";
							spriteBatchRenderer.Add(gameBoard.getPreTransformedSpriteVectors(x,y),textureString);	
							
							break;
						case "_":
							// Space
							if(debug)
							{
								using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
								{
									DrawGameBoard_AddToBatch.WriteLine(">>> Space <<<");
								}
							}
							break;
					} // switch
				} // for y
			} // for x
			
			if(debug)
			{
				using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
				{
					DrawGameBoard_AddToBatch.WriteLine("...about to call End()...");
				}
			}
				
			// END (draw after this!)
			spriteBatchRenderer.End();
				
			//spriteBatchRenderer.TestHarness_3();
			
			if(debug)
			{
				using (StreamWriter DrawGameBoard_AddToBatch = new StreamWriter(debugFileName, true, System.Text.Encoding.Default, 65535))
				{
					DrawGameBoard_AddToBatch.WriteLine("End of DrawGameBoard_AddToBatch");
				}
			}
			
			// Report just before calling draw (in cases where nothing draws we need to know why!)
			//spriteBatchRenderer.ReportSpriteBatchRenderer("JUST BEFORE DRAW CALL");
			
			// Now draw the board.
			spriteBatchRenderer.Draw();
			
			// And dispose
			spriteBatchRenderer.ResetSpriteCount();
			spriteBatchRenderer.Dispose();
			
		}
		// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		// >>>>>>>>>> END Method DrawGameBoard_AddToBatch >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
		// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Sorry if this is all a bit of a mess! 8|

The DrawGameBoard_AddToBatch() function simply passes through an array to draw each tile of a game board. For each tile I add a call to the SpriteBatchRenderer object.

I thought it would be interesting to give this a crack myself. Would be great to nail it finally.

I should add that my previous method was to have my entity objects each having their own dedicated vertex and index buffer. Every time an entity would move, I would simply rewrite the vertices data stream, and create a new vertex buffer. Each tile was also an entity, so for a 10x10 game board this was fine. Scaling up things went really slow so then I decided to try and write my own SpriteBatch class... but it's actually worse as is! 8o

This topic is closed to new replies.

Advertisement