SpriteBatch
Implementation status: SpriteBatch is fully implemented and works on all four rendering backends: SDL_RENDERER, EASYGL, BGFX, and VULKAN. All Begin(), Draw(), and DrawString() overloads described in XNA 4.0 are present.
Overview
SpriteBatch is the primary 2D drawing class in the Microsoft::Xna::Framework::Graphics namespace. It collects 2D draw calls issued between a Begin()/End() pair and submits them to the GPU as a single batched draw, dramatically reducing API overhead compared to drawing each sprite individually.
The fundamental usage pattern is:
- Call
Begin()once to configure blend state, sort mode, and any optional transform. - Call
Draw()orDrawString()any number of times to queue sprites and text. - Call
End()to flush the batch and issue the GPU draw calls.
SpriteBatch is backend-agnostic. On SDL_RENDERER it maps draw calls directly to SDL3 renderer commands. On EASYGL, BGFX, and VULKAN it generates textured quads fed through the internal SpriteEffect with an orthographic projection covering the back-buffer dimensions.
Begin() overloads
All overloads open a batch. Parameters not supplied take their XNA 4.0 defaults. A second call to Begin() without a preceding End() is an error.
| Overload | Parameters |
|---|---|
Begin() |
No arguments — defaults to SpriteSortMode::Deferred, BlendState::AlphaBlend |
Begin(sortMode) |
SpriteSortMode sortMode |
Begin(sortMode, blendState) |
SpriteSortMode, BlendState |
Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState) |
Full render state — adds SamplerState, DepthStencilState, RasterizerState |
Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect) |
Full render state plus a custom Effect (replaces the built-in SpriteEffect) |
Begin(sortMode, blendState, samplerState, depthStencilState, rasterizerState, effect, transformMatrix) |
Full render state, custom effect, and a Matrix applied to every sprite position (camera / zoom transform) |
SpriteSortMode
Controls the order in which batched sprites are drawn relative to each other. Choose a mode that balances visual correctness against throughput for your use case.
| Value | Behaviour |
|---|---|
Deferred |
Default. Sprites are queued and drawn in submission order when End() is called. Best throughput. |
Immediate |
Each Draw() call issues a GPU draw immediately. Required when mixing SpriteBatch with raw GraphicsDevice state changes mid-batch. |
Texture |
Sprites are sorted by texture before draw, minimising texture-switch overhead. Submission order is not preserved. |
BackToFront |
Sprites are sorted by descending layerDepth (furthest first). Use with alpha-blended sprites to avoid transparency artefacts. |
FrontToBack |
Sprites are sorted by ascending layerDepth (nearest first). Useful for depth-buffer early-out on opaque sprites. |
Draw() overloads
All Draw() overloads accept a Texture2D as the first argument. Omitted optional parameters take XNA 4.0 defaults (rotation = 0, origin = Vector2::Zero, scale = 1, effects = SpriteEffects::None, layerDepth = 0).
| Signature | Notes |
|---|---|
Draw(texture, position, color) |
position is a Vector2. Draws the full texture at native size. |
Draw(texture, position, sourceRect, color) |
Clips the source to sourceRect (nullable Rectangle). Draws at native sub-region size. |
Draw(texture, position, sourceRect, color, rotation, origin, scale, effects, layerDepth) |
Full Vector2-position overload. scale may be a float (uniform) or Vector2 (non-uniform). |
Draw(texture, destinationRect, color) |
destinationRect is a Rectangle. Stretches the full texture to fill the rectangle. |
Draw(texture, destinationRect, sourceRect, color) |
Source and destination rectangles — stretches the sub-region into the destination. |
Draw(texture, destinationRect, sourceRect, color, rotation, origin, effects, layerDepth) |
Full Rectangle-destination overload with rotation and flip. |
DrawString() overloads
DrawString() renders text using a SpriteFont loaded through the ContentManager. In CNA the text parameter accepts either a standard std::string or the String type alias provided by the sharp-runtime layer.
| Signature | Notes |
|---|---|
DrawString(spriteFont, text, position, color) |
Draws text at position (Vector2) with the given tint color. No rotation or scaling. |
DrawString(spriteFont, text, position, color, rotation, origin, scale, effects, layerDepth) |
Full overload matching the XNA 4.0 signature. scale may be a uniform float. |
SpriteEffects
The SpriteEffects enum controls axis-aligned flipping of a sprite around its origin. Values can be combined with the bitwise OR operator.
| Value | Effect |
|---|---|
SpriteEffects::None |
No flipping. Default. |
SpriteEffects::FlipHorizontally |
Mirrors the sprite left-to-right. |
SpriteEffects::FlipVertically |
Mirrors the sprite top-to-bottom. |
BlendState presets
CNA ships the same four BlendState static presets as XNA 4.0. Pass one to Begin() to control how each sprite's colour is composited over existing framebuffer contents.
| Preset | Blend equation | Typical use |
|---|---|---|
BlendState::AlphaBlend |
Pre-multiplied alpha: src + dst × (1 − src.a) |
Default for most 2D UIs and sprites |
BlendState::Additive |
src + dst (ignores alpha) |
Particle effects, glows, laser beams |
BlendState::NonPremultiplied |
Straight alpha: src × src.a + dst × (1 − src.a) |
Textures stored with un-premultiplied alpha |
BlendState::Opaque |
No blending — replaces destination entirely | Fully opaque backgrounds, render targets |
Code examples
1. Basic 2D sprite draw
The minimal Begin / Draw / End cycle. spriteBatch is typically stored as a member of your Game subclass and created once in LoadContent().
// In LoadContent():
spriteBatch = std::make_shared<SpriteBatch>(GraphicsDevice);
playerTexture = Content.Load<Texture2D>("player");
// In Draw():
spriteBatch->Begin();
spriteBatch->Draw(playerTexture, Vector2(100.0f, 200.0f), Color::White);
spriteBatch->End();
2. Draw with rotation and scale
Use the full Vector2-position overload to rotate a sprite around its centre and scale it uniformly.
float rotation = MathHelper::ToRadians(45.0f); // 45 degrees
Vector2 origin(playerTexture->Width() / 2.0f,
playerTexture->Height() / 2.0f); // centre pivot
float scale = 2.0f;
spriteBatch->Begin();
spriteBatch->Draw(
playerTexture,
Vector2(400.0f, 300.0f), // screen position
std::nullopt, // sourceRect: full texture
Color::White, // tint
rotation, // rotation in radians
origin, // pivot point
scale, // uniform scale
SpriteEffects::None,
0.0f); // layerDepth
spriteBatch->End();
3. DrawString example
Load a SpriteFont via ContentManager, then call DrawString() to render text.
// In LoadContent():
auto font = Content.Load<SpriteFont>("fonts/Arial20");
// In Draw():
spriteBatch->Begin();
spriteBatch->DrawString(
font,
"Score: " + std::to_string(score),
Vector2(16.0f, 16.0f),
Color::Yellow);
spriteBatch->End();
4. Additive blending for particles
Switch to BlendState::Additive so particle sprites brighten the scene rather than covering it.
spriteBatch->Begin(SpriteSortMode::Deferred, BlendState::Additive);
for (auto& particle : particles) {
spriteBatch->Draw(
sparkTexture,
particle.Position,
std::nullopt,
Color(255, 200, 100, particle.Alpha),
particle.Rotation,
sparkOrigin,
particle.Scale,
SpriteEffects::None,
0.0f);
}
spriteBatch->End();
5. Transform matrix camera (2D scrolling)
Pass a Matrix to Begin() to apply a global transform to every sprite in the batch. This is the standard XNA pattern for 2D camera scroll and zoom.
// Build a camera matrix: translate by -cameraPosition, scale by zoom
Matrix cameraTransform =
Matrix::CreateTranslation(-cameraPosition.X, -cameraPosition.Y, 0.0f) *
Matrix::CreateScale(zoom, zoom, 1.0f) *
Matrix::CreateTranslation(
GraphicsDevice->Viewport().Width / 2.0f,
GraphicsDevice->Viewport().Height / 2.0f,
0.0f);
spriteBatch->Begin(
SpriteSortMode::Deferred,
BlendState::AlphaBlend,
nullptr, // SamplerState (default)
nullptr, // DepthStencilState (default)
nullptr, // RasterizerState (default)
nullptr, // Effect (built-in SpriteEffect)
cameraTransform); // <-- camera matrix applied to all draws
// Draw world tiles, characters, etc. in world-space coordinates
for (auto& tile : world.VisibleTiles(cameraPosition)) {
spriteBatch->Draw(tileSheet, tile.WorldPosition, tile.SourceRect, Color::White);
}
spriteBatch->End();
Never call Draw() or DrawString() outside a Begin() – End() pair. Doing so throws an InvalidOperationException at runtime, matching XNA 4.0 behaviour. Similarly, nested Begin() calls without a matching End() are an error.