官术网_书友最值得收藏!

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.

主站蜘蛛池模板: 定兴县| 成安县| 泸西县| 富川| 泸水县| 葫芦岛市| 略阳县| 吉安县| 谢通门县| 深水埗区| 凤凰县| 涞源县| 藁城市| 长葛市| 晴隆县| 五寨县| 江西省| 威宁| 溧阳市| 嘉荫县| 忻城县| 神池县| 嵊州市| 富锦市| 锦州市| 镇沅| 囊谦县| 外汇| 延寿县| 定襄县| 林芝县| 淄博市| 大同县| 浪卡子县| 政和县| 斗六市| 鸡东县| 东兴市| 黑河市| 武冈市| 孝义市|