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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use std::collections::HashMap;
use std::path::PathBuf;
use failure::Error;
use webrender::api::{RenderApi, ResourceUpdates, ExternalImageId, ExternalImageData, ImageKey, ImageFormat, ImageData, ImageDescriptor};
use image::{self, ImageError, DynamicImage, GenericImage};
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub enum ImageSource {
AbsolutePath(PathBuf),
AssetPath(PathBuf),
Bundled(String),
}
impl ImageSource {
pub fn absolute<P: Into<PathBuf>>(path: P) -> Self {
ImageSource::AbsolutePath(path.into())
}
pub fn asset<P: Into<PathBuf>>(path: P) -> Self {
ImageSource::AssetPath(path.into())
}
pub fn bundled<P: Into<String>>(name: P) -> Self {
ImageSource::Bundled(name.into())
}
}
#[derive(Debug, Clone)]
pub struct ImageInfo {
pub key: ImageKey,
pub descriptor: ImageDescriptor,
}
#[derive(Debug, Fail)]
#[fail(display = "missing bundled image {}", name)]
struct BundledImageMissingError {
name: String,
}
#[derive(Default)]
pub struct ImageLoader {
pub render: Option<RenderApi>,
pub assets_path: PathBuf,
pub bundled_images: HashMap<ImageSource, ImageInfo>,
pub images: HashMap<ImageSource, ImageInfo>,
pub texture_descriptors: HashMap<u64, ImageDescriptor>,
}
impl ImageLoader {
pub fn new() -> Self {
ImageLoader::default()
}
pub fn get_image(&mut self, source: &ImageSource) -> Result<&ImageInfo, Error> {
let image = self.get_image_internal(source);
if let Err(ref error) = image {
error!("Failed to load image from source {:?}. {}", source, error);
}
image
}
fn get_image_internal(&mut self, source: &ImageSource) -> Result<&ImageInfo, Error> {
if self.images.contains_key(source) {
Ok(&self.images[source])
} else {
let (data, descriptor) = match *source {
ImageSource::AbsolutePath(ref path) => {
prepare_image(image::open(&path)?)?
},
ImageSource::AssetPath(ref relative_path) => {
let mut path = PathBuf::from(&self.assets_path);
path.push(relative_path);
prepare_image(image::open(&path)?)?
},
ImageSource::Bundled(ref name) => {
return Err(BundledImageMissingError { name: name.to_owned() }.into())
}
};
Ok(self.put_image(source, data, descriptor))
}
}
fn put_image(&mut self, source: &ImageSource, data: ImageData, descriptor: ImageDescriptor) -> &ImageInfo {
let image_info = self.create_image_resource(data, descriptor);
self.images.insert(source.clone(), image_info);
&self.images[source]
}
pub fn create_image_resource(&mut self, data: ImageData, descriptor: ImageDescriptor) -> ImageInfo {
let key = self.render_api().generate_image_key();
let mut resources = ResourceUpdates::new();
resources.add_image(key, descriptor, data, None);
self.render_api().update_resources(resources);
ImageInfo { key: key, descriptor: descriptor }
}
pub fn update_texture(&mut self, key: ImageKey, descriptor: ImageDescriptor, data: ExternalImageData) {
let mut resources = ResourceUpdates::new();
resources.update_image(key, descriptor, ImageData::External(data), None);
self.render_api().update_resources(resources);
let ExternalImageData { id: ExternalImageId(texture_id), .. } = data;
self.texture_descriptors.insert(texture_id, descriptor);
}
pub fn load_image(&mut self, name: &str, data: Vec<u8>) {
if let Err(error) = self.load_image_internal(name, data) {
error!("Failed to load image from raw data {}", error);
}
}
fn load_image_internal(&mut self, name: &str, data: Vec<u8>) -> Result<(), Error> {
let (data, descriptor) = prepare_image(image::load_from_memory(&data)?)?;
let image_info = self.create_image_resource(data, descriptor);
self.images.insert(ImageSource::bundled(name), image_info);
Ok(())
}
fn render_api(&self) -> &RenderApi {
self.render.as_ref().unwrap()
}
}
fn prepare_image(image: DynamicImage) -> Result<(ImageData, ImageDescriptor), Error> {
let image_dims = image.dimensions();
let format = match image {
image::ImageLuma8(_) => ImageFormat::R8,
image::ImageRgba8(_) => ImageFormat::BGRA8,
_ => {
return Err(ImageError::UnsupportedError("ImageFormat unsupported".to_string()).into());
}
};
let mut bytes = image.raw_pixels();
if format == ImageFormat::BGRA8 {
premultiply(bytes.as_mut_slice());
}
let opaque = is_image_opaque(format, &bytes[..]);
let descriptor = ImageDescriptor::new(image_dims.0, image_dims.1, format, opaque);
let data = ImageData::new(bytes);
Ok((data, descriptor))
}
fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool {
match format {
ImageFormat::BGRA8 => {
let mut is_opaque = true;
for i in 0..(bytes.len() / 4) {
if bytes[i * 4 + 3] != 255 {
is_opaque = false;
break;
}
}
is_opaque
}
ImageFormat::R8 => true,
_ => unreachable!(),
}
}
pub fn premultiply(data: &mut [u8]) {
for pixel in data.chunks_mut(4) {
let a = u32::from(pixel[3]);
let r = u32::from(pixel[2]);
let g = u32::from(pixel[1]);
let b = u32::from(pixel[0]);
pixel[3] = a as u8;
pixel[2] = ((r * a + 128) / 255) as u8;
pixel[1] = ((g * a + 128) / 255) as u8;
pixel[0] = ((b * a + 128) / 255) as u8;
}
}