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
120
121
122
123
124
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
use crate::graphics::gpu::{self, Texture};
use crate::graphics::{Color, Gpu, IntoQuad, Target};
use crate::load::Task;
use crate::Result;
/// A loaded image.
///
/// You can use this to load your spritesheets and draw your sprites!
///
/// Cloning an [`Image`] is cheap, it only clones a handle. It does not
/// create a new copy of the image on the GPU.
///
/// [`Image`]: struct.Image.html
#[derive(Clone)]
pub struct Image {
pub(super) texture: Texture,
}
impl Image {
/// Loads an [`Image`] from the given path.
///
/// [`Image`]: struct.Image.html
pub fn new<P: AsRef<Path>>(gpu: &mut Gpu, path: P) -> Result<Image> {
let image = {
let mut buf = Vec::new();
let mut reader = File::open(path)?;
let _ = reader.read_to_end(&mut buf)?;
image::load_from_memory(&buf)?
};
Image::from_image(gpu, &image)
}
/// Creates a [`Task`] that loads an [`Image`] from the given path.
///
/// [`Task`]: ../load/struct.Task.html
/// [`Image`]: struct.Image.html
pub fn load<P: Into<PathBuf>>(path: P) -> Task<Image> {
let p = path.into();
Task::using_gpu(move |gpu| Image::new(gpu, &p))
}
/// Creates an [`Image`] from a [`DynamicImage`] of the [`image` crate].
///
/// [`Image`]: struct.Image.html
/// [`DynamicImage`]: https://docs.rs/image/0.21.1/image/enum.DynamicImage.html
/// [`image` crate]: https://docs.rs/image
pub fn from_image(
gpu: &mut Gpu,
image: &image::DynamicImage,
) -> Result<Image> {
let texture = gpu.upload_texture(&image);
Ok(Image { texture })
}
/// Creates an [`Image`] representing a color palette.
///
/// Each [`Color`] will be a pixel of the image, arranged horizontally.
///
/// [`Image`]: struct.Image.html
/// [`Color`]: struct.Color.html
pub fn from_colors(gpu: &mut Gpu, colors: &[Color]) -> Result<Image> {
let colors: Vec<[u8; 4]> =
colors.iter().map(|color| color.to_rgba()).collect();
Self::from_image(
gpu,
&image::DynamicImage::ImageRgba8(
image::RgbaImage::from_raw(
colors.len() as u32,
1,
colors.iter().flatten().cloned().collect(),
)
.unwrap(),
),
)
}
/// Returns the width of the [`Image`].
///
/// [`Image`]: struct.Image.html
pub fn width(&self) -> u16 {
self.texture.width()
}
/// Returns the height of the [`Image`].
///
/// [`Image`]: struct.Image.html
pub fn height(&self) -> u16 {
self.texture.height()
}
/// Draws the [`Image`] on the given [`Target`].
///
/// [`Image`]: struct.Image.html
/// [`Target`]: struct.Target.html
#[inline]
pub fn draw<Q: IntoQuad>(&self, quad: Q, target: &mut Target<'_>) {
target.draw_texture_quads(
&self.texture,
&[gpu::Quad::from(quad.into_quad(
1.0 / self.width() as f32,
1.0 / self.height() as f32,
))],
);
}
}
impl std::fmt::Debug for Image {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Image {{ width: {}, height: {} }}",
self.width(),
self.height()
)
}
}