- Rust Programming By Example
- Guillaume Gomez Antoni Boucher
- 984字
- 2021-07-02 19:13:05
Drawing
We now have a working window; it'd be nice to draw into it. First, we need to get the window's canvas before starting the main loop:
let mut canvas = window.into_canvas() .target_texture() .present_vsync() .build() .expect("Couldn't get window's canvas");
A few explanations for the preceding code:
- into_canvas transforms the window into a canvas so that we can manipulate it more easily
- target_texture activates texture rendering support
- present_vsync enables the v-sync (also known as vertical-synchronization) limit
- build creates the canvas by applying all previously set parameters
Then we'll create a texture that we'll paste onto the window's canvas. First, let's get the texture creator, but before that, add this include at the top of the file:
use sdl2::render::{Canvas, Texture, TextureCreator};
Now we can get the texture creator:
let texture_creator: TextureCreator<_> = canvas.texture_creator();
OK! Now we need to create a rectangle. To make things easier to read, we'll create a constant that will be the texture's size (better to put it at the head of the file, just after the imports, for readability reasons):
const TEXTURE_SIZE: u32 = 32;
Let's create a texture with a 32x32 size:
let mut square_texture: Texture = texture_creator.create_texture_target(None, TEXTURE_SIZE,
TEXTURE_SIZE) .expect("Failed to create a texture");
Good! Now let's color it. First, add this import at the top of the file:
use sdl2::pixels::Color;
We use the canvas to draw our square texture:
canvas.with_texture_canvas(&mut square_texture, |texture| { texture.set_draw_color(Color::RGB(0, 255, 0)); texture.clear(); });
An explanation of the preceding code is as follows:
- set_draw_color sets the color to be used when drawing occurs. In our case, it's green.
- clear washes/clears the texture so it'll be filled with green.
Now, we just have to draw this square texture onto our window. In order to make it work, we need it to be drawn into the main loop but right after the event loop.
One thing to note before we continue: when drawing with the SDL2, the (0, 0) coordinates are at the top-left of a window, not at the bottom-left. The same goes for all shapes.
Add this import at the top of your file:
use sdl2::rect::Rect;
Now let's draw. In order to be able to update the rendering of your window, you need to draw inside the main loop (and after the event loop). So firstly, let's fill our window with red:
canvas.set_draw_color(Color::RGB(255, 0, 0)); canvas.clear();
Next, we copy our texture into the window in the top-left corner with a 32x32 size:
canvas.copy(&square_texture, None, Rect::new(0, 0, TEXTURE_SIZE, TEXTURE_SIZE)) .expect("Couldn't copy texture into window");
Finally, we update the window's display:
canvas.present();
So if we take a look at the full code, we now have the following:
extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::pixels::Color; use sdl2::rect::Rect; use sdl2::render::{Texture, TextureCreator}; use std::thread::sleep; use std::time::Duration; fn main() { let sdl_context = sdl2::init().expect("SDL initialization
failed"); let video_subsystem = sdl_context.video().expect("Couldn't get
SDL video subsystem"); // Parameters are: title, width, height let window = video_subsystem.window("Tetris", 800, 600) .position_centered() // to put it in the middle of the screen .build() // to create the window .expect("Failed to create window"); let mut canvas = window.into_canvas() .target_texture() .present_vsync() // To enable v-sync. .build() .expect("Couldn't get window's canvas"); let texture_creator: TextureCreator<_> =
canvas.texture_creator(); // To make things easier to read, we'll create a constant
which will be the texture's size. const TEXTURE_SIZE: u32 = 32; // We create a texture with a 32x32 size. let mut square_texture: Texture = texture_creator.create_texture_target(None, TEXTURE_SIZE,
TEXTURE_SIZE) .expect("Failed to create a texture"); // We use the canvas to draw into our square texture. canvas.with_texture_canvas(&mut square_texture, |texture| { // We set the draw color to green. texture.set_draw_color(Color::RGB(0, 255, 0)); // We "clear" our texture so it'll be fulfilled with green. texture.clear(); }).expect("Failed to color a texture"); // First we get the event handler: let mut event_pump = sdl_context.event_pump().expect("Failed
to get SDL event pump"); // Then we create an infinite loop to loop over events: 'running: loop { for event in event_pump.poll_iter() { match event { // If we receive a 'quit' event or if the user press the
'ESC' key, we quit. Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => { break 'running // We "break" the infinite loop. }, _ => {} } } // We set fulfill our window with red. canvas.set_draw_color(Color::RGB(255, 0, 0)); // We draw it. canvas.clear(); // Copy our texture into the window. canvas.copy(&square_texture, None, // We copy it at the top-left of the window with a 32x32 size. Rect::new(0, 0, TEXTURE_SIZE, TEXTURE_SIZE)) .expect("Couldn't copy texture into window"); // We update window's display. canvas.present(); // We sleep enough to get ~60 fps. If we don't call this,
the program will take // 100% of a CPU time. sleep(Duration::new(0, 1_000_000_000u32 / 60)); } }
If you run this code, you should have a red window with a small green rectangle at the top-left (just as shown in the following screenshot):

Figure 2.5
Now, what about switching the color of our small rectangle every second? Alright, first thing, we need to create another rectangle. To make things easier, we'll write a small function that will create texture.
As usual, add the following import at the top of your file:
use sdl2::video::{Window, WindowContext};
For convenience, we'll create a small enum to indicate the color as well:
#[derive(Clone, Copy)] enum TextureColor { Green, Blue, }
To make our lives easier, we'll handle errors outside of the next function, so no need to handle them directly here:
fn create_texture_rect<'a>(canvas: &mut Canvas<Window>, texture_creator: &'a TextureCreator<WindowContext>, color: TextureColor, size: u32) -> Option<Texture<'a>> { // We'll want to handle failures outside of this function. if let Ok(mut square_texture) = texture_creator.create_texture_target(None, size, size) { canvas.with_texture_canvas(&mut square_texture, |texture| { match color { TextureColor::Green =>
texture.set_draw_color(Color::RGB(0, 255, 0)), TextureColor::Blue =>
texture.set_draw_color(Color::RGB(0, 0, 255)), } texture.clear(); }).expect("Failed to color a texture"); Some(square_texture) } else { None } }
You'll note that the function returns an Option type, wrapping a texture. Option is an enum containing two variants: Some and None.
- 圖書館學(xué)是什么
- 公共圖書館動漫服務(wù)研究
- 單讀. 十周年特輯(時間的移民+在世界的門外)共2冊
- 公益 創(chuàng)新 服務(wù)
- 國際集郵聯(lián)合會(FIP)集郵展覽評審規(guī)則
- 基于價值全面實(shí)現(xiàn)的檔案信息資源配置
- 高校圖書館建設(shè)與知識管理
- 信息檢索
- 中外學(xué)術(shù)論文中英文摘要語料庫的創(chuàng)建及應(yīng)用
- 專利計量與專利合作
- 兒童閱讀的世界Ⅳ:學(xué)校、家庭與社區(qū)的實(shí)踐研究
- 電子文件長期保存:理論與實(shí)踐
- 電子文件管理與電子證據(jù)使用
- 北京大學(xué)中國古文獻(xiàn)研究中心集刊·第十七輯
- 人文通識講演錄:文學(xué)卷(二)