Skip to content

Extensibility Guide: Creating Custom Drivers

This guide explains how to implement a custom display driver (DrawSurface) to support hardware not included by default in the PixelRoot32 engine (e.g., monochromatic OLED displays, e-Ink screens, or non-standard SPI displays).

1. Inherit from BaseDrawSurface

The easiest way to create a driver is to inherit from pixelroot32::graphics::BaseDrawSurface. This class provides default implementations for most primitive methods (lines, circles, rectangles) using drawPixel().

#include <graphics/BaseDrawSurface.h>
#include <iostream>

class MyCustomDriver : public pixelroot32::graphics::BaseDrawSurface {
public:
    void init() override {
        // Initialize hardware (SPI, I2C, etc.)
        std::cout << "Hardware initialized" << std::endl;
    }

    void drawPixel(int x, int y, uint16_t color) override {
        // Logic to write a pixel to your buffer or hardware
    }

    void clearBuffer() override {
        // Logic to clear the buffer
    }

    void sendBuffer() override {
        // Logic to send the buffer to the physical display (Flush)
    }
};

2. Injecting the Driver into the Engine

Once you have your class, you can inject it into the engine using the PIXELROOT32_CUSTOM_DISPLAY macro. The engine will take ownership of the pointer and handle memory deallocation automatically upon shutdown.

#include <core/Engine.h>
#include "MyCustomDriver.h"

void setup() {
    // Create the configuration using our driver
    auto driver = std::make_unique<MyCustomDriver>();
    auto config = PIXELROOT32_CUSTOM_DISPLAY(driver.release(), 240, 240);

    // Initialize the engine with this configuration
    // Note: Use std::move to transfer ownership of the config
    Engine engine(std::move(config));

    engine.init();
    engine.run();
}

3. Memory Considerations

  • Ownership: By using PIXELROOT32_CUSTOM_DISPLAY, you transfer ownership of the object to the engine. Do not attempt to delete the pointer manually.
  • Smart Pointers: Internally, the engine uses std::unique_ptr to manage the driver.
  • Performance: BaseDrawSurface uses generic algorithms for lines and circles that call drawPixel(). If your hardware supports acceleration for these primitives, you can override the methods (e.g., drawLine, drawFilledRectangle) to achieve better performance.

4. Mandatory vs. Optional Methods

Method Mandatory Description
init() Yes Initial hardware configuration.
drawPixel() Yes The foundation of all rendering.
sendBuffer() Yes Sends data to the display.
clearBuffer() Yes Clears the screen/buffer.
setOffset() No Sets X/Y hardware alignment offset.
setRotation() No BaseDrawSurface handles this internally.
drawLine() No Optimized in BaseDrawSurface.
drawRectangle() No Optimized in BaseDrawSurface.
drawCircle() No Optimized in BaseDrawSurface.

PixelRoot32 - Extensible Driver System (Bridge Pattern)