FrameBuffer

Struct FrameBuffer 

Source
pub struct FrameBuffer { /* private fields */ }
Expand description

Double-buffered frame management for flicker-free animation.

FrameBuffer maintains two BrailleGrid buffers:

  • Front buffer: The currently displayed frame (rendered to terminal)
  • Back buffer: The next frame being prepared (where you draw)

This separation ensures users never see partially drawn frames, eliminating visual tearing and flickering common in terminal graphics.

§Performance

Buffer swapping is an O(1) pointer swap operation (<1ms), not a data copy. This makes it suitable for high frame-rate animations (60+ fps).

§Examples

Basic double-buffering workflow:

use dotmax::animation::FrameBuffer;

// Create a double-buffered frame system (80x24 terminal cells)
let mut buffer = FrameBuffer::new(80, 24);

// Draw to the back buffer
{
    let back = buffer.get_back_buffer();
    back.clear();
    back.set_dot(10, 10).unwrap();
    back.set_dot(11, 10).unwrap();
}

// Swap buffers - the back buffer becomes the new front
buffer.swap_buffers();

// Now the front buffer contains what we drew
assert!(buffer.get_front_buffer().get_dot(10 / 2, 10 / 4, 0).is_ok());

Animation loop pattern:

use dotmax::animation::FrameBuffer;
use dotmax::TerminalRenderer;

let mut buffer = FrameBuffer::new(80, 24);
let mut renderer = TerminalRenderer::new().unwrap();

loop {
    // 1. Clear back buffer
    buffer.get_back_buffer().clear();

    // 2. Draw next frame
    buffer.get_back_buffer().set_dot(10, 10).unwrap();

    // 3. Swap buffers (instant)
    buffer.swap_buffers();

    // 4. Render to terminal
    buffer.render(&mut renderer).unwrap();

    // 5. Wait for next frame timing
    std::thread::sleep(std::time::Duration::from_millis(16)); // ~60fps
}

Implementations§

Source§

impl FrameBuffer

Source

pub fn new(width: usize, height: usize) -> Self

Creates a new double-buffered frame system.

Allocates two BrailleGrid buffers of the specified dimensions. Both buffers are initialized empty (all dots cleared).

§Arguments
  • width - Width in terminal cells (characters)
  • height - Height in terminal cells (lines)
§Panics

Panics if BrailleGrid::new() fails (e.g., zero dimensions). For fallible construction, use the underlying BrailleGrid::new() directly.

§Examples
use dotmax::animation::FrameBuffer;

// Standard terminal size
let buffer = FrameBuffer::new(80, 24);
assert_eq!(buffer.width(), 80);
assert_eq!(buffer.height(), 24);

// Larger buffer for detailed graphics
let large = FrameBuffer::new(200, 50);
assert_eq!(large.width(), 200);
Source

pub fn get_back_buffer(&mut self) -> &mut BrailleGrid

Returns a mutable reference to the back buffer for drawing.

Use this to prepare the next frame. Draw operations on the back buffer do not affect the currently displayed front buffer.

§Examples
use dotmax::animation::FrameBuffer;

let mut buffer = FrameBuffer::new(80, 24);

// Get the back buffer and draw to it
let back = buffer.get_back_buffer();
back.clear();
back.set_dot(0, 0).unwrap();  // Top-left dot
back.set_dot(1, 0).unwrap();  // Adjacent dot

// Front buffer is unchanged until swap_buffers() is called
Source

pub const fn get_front_buffer(&self) -> &BrailleGrid

Returns an immutable reference to the front buffer.

The front buffer contains the currently displayed frame. This is read-only access; to modify a buffer, use get_back_buffer().

§Examples
use dotmax::animation::FrameBuffer;

let buffer = FrameBuffer::new(80, 24);

// Inspect the front buffer (read-only)
let front = buffer.get_front_buffer();
let (width, height) = front.dimensions();
assert_eq!(width, 80);
assert_eq!(height, 24);
Source

pub fn swap_buffers(&mut self)

Atomically swaps the front and back buffers.

After this call:

  • The previous back buffer becomes the new front buffer
  • The previous front buffer becomes the new back buffer

This is an O(1) pointer swap operation, not a data copy. Typical execution time is <1μs (well under the 1ms target).

§Examples
use dotmax::animation::FrameBuffer;

let mut buffer = FrameBuffer::new(80, 24);

// Draw a dot in the back buffer
buffer.get_back_buffer().set_dot(0, 0).unwrap();

// Swap - now the front buffer has the dot
buffer.swap_buffers();

// The old front (now back) is available for the next frame
buffer.get_back_buffer().clear();  // Prepare for next frame
Source

pub fn render(&self, renderer: &mut TerminalRenderer) -> Result<(), DotmaxError>

Renders the front buffer to the terminal.

Delegates to TerminalRenderer::render() to display the current front buffer contents. Supports both colored and non-colored grids.

§Arguments
  • renderer - The terminal renderer to output to
§Errors

Returns DotmaxError::Terminal if terminal I/O fails.

§Examples
use dotmax::animation::FrameBuffer;
use dotmax::TerminalRenderer;

let mut buffer = FrameBuffer::new(80, 24);
let mut renderer = TerminalRenderer::new().unwrap();

// Draw something
buffer.get_back_buffer().set_dot(10, 10).unwrap();
buffer.swap_buffers();

// Render to terminal
buffer.render(&mut renderer).expect("Failed to render");

// Clean up
renderer.cleanup().unwrap();
Source

pub const fn width(&self) -> usize

Returns the width of the buffers in terminal cells.

§Examples
use dotmax::animation::FrameBuffer;

let buffer = FrameBuffer::new(80, 24);
assert_eq!(buffer.width(), 80);
Source

pub const fn height(&self) -> usize

Returns the height of the buffers in terminal cells.

§Examples
use dotmax::animation::FrameBuffer;

let buffer = FrameBuffer::new(80, 24);
assert_eq!(buffer.height(), 24);

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more