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
use super::{ColorFormat, Graphics, PixelFormat};
use crate::geom::Vector;
use crate::QuicksilverError;
use std::cell::{Ref, RefCell};
use std::path::Path;
use std::rc::Rc;
use golem::*;
/// A 2D image, stored on the GPU
///
/// See [`Graphics::draw_image`] to draw it
#[derive(Clone)]
pub struct Image(pub(crate) Rc<RefCell<Texture>>);
impl Image {
pub(crate) fn new(texture: Texture) -> Image {
Image(Rc::new(RefCell::new(texture)))
}
/// Create an image with a given width and height
///
/// Either source the data from an array of bytes, or create a blank image.
/// `format` determines how to interpet the bytes when creating the image
pub fn from_raw(
gfx: &Graphics,
data: Option<&[u8]>,
width: u32,
height: u32,
format: PixelFormat,
) -> Result<Image, GolemError> {
let mut texture = Texture::new(&gfx.ctx)?;
texture.set_image(data, width, height, format);
Ok(Image::new(texture))
}
/// Create an image from an encoded image format
///
/// JPEG and PNG are supported
pub fn from_encoded_bytes(gfx: &Graphics, raw: &[u8]) -> Result<Image, QuicksilverError> {
let img = image::load_from_memory(raw)?.to_rgba();
let width = img.width();
let height = img.height();
Ok(Image::from_raw(
gfx,
Some(img.into_raw().as_slice()),
width,
height,
PixelFormat::RGBA,
)?)
}
/// Load an image from a file at the given path
///
/// JPEG and PNG file formats are supported
pub async fn load(gfx: &Graphics, path: impl AsRef<Path>) -> Result<Image, QuicksilverError> {
let file_contents = platter::load_file(path).await?;
Image::from_encoded_bytes(gfx, file_contents.as_slice())
}
/// Replace the backing data for the image, or create a blank image
pub fn set_data(&mut self, data: Option<&[u8]>, width: u32, height: u32, color: ColorFormat) {
self.0.borrow_mut().set_image(data, width, height, color);
}
/// Set the data for some region of this image, without clearing it
pub fn set_sub_data(
&self,
data: &[u8],
x: u32,
y: u32,
width: u32,
height: u32,
color: ColorFormat,
) {
self.raw().set_subimage(data, x, y, width, height, color);
}
pub(crate) fn raw(&self) -> Ref<Texture> {
self.0.borrow()
}
pub(crate) fn ptr_eq(&self, other: &Image) -> bool {
Rc::ptr_eq(&self.0, &other.0)
}
/// Get the size of the image
pub fn size(&self) -> Vector {
Vector {
x: self.raw().width() as f32,
y: self.raw().height() as f32,
}
}
/// Determine how the texture should scale down
///
/// Only textures with a power-of-2 size support mipmaps, all others will return errors
pub fn set_minification(&self, min: TextureFilter) -> Result<(), QuicksilverError> {
Ok(self.raw().set_minification(min)?)
}
/// Determine how the texture should scale up
///
/// Attempting to use a mipmap filter for magnification will result in an error
pub fn set_magnification(&self, max: TextureFilter) -> Result<(), QuicksilverError> {
Ok(self.raw().set_magnification(max)?)
}
/// Determine how the texture is wrapped horizontally
///
/// Only textures with a power-of-2 size support texture wrapping, all others must ClampToEdge
/// or will return an error
pub fn set_wrap_h(&self, wrap: TextureWrap) -> Result<(), QuicksilverError> {
Ok(self.raw().set_wrap_h(wrap)?)
}
/// Determine how the texture is wrapped vertically
///
/// Only textures with a power-of-2 size support texture wrapping, all others must ClampToEdge
/// or will return an error
pub fn set_wrap_v(&self, wrap: TextureWrap) -> Result<(), QuicksilverError> {
Ok(self.raw().set_wrap_v(wrap)?)
}
pub(crate) fn into_raw(self) -> Result<Texture, Rc<RefCell<Texture>>> {
Ok(Rc::try_unwrap(self.0)?.into_inner())
}
}