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.