pub struct Canvas<T: RenderTarget, U> { /* private fields */ }Expand description
This struct allows you to draw to the screen in various ways. It is a wrapper around:
- An sdl2
Canvas, which allows you to draw points, lines, rectangles, etc, and to “blit” textures and surfaces onto the screen. - An sdl2
TextureCreator, which is linked to the sdl2Canvas, for creating textures. - An [sdl2-unifont
SurfaceRenderer][TextRenderer] for rendering text to a surface. This struct implementsDerefandDerefMutfor the sdl2Canvas, so you can call any of the normal drawing routines via deref coersion.
Implementations§
Source§impl Canvas<Window, WindowContext>
impl Canvas<Window, WindowContext>
Source§impl<'a> Canvas<Surface<'a>, SurfaceContext<'a>>
impl<'a> Canvas<Surface<'a>, SurfaceContext<'a>>
Source§impl<T: RenderTarget, U> Canvas<T, U>
impl<T: RenderTarget, U> Canvas<T, U>
Sourcepub fn texture_creator(&self) -> &TextureCreator<U>
pub fn texture_creator(&self) -> &TextureCreator<U>
Returns an immutable reference to the TextureCreator associated with this canvas.
Sourcepub fn texture_creator_mut(&mut self) -> &mut TextureCreator<U>
pub fn texture_creator_mut(&mut self) -> &mut TextureCreator<U>
Returns a mutable reference to the TextureCreator associated with this canvas.
Sourcepub fn draw_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
pub fn draw_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
Draws a circle outline using Bresenham’s algorithm, with the given center and radius.
Sourcepub fn fill_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
pub fn fill_circle<P>(&mut self, center: P, radius: i32) -> Result<(), String>
Draws a filled circle using Bresenham’s algorithm, with the given center and radius.
Examples found in repository?
22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - CIRCLE_RADIUS) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - CIRCLE_RADIUS) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Draw the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_circle((self.x as i32, self.y as i32), CIRCLE_RADIUS as i32)?;
51 Ok(true)
52 }Methods from Deref<Target = SdlCanvas<T>>§
Sourcepub fn render_target_supported(&self) -> bool
pub fn render_target_supported(&self) -> bool
Determine whether a window supports the use of render targets.
Sourcepub fn with_texture_canvas<F>(
&mut self,
texture: &mut Texture<'_>,
f: F,
) -> Result<(), TargetRenderError>
pub fn with_texture_canvas<F>( &mut self, texture: &mut Texture<'_>, f: F, ) -> Result<(), TargetRenderError>
Temporarily sets the target of Canvas to a Texture. This effectively allows rendering
to a Texture in any way you want: you can make a Texture a combination of other
Textures, be a complex geometry form with the gfx module, … You can draw pixel by
pixel in it if you want, so you can do basically anything with that Texture.
If you want to set the content of multiple Texture at once the most efficient way
possible, don’t make a loop and call this function every time and use
with_multiple_texture_canvas instead. Using with_texture_canvas is actually
inefficient because the target is reset to the source (the Window or the Surface)
at the end of this function, but using it in a loop would make this reset useless.
Plus, the check that render_target is actually supported on that Canvas is also
done every time, leading to useless checks.
§Notes
Note that the Canvas in the closure is exactly the same as the one you call this
function with, meaning that you can call every function of your original Canvas.
That means you can also call with_texture_canvas and with_multiple_texture_canvas from
the inside of the closure. Even though this is useless and inefficient, this is totally
safe to do and allowed.
Since the render target is now a Texture, some calls of Canvas might return another result
than if the target was to be the original source. For instance output_size will return
this size of the current Texture in the closure, but the size of the Window or
Surface outside of the closure.
You do not need to call present after drawing in the Canvas in the closure, the changes
are applied directly to the Texture instead of a hidden buffer.
§Errors
- returns
TargetRenderError::NotSupportedif the renderer does not support the use of render targets - returns
TargetRenderError::SdlErrorif SDL2 returned with an error code.
The texture must be created with the texture access:
sdl2::render::TextureAccess::Target.
Using a texture which was not created with the texture access Target is undefined
behavior.
§Examples
The example below changes a newly created Texture to be a 150-by-150 black texture with a
50-by-50 red square in the middle.
let texture_creator = canvas.texture_creator();
let mut texture = texture_creator
.create_texture_target(texture_creator.default_pixel_format(), 150, 150)
.unwrap();
let result = canvas.with_texture_canvas(&mut texture, |texture_canvas| {
texture_canvas.set_draw_color(Color::RGBA(0, 0, 0, 255));
texture_canvas.clear();
texture_canvas.set_draw_color(Color::RGBA(255, 0, 0, 255));
texture_canvas.fill_rect(Rect::new(50, 50, 50, 50)).unwrap();
});Sourcepub fn with_multiple_texture_canvas<'t, 'a, 's, I, F, U>(
&mut self,
textures: I,
f: F,
) -> Result<(), TargetRenderError>
pub fn with_multiple_texture_canvas<'t, 'a, 's, I, F, U>( &mut self, textures: I, f: F, ) -> Result<(), TargetRenderError>
Same as with_texture_canvas, but allows to change multiple Textures at once with the
least amount of overhead. It means that between every iteration the Target is not reset to
the source, and that the fact that the Canvas supports render target isn’t checked every
iteration either; the check is actually only done once, at the beginning, avoiding useless
checks.
The closure is run once for every Texture sent as parameter.
The main changes from with_texture_canvas is that is takes an Iterator of (&mut Texture, U), where U is a type defined by the user. The closure takes a &mut Canvas, and
&U as arguments instead of a simple &mut Canvas. This user-defined type allows you to
keep track of what to do with the Canvas you have received in the closure.
You will usually want to keep track of the number, a property, or anything that will allow
you to uniquely track this Texture, but it can also be an empty struct or () as well!
§Examples
Let’s create two textures, one which will be yellow, and the other will be white
let texture_creator = canvas.texture_creator();
enum TextureColor {
Yellow,
White,
};
let mut square_texture1 : Texture =
texture_creator.create_texture_target(None, 100, 100).unwrap();
let mut square_texture2 : Texture =
texture_creator.create_texture_target(None, 100, 100).unwrap();
let textures : Vec<(&mut Texture, TextureColor)> = vec![
(&mut square_texture1, TextureColor::Yellow),
(&mut square_texture2, TextureColor::White)
];
let result : Result<(), _> =
canvas.with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| {
match *user_context {
TextureColor::White => {
texture_canvas.set_draw_color(Color::RGB(255, 255, 255));
},
TextureColor::Yellow => {
texture_canvas.set_draw_color(Color::RGB(255, 255, 0));
}
};
texture_canvas.clear();
});
// square_texture1 is now Yellow and square_texture2 is now White!pub fn raw(&self) -> *mut SDL_Renderer
Sourcepub fn set_draw_color<C>(&mut self, color: C)
pub fn set_draw_color<C>(&mut self, color: C)
Sets the color used for drawing operations (Rect, Line and Clear).
Examples found in repository?
24 fn on_update(
25 &mut self,
26 canvas: &mut WindowCanvas,
27 input: &InputState,
28 elapsed_time: f64,
29 ) -> sge::ApplicationResult {
30 // Handle keyboard input
31 if input.keyboard.pressed(Scancode::Q) {
32 return Ok(false);
33 }
34 // If we're at the bounds for a colour value, change direction
35 if self.col <= 0.0 || self.col >= 255.0 {
36 self.flipper = !self.flipper;
37 }
38 // Fill the screen with the current colour
39 canvas.set_draw_color(Color::RGB(self.col as u8, 0, 255 - self.col as u8));
40 canvas.clear();
41 // Change the colour
42 if !self.flipper {
43 self.col -= CYCLE_SPEED * elapsed_time as f32;
44 } else {
45 self.col += CYCLE_SPEED * elapsed_time as f32;
46 }
47 Ok(true)
48 }More examples
22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - CIRCLE_RADIUS) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - CIRCLE_RADIUS) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Draw the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_circle((self.x as i32, self.y as i32), CIRCLE_RADIUS as i32)?;
51 Ok(true)
52 }22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - RECT_SIZE) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - RECT_SIZE) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Fill the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_rect(Rect::new(
51 self.x as i32,
52 self.y as i32,
53 RECT_SIZE,
54 RECT_SIZE,
55 ))?;
56 Ok(true)
57 }Sourcepub fn draw_color(&self) -> Color
pub fn draw_color(&self) -> Color
Gets the color used for drawing operations (Rect, Line and Clear).
Sourcepub fn set_blend_mode(&mut self, blend: BlendMode)
pub fn set_blend_mode(&mut self, blend: BlendMode)
Sets the blend mode used for drawing operations (Fill and Line).
Sourcepub fn blend_mode(&self) -> BlendMode
pub fn blend_mode(&self) -> BlendMode
Gets the blend mode used for drawing operations.
Sourcepub fn clear(&mut self)
pub fn clear(&mut self)
Clears the current rendering target with the drawing color.
Examples found in repository?
24 fn on_update(
25 &mut self,
26 canvas: &mut WindowCanvas,
27 input: &InputState,
28 elapsed_time: f64,
29 ) -> sge::ApplicationResult {
30 // Handle keyboard input
31 if input.keyboard.pressed(Scancode::Q) {
32 return Ok(false);
33 }
34 // If we're at the bounds for a colour value, change direction
35 if self.col <= 0.0 || self.col >= 255.0 {
36 self.flipper = !self.flipper;
37 }
38 // Fill the screen with the current colour
39 canvas.set_draw_color(Color::RGB(self.col as u8, 0, 255 - self.col as u8));
40 canvas.clear();
41 // Change the colour
42 if !self.flipper {
43 self.col -= CYCLE_SPEED * elapsed_time as f32;
44 } else {
45 self.col += CYCLE_SPEED * elapsed_time as f32;
46 }
47 Ok(true)
48 }More examples
22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - CIRCLE_RADIUS) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - CIRCLE_RADIUS) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Draw the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_circle((self.x as i32, self.y as i32), CIRCLE_RADIUS as i32)?;
51 Ok(true)
52 }22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - RECT_SIZE) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - RECT_SIZE) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Fill the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_rect(Rect::new(
51 self.x as i32,
52 self.y as i32,
53 RECT_SIZE,
54 RECT_SIZE,
55 ))?;
56 Ok(true)
57 }Sourcepub fn present(&mut self)
pub fn present(&mut self)
Updates the screen with any rendering performed since the previous call.
SDL’s rendering functions operate on a backbuffer; that is, calling a
rendering function such as draw_line() does not directly put a line on
the screen, but rather updates the backbuffer.
As such, you compose your entire scene and present the composed
backbuffer to the screen as a complete picture.
Sourcepub fn output_size(&self) -> Result<(u32, u32), String>
pub fn output_size(&self) -> Result<(u32, u32), String>
Gets the output size of a rendering context.
Sourcepub fn set_logical_size(
&mut self,
width: u32,
height: u32,
) -> Result<(), IntegerOrSdlError>
pub fn set_logical_size( &mut self, width: u32, height: u32, ) -> Result<(), IntegerOrSdlError>
Sets a device independent resolution for rendering.
Sourcepub fn logical_size(&self) -> (u32, u32)
pub fn logical_size(&self) -> (u32, u32)
Gets device independent resolution for rendering.
Sourcepub fn set_viewport<R>(&mut self, rect: R)
pub fn set_viewport<R>(&mut self, rect: R)
Sets the drawing area for rendering on the current target.
Sourcepub fn set_clip_rect<R>(&mut self, rect: R)
pub fn set_clip_rect<R>(&mut self, rect: R)
Sets the clip rectangle for rendering on the specified target.
If the rectangle is None, clipping will be disabled.
Sourcepub fn clip_rect(&self) -> Option<Rect>
pub fn clip_rect(&self) -> Option<Rect>
Gets the clip rectangle for the current target.
Returns None if clipping is disabled.
Sourcepub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String>
pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String>
Sets the drawing scale for rendering on the current target.
Sourcepub fn draw_point<P>(&mut self, point: P) -> Result<(), String>
pub fn draw_point<P>(&mut self, point: P) -> Result<(), String>
Draws a point on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn draw_points<'a, P>(&mut self, points: P) -> Result<(), String>
pub fn draw_points<'a, P>(&mut self, points: P) -> Result<(), String>
Draws multiple points on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn draw_line<P1, P2>(&mut self, start: P1, end: P2) -> Result<(), String>
pub fn draw_line<P1, P2>(&mut self, start: P1, end: P2) -> Result<(), String>
Draws a line on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn draw_lines<'a, P>(&mut self, points: P) -> Result<(), String>
pub fn draw_lines<'a, P>(&mut self, points: P) -> Result<(), String>
Draws a series of connected lines on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn draw_rect(&mut self, rect: Rect) -> Result<(), String>
pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String>
Draws a rectangle on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String>
pub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String>
Draws some number of rectangles on the current rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn fill_rect<R>(&mut self, rect: R) -> Result<(), String>
pub fn fill_rect<R>(&mut self, rect: R) -> Result<(), String>
Fills a rectangle on the current rendering target with the drawing color. Passing None will fill the entire rendering target. Errors if drawing fails for any reason (e.g. driver failure)
Examples found in repository?
22 fn on_update(
23 &mut self,
24 canvas: &mut WindowCanvas,
25 input: &InputState,
26 elapsed_time: f64,
27 ) -> sge::ApplicationResult {
28 // Move the rectangle with the keyboard
29 if input.keyboard.held(Scancode::Up) {
30 self.y = (self.y - MOVEMENT_SPEED * elapsed_time).max(0.0);
31 } else if input.keyboard.held(Scancode::Down) {
32 self.y =
33 (self.y + MOVEMENT_SPEED * elapsed_time).min((SCREEN_HEIGHT - RECT_SIZE) as f64);
34 }
35 if input.keyboard.held(Scancode::Left) {
36 self.x = (self.x - MOVEMENT_SPEED * elapsed_time).max(0.0);
37 } else if input.keyboard.held(Scancode::Right) {
38 self.x =
39 (self.x + MOVEMENT_SPEED * elapsed_time).min((SCREEN_WIDTH - RECT_SIZE) as f64);
40 }
41 // Move the rectangle with the mouse
42 if input.mouse.buttons.held(MouseButton::Left) {
43 self.x = input.mouse.x as f64;
44 self.y = input.mouse.y as f64;
45 }
46 // Fill the screen
47 canvas.set_draw_color(Color::BLACK);
48 canvas.clear();
49 canvas.set_draw_color(Color::GRAY);
50 canvas.fill_rect(Rect::new(
51 self.x as i32,
52 self.y as i32,
53 RECT_SIZE,
54 RECT_SIZE,
55 ))?;
56 Ok(true)
57 }Sourcepub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String>
pub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String>
Fills some number of rectangles on the current rendering target with the drawing color. Errors if drawing fails for any reason (e.g. driver failure)
Sourcepub fn copy<R1, R2>(
&mut self,
texture: &Texture<'_>,
src: R1,
dst: R2,
) -> Result<(), String>
pub fn copy<R1, R2>( &mut self, texture: &Texture<'_>, src: R1, dst: R2, ) -> Result<(), String>
Copies a portion of the texture to the current rendering target.
- If
srcisNone, the entire texture is copied. - If
dstisNone, the texture will be stretched to fill the given rectangle.
Errors if drawing fails for any reason (e.g. driver failure), or if the provided texture does not belong to the renderer.
Sourcepub fn copy_ex<R1, R2, P>(
&mut self,
texture: &Texture<'_>,
src: R1,
dst: R2,
angle: f64,
center: P,
flip_horizontal: bool,
flip_vertical: bool,
) -> Result<(), String>
pub fn copy_ex<R1, R2, P>( &mut self, texture: &Texture<'_>, src: R1, dst: R2, angle: f64, center: P, flip_horizontal: bool, flip_vertical: bool, ) -> Result<(), String>
Copies a portion of the texture to the current rendering target, optionally rotating it by angle around the given center and also flipping it top-bottom and/or left-right.
- If
srcisNone, the entire texture is copied. - If
dstisNone, the texture will be stretched to fill the given rectangle. - If
centerisNone, rotation will be done around the center point ofdst, orsrcifdstis None.
Errors if drawing fails for any reason (e.g. driver failure), if the provided texture does not belong to the renderer, or if the driver does not support RenderCopyEx.
Methods from Deref<Target = RendererContext<<T as RenderTarget>::Context>>§
Sourcepub fn info(&self) -> RendererInfo
pub fn info(&self) -> RendererInfo
Gets information about the rendering context.
Sourcepub fn raw(&self) -> *mut SDL_Renderer
pub fn raw(&self) -> *mut SDL_Renderer
Gets the raw pointer to the SDL_Renderer