Skip to content

Software Output

Finalspace edited this page May 29, 2026 · 2 revisions

Table of Contents

Initialize a software backbuffer

To initialize software rendering output, you simply set the fplInitFlags_Video flag in the fplPlatformInit() call and change the video backend type to fplVideoBackendType_Software.

Call fplGetVideoBackBuffer() to get access to the pixel data.

 settings;
(&settings);
 &videoSettings = settings.;

// Forcing the video backend to be software
videoSettings. = ;

if ((, &settings)) {
    // Video software backbuffer is ready
     *videoBackBuffer = ();
}

Usage

To use the software backbuffer you simply access the fplVideoBackBuffer from the fplGetVideoBackBuffer() function and update the pixels as needed.

Presenting your frame

Call fplVideoFlip() to draw the pixels from the backbuffer to the window.

It is recommended to call this after each draw call of your frame at the end of the main-loop.

Drawing

Drawing is done by manually changing the pixels in the fplVideoBackBuffer::pixels field.

Each pixel is stored as 32-bit with 4 RGBA components in little-endian (AA BB GG RR).

Lines are stored in top-down order - meaning that position "0" in the fplVideoBackBuffer::pixels field is always the top-left corner of the bitmap!

To calculate the actual position for the current line, you simply multiply your Y-Index with the fplVideoBackBuffer::lineWidth field.

Example (Filling all pixels to purple):

 *backBuffer = ();
for (uint32_t y = 0; y < backBuffer->; ++y) {
    uint32_t *p = (uint32_t *)((uint8_t *)backBuffer-> + y * backBuffer->);
    for (uint32_t x = 0; x < backBuffer->; ++x) {
        uint32_t color = 0xFFFF00FF;
         *p++ = color;
    }
}

Limiting the output rectangle (Stretching vs non-stretched)

To force the pixels to be shown in a fixed rectangle you simply enable the fplVideoBackBuffer::useOutputRect field and update the fplVideoBackBuffer::outputRect as needed.

This mimics a "viewport" which is similar to OpenGL's glViewport().

If you don't use this feature all pixels are fully stretched to the current window area always!

Note: This viewport should not be greater than the actual window area dimension!

Example (Resize window event):

static  ComputeLetterbox(int windowWidth, int windowHeight, int backWidth, int backHeight) {
    return {};
}
 *backBuffer = ();
backBuffer-> = true;
while (()) {
     ev;
    while ((&ev)) {
        if (ev. == ) {
            if (ev.. == ) {
                 newRect = ComputeLetterbox(ev..width, ev..height, backBuffer->, backBuffer->); // ... Compute new rectangle here (Letterbox or something)
                backBuffer-> = newRect;
            }
        }
    }

    // ... Modify the pixels here (Draw call)

    ();
}

Example (Always before the draw call):

 *backBuffer = ();
backBuffer-> = true;
while (()) {
     ev;
    while ((ev)) {}

     windowArea = ();
     newRect = ComputeLetterbox(windowArea, backBuffer->, backBuffer->); // ... Compute new rectangle here (Letterbox or something)
    backBuffer-> = newRect;

    // ... Modify the pixels here (Draw call)

    ();
}

Resizing the backbuffer

By default, the video backbuffer is automatically resized when the dimension of the window area changes.

If you want to manually do this, you disable this feature in the fplVideoSettings::isAutoSize field - in the fplSettings::video configuration section.

Call fplResizeVideoBackBuffer() with a new width and height as an argument, to force the backbuffer to be resized to the new dimension.

Warning: Do not call this method while you are modifying pixels!

Notes

  • There are no software rendering functions built-in! If you want to draw a circle for example, you have to roll your own drawCircle() function - which may use Bresenham as its base or something.
  • Vertical synchronization is not supported for software video backends!

Final Platform Layer

Pages

Topics

Data Structures

Clone this wiki locally