Skip to content

Renderer

High-level graphics rendering system for drawing shapes, text, sprites, and tilemaps.

Description

The Renderer class provides a unified API for drawing shapes, text, and images. It abstracts the underlying hardware implementation (DrawSurface) and manages display configuration, including rotation and offsets.

The renderer uses integer-only math for optimal performance on ESP32 and supports multiple sprite formats (1bpp, 2bpp, 4bpp) and multi-layer sprites.

Namespace

namespace pixelroot32::graphics {
    class Renderer {
        // ...
    };
}

Inheritance

  • Base class: None (standalone class)
  • Used by: Engine (manages renderer instance)

Constructors

Renderer(const DisplayConfig& config)

Constructs the Renderer with a specific display configuration.

Parameters: - config (const DisplayConfig&): The display configuration settings (width, height, rotation, etc.)

Example:

#include "graphics/Renderer.h"
#include "graphics/DisplayConfig.h"

pixelroot32::graphics::DisplayConfig config;
config.width = 128;
config.height = 128;
config.rotation = 0;

pixelroot32::graphics::Renderer renderer(config);
renderer.init();

Public Methods

void init()

Initializes the renderer and the underlying draw surface.

Returns: - void

Notes: - Must be called after construction and before any drawing operations - Initializes the platform-specific DrawSurface implementation - Safe to call multiple times (idempotent)

Example:

Renderer renderer(displayConfig);
renderer.init();  // Initialize before use

void beginFrame()

Prepares the buffer for a new frame (clears screen).

Returns: - void

Notes: - Should be called once at the start of each frame - Clears the display buffer - Typically called automatically by Engine, but can be called manually

Example:

void draw(Renderer& renderer) override {
    renderer.beginFrame();
    // Draw everything...
    renderer.endFrame();
}

void endFrame()

Finalizes the frame and sends the buffer to the display.

Returns: - void

Notes: - Should be called once at the end of each frame - Sends the completed frame buffer to the display - Typically called automatically by Engine, but can be called manually

DrawSurface& getDrawSurface()

Gets the underlying DrawSurface implementation.

Returns: - DrawSurface&: Reference to the DrawSurface

Notes: - Advanced usage: typically not needed unless implementing custom drawing - Provides low-level access to the display driver

void drawText(const char* text, int16_t x, int16_t y, Color color, uint8_t size)

Draws a string of text using the default font.

Parameters: - text (const char*): The text to draw (null-terminated string) - x (int16_t): X coordinate (top-left corner of text) - y (int16_t): Y coordinate (top-left corner of text) - color (Color): Text color - size (uint8_t): Text size multiplier (1 = normal, 2 = double, etc.)

Performance Notes: - Efficient for small amounts of text - Avoid calling in tight loops with long strings - Use static buffers for text formatting

Example:

renderer.drawText("Hello World", 10, 10, Color::White, 1);
renderer.drawText("Score: 100", 10, 30, Color::Yellow, 2);

void drawText(const char text, int16_t x, int16_t y, Color color, uint8_t size, const Font font)

Draws a string of text using a specific font.

Parameters: - text (const char): The text to draw - x (int16_t): X coordinate - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size multiplier - font (const Font): Pointer to the font to use. If nullptr, uses the default font

Example:

const Font* customFont = &FONT_5X7;
renderer.drawText("Custom Font", 10, 10, Color::White, 1, customFont);

void drawTextCentered(const char* text, int16_t y, Color color, uint8_t size)

Draws text centered horizontally at a given Y coordinate using the default font.

Parameters: - text (const char*): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size

Example:

renderer.drawTextCentered("Game Over", 64, Color::White, 2);

void drawTextCentered(const char text, int16_t y, Color color, uint8_t size, const Font font)

Draws text centered horizontally at a given Y coordinate using a specific font.

Parameters: - text (const char): The text to draw - y (int16_t): Y coordinate - color (Color): Text color - size (uint8_t): Text size - font (const Font): Pointer to the font to use. If nullptr, uses the default font

void drawFilledCircle(int x, int y, int radius, Color color)

Draws a filled circle.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Fill color

Example:

renderer.drawFilledCircle(64, 64, 20, Color::Red);

void drawCircle(int x, int y, int radius, Color color)

Draws a circle outline.

Parameters: - x (int): Center X coordinate - y (int): Center Y coordinate - radius (int): Radius of the circle in pixels - color (Color): Outline color

Example:

renderer.drawCircle(64, 64, 20, Color::White);

void drawRectangle(int x, int y, int width, int height, Color color)

Draws a rectangle outline.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Outline color

Example:

renderer.drawRectangle(10, 10, 100, 50, Color::Blue);

void drawFilledRectangle(int x, int y, int width, int height, Color color)

Draws a filled rectangle.

Parameters: - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - width (int): Width of the rectangle in pixels - height (int): Height of the rectangle in pixels - color (Color): Fill color

Example:

renderer.drawFilledRectangle(10, 10, 100, 50, Color::Green);

void drawLine(int x1, int y1, int x2, int y2, Color color)

Draws a line between two points.

Parameters: - x1 (int): Start X coordinate - y1 (int): Start Y coordinate - x2 (int): End X coordinate - y2 (int): End Y coordinate - color (Color): Line color

Example:

renderer.drawLine(0, 0, 128, 128, Color::White);

void drawPixel(int x, int y, Color color)

Draws a single pixel.

Parameters: - x (int): X coordinate - y (int): Y coordinate - color (Color): Pixel color

Performance Notes: - Very fast, but avoid calling thousands of times per frame - Use for special effects or debugging

Example:

renderer.drawPixel(64, 64, Color::Red);

void drawSprite(const Sprite& sprite, int x, int y, Color color, bool flipX = false)

Draws a 1bpp monochrome sprite using the Sprite descriptor.

Parameters: - sprite (const Sprite&): Sprite descriptor (data, width, height) - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space - color (Color): Color used for "on" pixels. Default: uses sprite palette context - flipX (bool, optional): If true, sprite is mirrored horizontally. Default: false

Performance Notes: - Very efficient for 1bpp sprites (integer-only operations) - Sprite data should be stored in flash (const/constexpr) for best performance - Avoid calling in tight loops; batch similar operations when possible

Example:

static const uint16_t playerData[] = {
    0b00111100,
    0b01111110,
    // ... more rows
};

static const Sprite playerSprite = {
    playerData,
    8,  // width
    8   // height
};

renderer.drawSprite(playerSprite, 100, 100, Color::White);
renderer.drawSprite(playerSprite, 120, 100, Color::White, true);  // Flipped

void drawSprite(const Sprite& sprite, int x, int y, float scaleX, float scaleY, Color color, bool flipX = false)

Draws a scaled 1bpp monochrome sprite.

Parameters: - sprite (const Sprite&): Sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor (e.g., 1.25 for 25% larger) - scaleY (float): Vertical scaling factor - color (Color): Color used for "on" pixels - flipX (bool, optional): If true, sprite is mirrored horizontally before scaling. Default: false

Performance Notes: - Slower than non-scaled version due to scaling calculations - Use integer scaling factors when possible (1.0, 2.0, etc.) for better performance

Example:

renderer.drawSprite(playerSprite, 100, 100, 2.0f, 2.0f, Color::White);  // 2x size

void drawMultiSprite(const MultiSprite& sprite, int x, int y)

Draws a multi-layer sprite composed of several 1bpp layers.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate in logical screen space - y (int): Top-left Y coordinate in logical screen space

Performance Notes: - Each layer is rendered separately, so more layers = more draw calls - Still efficient as each layer uses 1bpp format - Use for multi-color sprites without higher bit-depths

Example:

static const SpriteLayer layers[] = {
    { outlineData, Color::Black },
    { fillData, Color::Red },
    { highlightData, Color::Yellow }
};

static const MultiSprite playerMultiSprite = {
    8,      // width
    8,      // height
    layers, // layers array
    3       // layer count
};

renderer.drawMultiSprite(playerMultiSprite, 100, 100);

void drawMultiSprite(const MultiSprite& sprite, int x, int y, float scaleX, float scaleY)

Draws a scaled multi-layer sprite.

Parameters: - sprite (const MultiSprite&): Multi-layer sprite descriptor - x (int): Top-left X coordinate - y (int): Top-left Y coordinate - scaleX (float): Horizontal scaling factor - scaleY (float): Vertical scaling factor

void drawTileMap(const TileMap& map, int originX, int originY, Color color)

Draws a tilemap.

Parameters: - map (const TileMap&): Tilemap descriptor (indices, tiles, dimensions) - originX (int): X coordinate of the top-left corner of the tilemap - originY (int): Y coordinate of the top-left corner of the tilemap - color (Color): Color used for tile sprites

Performance Notes: - Very efficient for rendering large backgrounds - Only visible tiles are drawn (viewport culling) - Use tilemaps instead of individual sprites for backgrounds

Example:

static const uint8_t levelIndices[] = {
    0, 1, 2, 3,
    4, 5, 6, 7,
    // ... more rows
};

static const TileMap levelMap = {
    levelIndices,
    16,        // width in tiles
    16,        // height in tiles
    tileSprites, // tile sprite array
    8,         // tile width
    8,         // tile height
    16         // tile count
};

renderer.drawTileMap(levelMap, 0, 0, Color::White);

void setDisplayOffset(int x, int y)

Sets a global offset for all drawing operations. Useful for camera/parallax effects.

Parameters: - x (int): X offset in pixels - y (int): Y offset in pixels

Notes: - All subsequent drawing operations are offset by this amount - Useful for camera scrolling and parallax effects - Reset to (0, 0) to disable offset

Example:

// Camera scrolling
camera.setPosition(playerX - 64, playerY - 64);
renderer.setDisplayOffset(-camera.getX(), -camera.getY());
renderer.drawTileMap(background, 0, 0, Color::White);

void setDisplaySize(int w, int h)

Sets the logical display size.

Parameters: - w (int): Width in pixels - h (int): Height in pixels

Notes: - Typically set via DisplayConfig during construction - Use this to change display size at runtime if needed

int getWidth() const

Gets the display width.

Returns: - int: Display width in pixels

int getHeight() const

Gets the display height.

Returns: - int: Display height in pixels

int getXOffset() const

Gets the current X display offset.

Returns: - int: X offset in pixels

int getYOffset() const

Gets the current Y display offset.

Returns: - int: Y offset in pixels

void setContrast(uint8_t level)

Sets the display contrast (brightness).

Parameters: - level (uint8_t): Contrast level (0-255)

Notes: - Platform-specific: may not be supported on all displays - Higher values = brighter display

void setFont(const uint8_t* font)

Sets the font for text rendering.

Parameters: - font (const uint8_t*): Pointer to the font data

Notes: - Sets the default font for drawText() calls without font parameter - Use font constants like FONT_5X7 from Font.h

Usage Example

#include "graphics/Renderer.h"
#include "graphics/DisplayConfig.h"

void draw(Renderer& renderer) override {
    renderer.beginFrame();

    // Draw background
    renderer.drawFilledRectangle(0, 0, 128, 128, Color::Black);

    // Draw sprites
    renderer.drawSprite(playerSprite, playerX, playerY, Color::White);
    renderer.drawSprite(enemySprite, enemyX, enemyY, Color::Red);

    // Draw UI
    renderer.drawText("Score: 100", 10, 10, Color::White, 1);
    renderer.drawTextCentered("Game Over", 64, Color::Yellow, 2);

    renderer.endFrame();
}

Performance Considerations

  • Integer-only math: All operations use integer arithmetic for ESP32 efficiency
  • Sprite storage: Store sprite data in flash (const/constexpr) for best performance
  • Batch operations: Group similar draw calls together
  • Tilemaps: Use tilemaps for backgrounds instead of individual sprites
  • Viewport culling: Only draw what's visible on screen

ESP32 Considerations

  • Memory: Sprite data should be in flash, not RAM
  • Frame rate: Limit draw calls per frame for consistent FPS
  • Display offset: Use for scrolling instead of redrawing everything

See Also