Basic Shape Rendering
Relevant source files
The following files were used as context for generating this wiki page:
Basic Shape Rendering in the guiltty project refers to the capability of drawing pixel-level 2D geometric primitives into a Canvas. Unlike traditional TUI libraries that operate on character grids, this system manipulates an RGBA8 pixel buffer to render smooth shapes, lines, and polygons.
The rendering logic is backend-agnostic, contained within the guiltty-core crate, and supports a variety of primitives including lines, rectangles, circles, ellipses, triangles, and arbitrary paths. These shapes are processed through various rasterization algorithms like Bresenham's for lines and scanline fill for polygons, ensuring accuracy and performance by clipping operations to the canvas bounds.
Sources: README.md:1-10, crates/guiltty-core/src/lib.rs:1-10
Core Data Structures
The rendering system relies on several fundamental primitives to define color, position, and geometry.
Color and Coordinates
Shapes are rendered using the Color struct, which represents an RGBA8 color. Spatial information is handled by Point (pixel-addressable coordinates) and Rect (origin and dimensions).
| Structure | Description | Fields |
|---|---|---|
Color | RGBA8 color model used for pixels and fills. | r, g, b, a (u8) |
Point | A pixel-addressable point with top-left origin. | x, y (i32) |
Rect | A pixel-addressable rectangle. | x, y (i32), width, height (u32) |
Sources: crates/guiltty-core/src/lib.rs:8-66
Shape Definition
The Shape enum defines the available geometric primitives. Some shapes are naturally closed and support filling, while others are primarily for stroking.
The diagram shows the relationship between geometric shapes and the fill types used to paint them.
Sources: crates/guiltty-core/src/lib.rs:343-401
Rendering Logic and Algorithms
The Canvas struct provides the primary interface for drawing shapes via draw_shape. It uses specific algorithms to translate geometric definitions into pixel data.
Dispatch Flow
The draw_shape method acts as a dispatcher, routing the shape and its Fill properties to the appropriate internal rasterization function.
This flowchart illustrates how different Shape variants are dispatched to specialized rendering methods.
Sources: crates/guiltty-core/src/lib.rs:411-432
Rasterization Techniques
The implementation uses several standard computer graphics algorithms optimized for the guiltty canvas:
- Bresenham's Line Algorithm: Used in
stroke_linefor single-pixel wide lines without anti-aliasing. Lines are clipped using the Liang-Barsky algorithm to prevent unnecessary iterations for off-screen segments. - Even-Odd Rule: Employed in
fill_polygon_even_oddfor closed paths. This scanline algorithm handles concave and self-intersecting polygons by counting edge crossings. - Barycentric Sign Test: Used in
fill_triangleto determine if a pixel center lies within the triangular bounds. - Elliptical Inclusion:
fill_ellipseuses anf64inclusion test(dx/rx)^2 + (dy/ry)^2 <= 1to avoid integer overflow issues common with large radii.
Sources: crates/guiltty-core/src/lib.rs:437-565, tasks/plan.md:65-80
Clipping and Precision
To maintain performance and stability, all rendering functions include clipping logic.
| Algorithm | Optimization / Safety |
|---|---|
| Liang-Barsky | Clips lines to [0, width) x [0, height) before Bresenham walk. |
| Bounding Box | Triangles and Ellipses only scan pixels within their intersection with the canvas. |
| i128 Precision | edge_sign calculations for triangles use i128 to prevent cross-product overflow. |
| f64 Precision | Ellipse inclusion and polygon scanline crossings use floating point to ensure rasterization accuracy. |
Sources: crates/guiltty-core/src/lib.rs:500-515%20x%20%5B0%2C%20height)%60%20before%20Bresenham%20walk.%20%7C%0A%7C%20Bounding%20Box%20%7C%20Triangles%20and%20Ellipses%20only%20scan%20pixels%20within%20their%20intersection%20with%20the%20canvas.%20%7C%0A%7C%20i128%20Precision%20%7C%20%60edge_sign%60%20calculations%20for%20triangles%20use%20%60i128%60%20to%20prevent%20cross-product%20overflow.%20%7C%0A%7C%20f64%20Precision%20%7C%20Ellipse%20inclusion%20and%20polygon%20scanline%20crossings%20use%20floating%20point%20to%20ensure%20rasterization%20accuracy.%20%7C%0A%0ASources%3A%20%5Bcrates/guiltty-core/src/lib.rs%3A500-515), crates/guiltty-core/src/lib.rs:695-715, crates/guiltty-core/src/lib.rs:758-765
Usage Example
Shapes are drawn by creating a Canvas, defining a Shape, and specifying a Fill.
// crates/guiltty-core/src/lib.rs
let mut canvas = Canvas::new(100, 100);
let red = Color::rgb(255, 0, 0);
// Draw a filled rectangle
canvas.draw_shape(
&Shape::rect(Point::new(10, 10), 50, 30),
Fill::solid(red)
);
// Draw a line
canvas.draw_shape(
&Shape::line(Point::new(0, 0), Point::new(99, 99)),
Fill::solid(red)
);
Sources: crates/guiltty-core/src/lib.rs:411-432, crates/guiltty/src/lib.rs:1-10
Summary
Basic Shape Rendering in guiltty provides a robust foundation for 2D graphics in the terminal. By utilizing precise rasterization algorithms and aggressive clipping, the system allows for the creation of complex visual elements like polygons and ellipses while remaining safe from coordinate overflows and performance degradation. This module serves as the primary engine for higher-level features like Sprites and Text Rendering.