Skip to content

Customizing SpriteBatch

Cole Campbell edited this page Mar 3, 2018 · 2 revisions

Ultraviolet's default sprite batching class, SpriteBatch, is written to satisfy common use cases. However, it is sometimes necessary to draw sprites in a non-standard way, for example using a different vertex format. Ultraviolet exposes the SpriteBatchBase class to make it easier for applications to implement modified sprite batching logic without having to re-implement it entirely from scratch.

The SpriteBatchBase Class

Ultraviolet's SpriteBatch class is actually just an implementation of the abstract SpriteBatchBase class, which contains all of the common code necessary to draw a batch of 2D sprites.

SpriteBatchBase has two generic parameters:

  • VertexType specifies the type of vertex used to represent the sprite geometry. This can be any type which implements IVertexType; the SpriteBatch class sets this to VertexPositionColorTexture.
  • SpriteData is an arbitrary structure associated with each sprite instance. Because the SpriteBatch class does not require per-instance data, it sets this to a placeholder type called SpriteBatchData which has no fields. All of the Draw*() methods on SpriteBatchBase allow you to specify an instance of this type to associate with the sprites that are added to the batch.

To implement SpriteBatchBase, derived classes must implement the GenerateVertices() method. This method takes the sprite metadata lists which are produced by the batch's Draw*() methods and converts them into vertices which can be rendered by the graphics device. To assist in this process, SpriteBatchBase exposes a number of protected helper methods which perform tasks which may be broadly useful across different custom implementations. These methods are:

  • CalculateUV()

    Calculates and caches the inverse of a texture's width and height. The result of this operation is used by CalculateTextureCoordinates().

  • CalculateSinAndCos()

    Calculates and caches the sine and cosine of a specified angle. The result of this operation is used by CalculatePosition().

  • CalculateRelativeOrigin()

    Calculates and caches the relative point of origin of a specified sprite. The result of this operation is used by CalculatePosition().

  • CalculatePosition()

    Calculates the three-dimensional position of a specified sprite vertex.

  • CalculateTextureCoordinates()

    Calculates the texture coordinates of a specified sprite vertex.

Example Implementation

At time of writing, the built-in SpriteBatch class implements GenerateVertices() as follows:

protected override unsafe void GenerateVertices(Texture2D texture, SpriteHeader[] sprites,
    VertexPositionColorTexture[] vertices, SpriteBatchData[] data, Int32 offset, Int32 count)
{
    CalculateUV(texture);

    fixed (SpriteHeader* pSprites1 = &sprites[offset])
    fixed (SpriteBatchData* pData1 = &data[offset])
    fixed (VertexPositionColorTexture* pVertices1 = &vertices[0])
    {
        var pSprites = pSprites1;
        var pData = pData1;
        var pVertices = pVertices1;

        for (int i = 0; i < count; i++)
        {
            CalculateSinAndCos(pSprites->Rotation);
            CalculateRelativeOrigin(pSprites);

            for (int v = 0; v < 4; v++)
            {
                CalculatePosition(pSprites, v, ref pVertices->Position);
                CalculateTextureCoordinates(pSprites, v, ref pVertices->TextureCoordinate);

                pVertices->Color = pSprites->Color;
                pVertices++;
            }

            pSprites++;
            pData++;
        }
    }
}
Clone this wiki locally