Tutorial 08: Loading and Drawing Textures

CNA Tutorial Series  ·  Beginner

Texture2D Overview

Texture2D represents a 2D image stored on the GPU. In CNA you load image files (PNG, JPEG, BMP) and use SpriteBatch::Draw() to render them. Key properties:

#include "Microsoft/Xna/Framework/Graphics/Texture2D.hpp"

// After loading:
int w = texture->getWidth();   // width in pixels
int h = texture->getHeight();  // height in pixels

Texture2D is owned by your game class via std::unique_ptr<Texture2D>. The GPU memory is freed when the unique_ptr is destroyed.

Loading Textures

CNA supports two loading paths:

Option A: Direct file load (simplest)

Pass a file path directly to the Texture2D constructor:

void MyGame::LoadContent() {
    spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());

    // Load a PNG from the assets/ directory
    // Path is relative to the executable
    player_ = std::make_unique<Texture2D>("assets/player.png",
                                           getGraphicsDeviceProperty());

    background_ = std::make_unique<Texture2D>("assets/background.png",
                                               getGraphicsDeviceProperty());
}

Option B: ContentManager (XNA-style)

The Content member (of type ContentManager) provides the XNA-style asset pipeline. It caches assets and resolves paths relative to a root directory:

void MyGame::Initialize() {
    Game::Initialize();
    // Set the root directory for content
    Content.setRootDirectory("assets");
}

void MyGame::LoadContent() {
    spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());

    // Loads assets/player.png (extension added automatically if texture.json found)
    playerTex_ = Content.Load<Texture2D>("player");

    // Loads assets/ui/button.png
    buttonTex_ = Content.Load<Texture2D>("ui/button");
}

The ContentManager path strips the extension and expects either a raw image file or a texture.json descriptor alongside the image.

The texture.json Descriptor

CNA's content pipeline supports JSON descriptors alongside image files. A player.json next to player.png can specify filtering and wrapping:

{
  "file": "player.png",
  "filter": "Linear",
  "wrap": "Clamp"
}

Available filter values: "Point" (nearest-neighbour, pixel art look), "Linear" (smooth, default), "Anisotropic".

Available wrap values: "Wrap" (tile), "Clamp" (clamp to edge), "Mirror".

If no descriptor is present, CNA loads the PNG directly with linear filtering and clamp wrap mode.

Draw Overloads

SpriteBatch::Draw() has several overloads with increasing control. Here they are from simplest to most complete:

1. Position only

// Draw at (x, y), no tint (White), full texture
spriteBatch_->Draw(*tex_, Vector2(100.0f, 200.0f), Color::White);

2. Position with tint

// Draw tinted red at position
spriteBatch_->Draw(*tex_, Vector2(100.0f, 200.0f), Color::Red);

3. Destination rectangle

// Stretch texture to fill a 200x150 rectangle at (50,50)
spriteBatch_->Draw(*tex_, Rectangle(50, 50, 200, 150), Color::White);

4. Source rectangle (draw sub-region)

// Draw only the top-left 32x32 pixels of the texture
Rectangle src(0, 0, 32, 32);
spriteBatch_->Draw(*tex_, Vector2(100.0f, 100.0f), src, Color::White);

5. Full control overload

// Full signature:
// Draw(texture, position, sourceRect, color, rotation, origin, scale, effects, depth)
Vector2   position(400.0f, 300.0f);   // screen position
Rectangle source(0, 0, 64, 64);       // source region (nullptr for whole texture)
Color     color   = Color::White;
float     rotation = 0.5f;            // radians
Vector2   origin(32.0f, 32.0f);       // rotation pivot (centre of 64x64 sprite)
float     scale   = 2.0f;             // 2x size
SpriteEffects fx  = SpriteEffects::None;
float     depth   = 0.0f;             // z-depth for sorting (0=front, 1=back)

spriteBatch_->Draw(*tex_, position, source, color,
                   rotation, origin, scale, fx, depth);

Parameters explained:

ParameterTypeDescription
positionVector2Top-left (or origin point) on screen
sourceRectangleRectangleRegion of the texture to draw; omit for whole texture
colorColorTint color; White = no tint
rotationfloatRotation in radians, clockwise
originVector2Pivot point in texture space (pixels); (0,0) = top-left
scalefloat or Vector2Scale multiplier (1.0 = original size)
effectsSpriteEffectsFlip flags
layerDepthfloat0..1, used with BackToFront / FrontToBack sorting

Practical examples

// Draw a sprite centred at screen centre, rotated, 2x scale
auto& vp = getGraphicsDeviceProperty().getViewport();
Vector2 screenCentre(vp.getWidth() / 2.0f, vp.getHeight() / 2.0f);
Vector2 texCentre(tex_->getWidth() / 2.0f, tex_->getHeight() / 2.0f);

spriteBatch_->Draw(*tex_, screenCentre, std::nullopt, Color::White,
                   rotation_, texCentre, 2.0f, SpriteEffects::None, 0.0f);

// Update rotation in Update():
rotation_ += MathHelper::Pi * dt;  // rotate 180 degrees per second
// Non-uniform scale: stretch width only
Vector2 scaleXY(3.0f, 1.0f);  // triple width, normal height
spriteBatch_->Draw(*tex_, Vector2(50.0f, 50.0f), std::nullopt,
                   Color::White, 0.0f, Vector2::Zero, scaleXY,
                   SpriteEffects::None, 0.0f);

SpriteEffects: Flipping

SpriteEffects is an enum used to flip sprites horizontally or vertically — essential for characters that face both left and right:

#include "Microsoft/Xna/Framework/Graphics/SpriteEffects.hpp"

// No flip (default)
SpriteEffects::None

// Mirror horizontally (flip left-right) — for a character facing left
SpriteEffects::FlipHorizontally

// Mirror vertically (flip up-down) — less common
SpriteEffects::FlipVertically

// Flip both axes
SpriteEffects::FlipBoth  // = FlipHorizontally | FlipVertically

Typical usage — a character that faces the direction of movement:

// In Update():
if (velocity_.X < 0.0f) {
    facingLeft_ = true;
} else if (velocity_.X > 0.0f) {
    facingLeft_ = false;
}

// In Draw():
SpriteEffects flip = facingLeft_
    ? SpriteEffects::FlipHorizontally
    : SpriteEffects::None;

spriteBatch_->Draw(*playerTex_, position_, std::nullopt, Color::White,
                   0.0f, Vector2::Zero, 1.0f, flip, 0.0f);

You now know how to load image files and draw them with full control. In Tutorial 09 you will add text to your game using SpriteFont.