1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! Interactability might be important, but just sticking to regular shapes can get a bit boring. //! //! It's time for the wonderful world of images! Drawing images is almost the same as drawing //! colors, but instead of using `Background::Col` we use `Background::Img`. The big change to //! learn with images is asset loading. //! On desktop, you can make a blocking file load read, but that's not an option on web. This means //! that *all* Quicksilver asset loading is asynchronous, through the `Asset` system. //! ```no_run //! // Draw an image to the screen //! extern crate quicksilver; //! //! use quicksilver::{ //! Result, //! geom::{Shape, Vector}, //! graphics::{Background::Img, Color, Image}, // We need Image and image backgrounds //! lifecycle::{Asset, Settings, State, Window, run}, // To load anything, we need Asset //! }; //! //! struct ImageViewer { //! asset: Asset<Image>, // an image asset isn't state, but it does need to persist //! } //! //! impl State for ImageViewer { //! fn new() -> Result<ImageViewer> { //! let asset = Asset::new(Image::load("image.png")); // Start loading the asset //! Ok(ImageViewer { asset }) //! } //! //! fn draw(&mut self, window: &mut Window) -> Result<()> { //! window.clear(Color::WHITE)?; //! self.asset.execute(|image| { //! // If we've loaded the image, draw it //! window.draw(&image.area().with_center((400, 300)), Img(&image)); //! Ok(()) //! }) //! } //! } //! //! fn main() { //! run::<ImageViewer>("Image Example", Vector::new(800, 600), Settings { //! icon_path: Some("image.png"), // Set the window icon //! ..Settings::default() //! }); //! } //! ``` //! You'll notice we provided a path to `Image::load`, which was "image.png." This asset is stored //! in the `static` directory, not in the crate root. This is a current limitation of `cargo-web` //! and may be changed in the future, but for now all assets must be stored in `static.` You can //! use the [Quicksilver test //! image](https://github.com/ryanisaacg/quicksilver/blob/development/static/image.png). //! //! On the other hand, if you want to pack the Image data directly into the Rust binary, you can //! use `include_bytes!` and `Image::from_bytes`, which would look like //! `Image::from_bytes(include_bytes("path/to/my/image.png"))`. This has the advantage of allowing //! you to pack all your assets into one file, but also several disadvantages (such as needing to //! recompile the binary to edit the assets). Generally it is recommended to use the Asset system, //! but including the bytes is also an option. //! //! The asset system uses Futures, which are an asychronous programming concept. Basically, a //! Future is a computation that will complete at some point in, well, the future. For example, //! loading an image over a network is a future: the web browser doesn't have the image downloaded //! *yet* but it will (or it will produce an error.) //! //! This asset system is probably temporary, as async / await promise to be much more ergonomic //! methods of dealing with futures. However, Rust's async / await story isn't stable yet, so the //! Asset system is the most convenient way of loading things with Quicksilver. The execute //! function on an Asset runs the provided closure if loading is complete, with the actual asset //! data passed as a parameter. In the example above, the window is cleared every draw frame and //! once the image is loaded, it is drawn to the screen. //! //! Additionally, we now set the application icon path. The icon is also sourced from `static`, and //! determines the tab icon on the web and the window icon on desktop. //! //! Images can have subimages, which allows for spritesheets, texture atlases, and sprite batching: //! ```no_run //! // Draw an image to the screen //! extern crate quicksilver; //! //! use quicksilver::{ //! Future, Result, // We need the Future trait to operate on a future //! geom::{Rectangle, Shape, Vector}, //! graphics::{Background::Img, Color, Image}, //! lifecycle::{Asset, Settings, State, Window, run}, //! }; //! //! struct ImageViewer { //! asset: Asset<Image>, //! } //! //! impl State for ImageViewer { //! fn new() -> Result<ImageViewer> { //! let asset = Asset::new( //! Image::load("image.png") //! // Between the image loading and the asset being "done", take a slice from it //! .map(|image| image.subimage(Rectangle::new((0, 0), (32, 64)))) //! ); //! Ok(ImageViewer { asset }) //! } //! //! fn draw(&mut self, window: &mut Window) -> Result<()> { //! window.clear(Color::WHITE)?; //! self.asset.execute(|image| { //! // If we've loaded the image, draw it //! window.draw(&image.area().with_center((400, 300)), Img(&image)); //! Ok(()) //! }) //! } //! } //! //! fn main() { //! run::<ImageViewer>("Image Example", Vector::new(800, 600), Settings { //! icon_path: Some("image.png"), // Set the window icon //! ..Settings::default() //! }); //! } //! ``` //! Here `map` applies a transformation to the image after it is loaded; the ability to chain //! multiple assets together or apply complex operations to loading assets will be covered more in //! depth in the asset combinator tutorial.