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.