Creating a simple 2d engine (C++), best way to create an Sprite class?

Started by
2 comments, last by Joyal 11 years, 1 month ago

Since MS announced that they are not give more support to XNA , for me was an opportunity to start to learn DirectX , so i wanted to learn DX11,

i was following this tutorials

http://www.rastertek.com/tutdx11.html

i want to build a simple 2D engine while im learning with basic thing,like render an sprite based on a spritesheet, ,animate it, scale, rotation, flip image

I started creating some simple basic structure,

- Engine Class, this hold the initialization of the Window basically

- RenderManager class, this hold all the DX stuff, initialize it, create the swapchain, store the device , etc

So now my next step is create the Sprite class , i wanted to create an method called "Quad2D" inside my RenderManager, so i can use it on my render method in my sprite class


//This is not actual code, is just oh i want to approach this
class Sprite{

public void Render(RenderManager *rm){
  
    rm->Quad2D(Texture,Position,Width,Height);

}
}

i have some experience with OpenGL and Directx9 , it was easy to approach this, i just need to create an Array with the vertex, send to the VertexBuffer, bind the Texture, and done,

but because now DX10 and DX11 not used fixed pipeline, and you need create this with more advanced stuff (Shaders),

i stopped in here http://www.rastertek.com/dx11tut11.html , i can see how to render the image and everything, but i was thinking, do i need to create an separate Class just to render a Quad? if so, this is going to compile the shader everytime is used?, well one solution maybe is just declare an static atribute for the ps and vs to share the same compile shader

so i want to hear your suggestion, how do you manage your Sprite class?

if it necessary, i can attach my source code, but it doesnt has too much, just open a window

Note: i want to know how to do it in DX11, please dont reply, (used DX9,OpenGL,DX10, etc..)

Advertisement

Create separate classes for Shaders, Vertex Buffers etc.

For example i have the following class for vertex shader:


class VertexShaderDX11
	{
	protected:

		ID3D11VertexShader*	m_pShader;
		InputAssemblerStateDX11*	m_pState;

	public:
		VertexShaderDX11()  { m_pState = new InputAssemblerStateDX11(); }
		~VertexShaderDX11() {	SAFE_RELEASE(m_pShader);
								SAFE_DELETE(m_pState); }

		ABOOL Create(BlobDX11 & shaderbuffer, INPUT_LAYOUT* layout, AUINT8 num,
										 AUINT16 topology);
		AVOID Set() const;
	};

Note that it has pointer to the InputAssembler structure (it stores information about Input Assembler stage as for vertex shader you have to have right input topology).

In your sprite class you can reference shader for rendering and bind it to the pipeline before you render your sprite. Don't recompile shader all the time! Compile it one time and then just have a pointer to an object of your shader class which stores compiled shader. Multiple sprites can use single shader for rendering just having pointer to it.

I'm somewhat curious how your Quad2D method is handling things under the hood. Is it buffering the sprites and then drawing them in all one big draw call, sorting them by texture, or does each call set the texture, vertex buffers, IA Layout, shaders, etc? If it is the latter then it is likely to not be all that efficient. You may want to look into mimicking the way SpriteBatch in XNA handles things. You tell it to Begin() and then you do a number of Draw() calls. When you are finished you say End(), which draws all the sprites in one go. This approach is generally more efficient.

As for me, I store all my sprites as points in a dynamic vertex buffer and expand them to quads in the Geometry shader. This makes managing the vertex buffers on the C side much easier.

@DgekGD , i like your approach because i can use the same VS and PS in differents classes biggrin.png!

@Racoonacoon well right now i don`t have the implementation made of Quad2D on my current "Engine"(DX11), i wanted to ask before i do it because DX10-11 works different, but i do have my DX9 version ,


void RenderManager::DrawQuad2D (CTexture* texture, Vector2 position, int w, int h)
{

	// position = [0] 
	//
	//  [0]------[2]
	//   |        |
	//   |        |
	//   |        |
	//  [1]------[3]
	
	Vector2 coord_text[4];
	coord_text[0].x = 0.f;	coord_text[0].y = 0.f;
	coord_text[1].x = 0.f;	coord_text[1].y = 1.f;
	coord_text[2].x = 1.f;	coord_text[2].y = 0.f;
	coord_text[3].x = 1.f;	coord_text[3].y = 1.f;
			
	unsigned short indices[6]={0,2,1,1,2,3};
	SCREEN_TEXTURE_VERTEX v[4] =
	{
			{ (float)position.x,	(float)position.y,	0.f,1.f, coord_text[0].x,	coord_text[0].y} //(x,y) sup_esq.
		,	{ (float)position.x,	(float)position.y+h,	0.f,1.f, coord_text[1].x,	coord_text[1].y} //(x,y) inf_esq.
		, 	{ (float)position.x+w,	(float)position.y,	0.f,1.f, coord_text[2].x,	coord_text[2].y} //(x,y) sup_dr.
		,	{ (float)position.x+w,	(float)position.y+h,	0.f,1.f, coord_text[3].x,	coord_text[3].y} //(x,y) inf_dr.
	};

	m_pD3DDevice->SetFVF( SCREEN_TEXTURE_VERTEX::getFlags() );
	m_pD3DDevice->SetTexture(0, texture->GetD3DXTexture() );
	m_pD3DDevice->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST,0, 4, 2,indices,D3DFMT_INDEX16, v, sizeof( SCREEN_TEXTURE_VERTEX ) );
}

Well i based in your suggestion , i think i will do some sort of XNA's "SpriteBranch", and that class can be instantiated once, and be passed on the "Render" method, instead of the "RenderManager",

Thank for your greats advice

This topic is closed to new replies.

Advertisement