~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~
~

Canvas

Initialization

To initialize a Canvas struct, use a Window:

let mut canvas = window.into_canvas().build().unwrap();

Set Draw Color

To set the draw color for the Canvas, use a Color:

pub fn set_draw_color<C: Into<Color>>(&mut self, color: C)

Clear Canvas

To clear the Canvas with the draw color:

pub fn clear(&mut self)

Present Canvas

To present the actual canvas onto the screen, updating any buffered rendering changes:

pub fn present(&mut self)

Draw Line

To draw a line on the canvas, use a start and end Point:

pub fn draw_line<P1: Into<Point>, P2: Into<Point>>(
        &mut self,
        start: P1,
        end: P2,
    ) -> Result<(), String>

Draw Rectangle

To draw a rectangle on the canvas, pass in a Rect to draw_rect:

pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String>

NOTE: This only draws an outline of the rectangle. To fill the rectangle, use fill_rect instead:

Fill Rectangle

To fill a rectangle on the canvas, pass in a Rect to fill_rect:

pub fn fill_rect<R: Into<Option<Rect>>>(
        &mut self,
        rect: R,
    ) -> Result<(), String>

Draw Triangle

SDL2-rs does not implement the RenderGeometry functions, so we are left to create them for ourselves. Drawing the outline of a triangle is easy enough:

/// Given three points, render the outline of a triangle abc
pub fn draw_triangle(canvas: &mut Canvas<Window>, a: Point, b: Point, c: Point) {
    canvas.draw_line(a, b).unwrap();
    canvas.draw_line(b, c).unwrap();
    canvas.draw_line(c, a).unwrap();
}

Fill Triangle

However, filling a triangle requires more work. We can utilize a scanline algorithm, which as a high-level overview simply iterates through y-levels of the triangle, figuring out the bounding edges, and then drawing a line to fill the triangle.

The following is a basic implementation of this, which uses a Vector2 (see here):

/// Given two points that form a line, and a y-coordinate, interpolate the x-coordinate 
fn interpolate(a: Vector2, b: Vector2, y: i32) -> i32 {
    let m = (b.y - a.y) as f32 / (b.x - a.x) as f32;
    ((y - a.y) as f32 / m) as i32 + a.x
} 

/// Given three points, fill the triangle abc using a scanline algorithm
pub fn fill_triangle(canvas: &mut Canvas<Window>, a: Vector2, b: Vector2, c: Vector2) {
    let mut points: Vec<Vector2> = vec![a, b, c];
    points.sort_by(|first, second| first.y.cmp(&second.y));

    // iterate through each y-level
    for y in points[0].y..=points[2].y {
        // compute active edges
        let left_edge: (Vector2, Vector2);
        let right_edge: (Vector2, Vector2);

        // configuration where the intermediate point is to the right of the lowest point
        if points[0].x <= points[1].x && y <= points[1].y {
            left_edge = (points[0], points[2]);
            right_edge = (points[0], points[1]);
        } else if points[0].x <= points[1].x {
            left_edge = (points[0], points[2]);
            right_edge = (points[1], points[2]);
        }

        // configuration where the intermediate point is to the left of the lowest point
        else if y <= points[1].y {
            left_edge = (points[0], points[1]);
            right_edge = (points[0], points[2]);
        } else {
            left_edge = (points[1], points[2]);
            right_edge = (points[0], points[2]);
        }

        // get start and end points of line to draw
        let start: Vector2 = Vector2::new(interpolate(left_edge.0, left_edge.1, y), y);
        let end: Vector2 = Vector2::new(interpolate(right_edge.0, right_edge.1, y), y);

        // draw the line
        canvas.draw_line(start, end).unwrap();
    }
}

NOTE: this may not be the most efficient implementation, as it is possible to reduce the number of times interpolation occurs as well as the number of times the active edges are calculated.

Get Output Size

To get the output or window size, use the output_size() method:

pub fn output_size(&self) -> Result<(u32, u32), String>

Create a TextureCreator

Returns a TextureCreator that can create Textures to be drawn on this Canvas

This TextureCreator will share a reference to the renderer and target context.

The target (i.e., Window) will not be destroyed and the SDL_Renderer will not be destroyed if the TextureCreator is still in scope.

pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>>
NORMAL
1:1