Struct Image

Source
pub struct Image {
    pub bytes: Vec<u8>,
    pub width: u16,
    pub height: u16,
}
Expand description

Image, data stored in CPU memory

Fields§

§bytes: Vec<u8>§width: u16§height: u16

Implementations§

Source§

impl Image

Source

pub const fn empty() -> Image

Creates an empty Image.

let image = Image::empty();
Source

pub fn from_file_with_format( bytes: &[u8], format: Option<ImageFormat>, ) -> Result<Image, Error>

Creates an Image from a slice of bytes that contains an encoded image.

If format is None, it will make an educated guess on the ImageFormat.

§Example
let icon = Image::from_file_with_format(
    include_bytes!("../examples/rust.png"),
    Some(ImageFormat::Png),
    );
Examples found in repository?
examples/ui_skins.rs (lines 22-25)
6async fn main() {
7    let skin1 = {
8        let font = load_ttf_font("examples/ui_assets/HTOWERT.TTF")
9            .await
10            .unwrap();
11        let label_style = root_ui()
12            .style_builder()
13            .with_font(&font)
14            .unwrap()
15            .text_color(Color::from_rgba(180, 180, 120, 255))
16            .font_size(30)
17            .build();
18
19        let window_style = root_ui()
20            .style_builder()
21            .background(
22                Image::from_file_with_format(
23                    include_bytes!("../examples/ui_assets/window_background.png"),
24                    None,
25                )
26                .unwrap(),
27            )
28            .background_margin(RectOffset::new(20.0, 20.0, 10.0, 10.0))
29            .margin(RectOffset::new(-20.0, -30.0, 0.0, 0.0))
30            .build();
31
32        let button_style = root_ui()
33            .style_builder()
34            .background(
35                Image::from_file_with_format(
36                    include_bytes!("../examples/ui_assets/button_background.png"),
37                    None,
38                )
39                .unwrap(),
40            )
41            .background_margin(RectOffset::new(37.0, 37.0, 5.0, 5.0))
42            .margin(RectOffset::new(10.0, 10.0, 0.0, 0.0))
43            .background_hovered(
44                Image::from_file_with_format(
45                    include_bytes!("../examples/ui_assets/button_hovered_background.png"),
46                    None,
47                )
48                .unwrap(),
49            )
50            .background_clicked(
51                Image::from_file_with_format(
52                    include_bytes!("../examples/ui_assets/button_clicked_background.png"),
53                    None,
54                )
55                .unwrap(),
56            )
57            .with_font(&font)
58            .unwrap()
59            .text_color(Color::from_rgba(180, 180, 100, 255))
60            .font_size(40)
61            .build();
62
63        let editbox_style = root_ui()
64            .style_builder()
65            .background_margin(RectOffset::new(0., 0., 0., 0.))
66            .with_font(&font)
67            .unwrap()
68            .text_color(Color::from_rgba(120, 120, 120, 255))
69            .color_selected(Color::from_rgba(190, 190, 190, 255))
70            .font_size(50)
71            .build();
72
73        Skin {
74            editbox_style,
75            window_style,
76            button_style,
77            label_style,
78            ..root_ui().default_skin()
79        }
80    };
81
82    let skin2 = {
83        let font = load_ttf_font("examples/ui_assets/MinimalPixel v2.ttf")
84            .await
85            .unwrap();
86        let label_style = root_ui()
87            .style_builder()
88            .with_font(&font)
89            .unwrap()
90            .text_color(Color::from_rgba(120, 120, 120, 255))
91            .font_size(25)
92            .build();
93
94        let window_style = root_ui()
95            .style_builder()
96            .background(
97                Image::from_file_with_format(
98                    include_bytes!("../examples/ui_assets/window_background_2.png"),
99                    None,
100                )
101                .unwrap(),
102            )
103            .background_margin(RectOffset::new(52.0, 52.0, 52.0, 52.0))
104            .margin(RectOffset::new(-30.0, 0.0, -30.0, 0.0))
105            .build();
106
107        let button_style = root_ui()
108            .style_builder()
109            .background(
110                Image::from_file_with_format(
111                    include_bytes!("../examples/ui_assets/button_background_2.png"),
112                    None,
113                )
114                .unwrap(),
115            )
116            .background_margin(RectOffset::new(8.0, 8.0, 8.0, 8.0))
117            .background_hovered(
118                Image::from_file_with_format(
119                    include_bytes!("../examples/ui_assets/button_hovered_background_2.png"),
120                    None,
121                )
122                .unwrap(),
123            )
124            .background_clicked(
125                Image::from_file_with_format(
126                    include_bytes!("../examples/ui_assets/button_clicked_background_2.png"),
127                    None,
128                )
129                .unwrap(),
130            )
131            .with_font(&font)
132            .unwrap()
133            .text_color(Color::from_rgba(180, 180, 100, 255))
134            .font_size(40)
135            .build();
136
137        let checkbox_style = root_ui()
138            .style_builder()
139            .background(
140                Image::from_file_with_format(
141                    include_bytes!("../examples/ui_assets/checkbox_background.png"),
142                    None,
143                )
144                .unwrap(),
145            )
146            .background_hovered(
147                Image::from_file_with_format(
148                    include_bytes!("../examples/ui_assets/checkbox_hovered_background.png"),
149                    None,
150                )
151                .unwrap(),
152            )
153            .background_clicked(
154                Image::from_file_with_format(
155                    include_bytes!("../examples/ui_assets/checkbox_clicked_background.png"),
156                    None,
157                )
158                .unwrap(),
159            )
160            .build();
161
162        let editbox_style = root_ui()
163            .style_builder()
164            .background(
165                Image::from_file_with_format(
166                    include_bytes!("../examples/ui_assets/editbox_background.png"),
167                    None,
168                )
169                .unwrap(),
170            )
171            .background_margin(RectOffset::new(2., 2., 2., 2.))
172            .with_font(&font)
173            .unwrap()
174            .text_color(Color::from_rgba(120, 120, 120, 255))
175            .font_size(25)
176            .build();
177
178        let combobox_style = root_ui()
179            .style_builder()
180            .background(
181                Image::from_file_with_format(
182                    include_bytes!("../examples/ui_assets/combobox_background.png"),
183                    None,
184                )
185                .unwrap(),
186            )
187            .background_margin(RectOffset::new(4., 25., 6., 6.))
188            .with_font(&font)
189            .unwrap()
190            .text_color(Color::from_rgba(120, 120, 120, 255))
191            .color(Color::from_rgba(210, 210, 210, 255))
192            .font_size(25)
193            .build();
194
195        Skin {
196            window_style,
197            button_style,
198            label_style,
199            checkbox_style,
200            editbox_style,
201            combobox_style,
202            ..root_ui().default_skin()
203        }
204    };
205    let default_skin = root_ui().default_skin().clone();
206
207    let mut window1_skin = skin1.clone();
208    let mut window2_skin = skin2.clone();
209
210    let mut checkbox = false;
211    let mut text = String::new();
212    let mut number = 0.0f32;
213    let mut combobox = 0;
214
215    loop {
216        clear_background(GRAY);
217
218        root_ui().group(hash!(), vec2(70.0, 100.0), |ui| {
219            ui.label(None, "Window 1");
220
221            if ui.button(None, "Skin 1") {
222                window1_skin = skin1.clone();
223            }
224            if ui.button(None, "Skin 2") {
225                window1_skin = skin2.clone();
226            }
227            if ui.button(None, "No Skin") {
228                window1_skin = default_skin.clone();
229            }
230        });
231        root_ui().same_line(0.);
232        root_ui().group(hash!(), vec2(70.0, 100.0), |ui| {
233            ui.label(None, "Window 2");
234            if ui.button(None, "Skin 1") {
235                window2_skin = skin1.clone();
236            }
237            if ui.button(None, "Skin 2") {
238                window2_skin = skin2.clone();
239            }
240            if ui.button(None, "No Skin") {
241                window2_skin = default_skin.clone();
242            }
243        });
244
245        root_ui().push_skin(&window1_skin);
246
247        root_ui().window(hash!(), vec2(20., 250.), vec2(300., 300.), |ui| {
248            widgets::Button::new("Play")
249                .position(vec2(65.0, 15.0))
250                .ui(ui);
251            widgets::Button::new("Options")
252                .position(vec2(40.0, 75.0))
253                .ui(ui);
254
255            widgets::Button::new("Quit")
256                .position(vec2(65.0, 195.0))
257                .ui(ui);
258        });
259        root_ui().pop_skin();
260
261        root_ui().push_skin(&window2_skin);
262        root_ui().window(hash!(), vec2(250., 20.), vec2(500., 250.), |ui| {
263            ui.checkbox(hash!(), "Checkbox 1", &mut checkbox);
264            ui.combo_box(
265                hash!(),
266                "Combobox",
267                &["First option", "Second option"],
268                &mut combobox,
269            );
270            ui.input_text(hash!(), "Text", &mut text);
271            ui.drag(hash!(), "Drag", None, &mut number);
272
273            widgets::Button::new("Apply")
274                .position(vec2(80.0, 150.0))
275                .ui(ui);
276            widgets::Button::new("Cancel")
277                .position(vec2(280.0, 150.0))
278                .ui(ui);
279        });
280        root_ui().pop_skin();
281
282        next_frame().await;
283    }
284}
Source

pub fn gen_image_color(width: u16, height: u16, color: Color) -> Image

Creates an Image filled with the provided Color.

Examples found in repository?
examples/shadertoy.rs (line 31)
28fn color_picker_texture(w: usize, h: usize) -> (Texture2D, Image) {
29    let ratio = 1.0 / h as f32;
30
31    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
32    let image_data = image.get_image_data_mut();
33
34    for j in 0..h {
35        for i in 0..w {
36            let lightness = 1.0 - i as f32 * ratio;
37            let hue = j as f32 * ratio;
38
39            image_data[i + j * w] = color::hsl_to_rgb(hue, 1.0, lightness).into();
40        }
41    }
42
43    (Texture2D::from_image(&image), image)
44}
More examples
Hide additional examples
examples/life.rs (line 17)
10async fn main() {
11    let w = screen_width() as usize;
12    let h = screen_height() as usize;
13
14    let mut cells = vec![CellState::Dead; w * h];
15    let mut buffer = vec![CellState::Dead; w * h];
16
17    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
18
19    for cell in cells.iter_mut() {
20        if rand::gen_range(0, 5) == 0 {
21            *cell = CellState::Alive;
22        }
23    }
24    let texture = Texture2D::from_image(&image);
25
26    loop {
27        clear_background(WHITE);
28
29        let w = image.width();
30        let h = image.height();
31
32        for y in 0..h as i32 {
33            for x in 0..w as i32 {
34                let mut neighbors_count = 0;
35
36                for j in -1i32..=1 {
37                    for i in -1i32..=1 {
38                        // out of bounds
39                        if y + j < 0 || y + j >= h as i32 || x + i < 0 || x + i >= w as i32 {
40                            continue;
41                        }
42                        // cell itself
43                        if i == 0 && j == 0 {
44                            continue;
45                        }
46
47                        let neighbor = cells[(y + j) as usize * w + (x + i) as usize];
48                        if neighbor == CellState::Alive {
49                            neighbors_count += 1;
50                        }
51                    }
52                }
53
54                let current_cell = cells[y as usize * w + x as usize];
55                buffer[y as usize * w + x as usize] = match (current_cell, neighbors_count) {
56                    // Rule 1: Any live cell with fewer than two live neighbours
57                    // dies, as if caused by underpopulation.
58                    (CellState::Alive, x) if x < 2 => CellState::Dead,
59                    // Rule 2: Any live cell with two or three live neighbours
60                    // lives on to the next generation.
61                    (CellState::Alive, 2) | (CellState::Alive, 3) => CellState::Alive,
62                    // Rule 3: Any live cell with more than three live
63                    // neighbours dies, as if by overpopulation.
64                    (CellState::Alive, x) if x > 3 => CellState::Dead,
65                    // Rule 4: Any dead cell with exactly three live neighbours
66                    // becomes a live cell, as if by reproduction.
67                    (CellState::Dead, 3) => CellState::Alive,
68                    // All other cells remain in the same state.
69                    (otherwise, _) => otherwise,
70                };
71            }
72        }
73
74        for i in 0..buffer.len() {
75            cells[i] = buffer[i];
76
77            image.set_pixel(
78                (i % w) as u32,
79                (i / w) as u32,
80                match buffer[i as usize] {
81                    CellState::Alive => BLACK,
82                    CellState::Dead => WHITE,
83                },
84            );
85        }
86
87        texture.update(&image);
88
89        draw_texture(&texture, 0., 0., WHITE);
90
91        next_frame().await
92    }
93}
Source

pub fn update(&mut self, colors: &[Color])

Updates this image from a slice of Colors.

Source

pub const fn width(&self) -> usize

Returns the width of this image.

Examples found in repository?
examples/life.rs (line 29)
10async fn main() {
11    let w = screen_width() as usize;
12    let h = screen_height() as usize;
13
14    let mut cells = vec![CellState::Dead; w * h];
15    let mut buffer = vec![CellState::Dead; w * h];
16
17    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
18
19    for cell in cells.iter_mut() {
20        if rand::gen_range(0, 5) == 0 {
21            *cell = CellState::Alive;
22        }
23    }
24    let texture = Texture2D::from_image(&image);
25
26    loop {
27        clear_background(WHITE);
28
29        let w = image.width();
30        let h = image.height();
31
32        for y in 0..h as i32 {
33            for x in 0..w as i32 {
34                let mut neighbors_count = 0;
35
36                for j in -1i32..=1 {
37                    for i in -1i32..=1 {
38                        // out of bounds
39                        if y + j < 0 || y + j >= h as i32 || x + i < 0 || x + i >= w as i32 {
40                            continue;
41                        }
42                        // cell itself
43                        if i == 0 && j == 0 {
44                            continue;
45                        }
46
47                        let neighbor = cells[(y + j) as usize * w + (x + i) as usize];
48                        if neighbor == CellState::Alive {
49                            neighbors_count += 1;
50                        }
51                    }
52                }
53
54                let current_cell = cells[y as usize * w + x as usize];
55                buffer[y as usize * w + x as usize] = match (current_cell, neighbors_count) {
56                    // Rule 1: Any live cell with fewer than two live neighbours
57                    // dies, as if caused by underpopulation.
58                    (CellState::Alive, x) if x < 2 => CellState::Dead,
59                    // Rule 2: Any live cell with two or three live neighbours
60                    // lives on to the next generation.
61                    (CellState::Alive, 2) | (CellState::Alive, 3) => CellState::Alive,
62                    // Rule 3: Any live cell with more than three live
63                    // neighbours dies, as if by overpopulation.
64                    (CellState::Alive, x) if x > 3 => CellState::Dead,
65                    // Rule 4: Any dead cell with exactly three live neighbours
66                    // becomes a live cell, as if by reproduction.
67                    (CellState::Dead, 3) => CellState::Alive,
68                    // All other cells remain in the same state.
69                    (otherwise, _) => otherwise,
70                };
71            }
72        }
73
74        for i in 0..buffer.len() {
75            cells[i] = buffer[i];
76
77            image.set_pixel(
78                (i % w) as u32,
79                (i / w) as u32,
80                match buffer[i as usize] {
81                    CellState::Alive => BLACK,
82                    CellState::Dead => WHITE,
83                },
84            );
85        }
86
87        texture.update(&image);
88
89        draw_texture(&texture, 0., 0., WHITE);
90
91        next_frame().await
92    }
93}
Source

pub const fn height(&self) -> usize

Returns the height of this image.

Examples found in repository?
examples/life.rs (line 30)
10async fn main() {
11    let w = screen_width() as usize;
12    let h = screen_height() as usize;
13
14    let mut cells = vec![CellState::Dead; w * h];
15    let mut buffer = vec![CellState::Dead; w * h];
16
17    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
18
19    for cell in cells.iter_mut() {
20        if rand::gen_range(0, 5) == 0 {
21            *cell = CellState::Alive;
22        }
23    }
24    let texture = Texture2D::from_image(&image);
25
26    loop {
27        clear_background(WHITE);
28
29        let w = image.width();
30        let h = image.height();
31
32        for y in 0..h as i32 {
33            for x in 0..w as i32 {
34                let mut neighbors_count = 0;
35
36                for j in -1i32..=1 {
37                    for i in -1i32..=1 {
38                        // out of bounds
39                        if y + j < 0 || y + j >= h as i32 || x + i < 0 || x + i >= w as i32 {
40                            continue;
41                        }
42                        // cell itself
43                        if i == 0 && j == 0 {
44                            continue;
45                        }
46
47                        let neighbor = cells[(y + j) as usize * w + (x + i) as usize];
48                        if neighbor == CellState::Alive {
49                            neighbors_count += 1;
50                        }
51                    }
52                }
53
54                let current_cell = cells[y as usize * w + x as usize];
55                buffer[y as usize * w + x as usize] = match (current_cell, neighbors_count) {
56                    // Rule 1: Any live cell with fewer than two live neighbours
57                    // dies, as if caused by underpopulation.
58                    (CellState::Alive, x) if x < 2 => CellState::Dead,
59                    // Rule 2: Any live cell with two or three live neighbours
60                    // lives on to the next generation.
61                    (CellState::Alive, 2) | (CellState::Alive, 3) => CellState::Alive,
62                    // Rule 3: Any live cell with more than three live
63                    // neighbours dies, as if by overpopulation.
64                    (CellState::Alive, x) if x > 3 => CellState::Dead,
65                    // Rule 4: Any dead cell with exactly three live neighbours
66                    // becomes a live cell, as if by reproduction.
67                    (CellState::Dead, 3) => CellState::Alive,
68                    // All other cells remain in the same state.
69                    (otherwise, _) => otherwise,
70                };
71            }
72        }
73
74        for i in 0..buffer.len() {
75            cells[i] = buffer[i];
76
77            image.set_pixel(
78                (i % w) as u32,
79                (i / w) as u32,
80                match buffer[i as usize] {
81                    CellState::Alive => BLACK,
82                    CellState::Dead => WHITE,
83                },
84            );
85        }
86
87        texture.update(&image);
88
89        draw_texture(&texture, 0., 0., WHITE);
90
91        next_frame().await
92    }
93}
Source

pub fn get_image_data(&self) -> &[[u8; 4]]

Returns this image’s data as a slice of 4-byte arrays.

Source

pub fn get_image_data_mut(&mut self) -> &mut [[u8; 4]]

Returns this image’s data as a mutable slice of 4-byte arrays.

Examples found in repository?
examples/shadertoy.rs (line 32)
28fn color_picker_texture(w: usize, h: usize) -> (Texture2D, Image) {
29    let ratio = 1.0 / h as f32;
30
31    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
32    let image_data = image.get_image_data_mut();
33
34    for j in 0..h {
35        for i in 0..w {
36            let lightness = 1.0 - i as f32 * ratio;
37            let hue = j as f32 * ratio;
38
39            image_data[i + j * w] = color::hsl_to_rgb(hue, 1.0, lightness).into();
40        }
41    }
42
43    (Texture2D::from_image(&image), image)
44}
Source

pub fn set_pixel(&mut self, x: u32, y: u32, color: Color)

Modifies a pixel Color in this image.

Examples found in repository?
examples/life.rs (lines 77-84)
10async fn main() {
11    let w = screen_width() as usize;
12    let h = screen_height() as usize;
13
14    let mut cells = vec![CellState::Dead; w * h];
15    let mut buffer = vec![CellState::Dead; w * h];
16
17    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
18
19    for cell in cells.iter_mut() {
20        if rand::gen_range(0, 5) == 0 {
21            *cell = CellState::Alive;
22        }
23    }
24    let texture = Texture2D::from_image(&image);
25
26    loop {
27        clear_background(WHITE);
28
29        let w = image.width();
30        let h = image.height();
31
32        for y in 0..h as i32 {
33            for x in 0..w as i32 {
34                let mut neighbors_count = 0;
35
36                for j in -1i32..=1 {
37                    for i in -1i32..=1 {
38                        // out of bounds
39                        if y + j < 0 || y + j >= h as i32 || x + i < 0 || x + i >= w as i32 {
40                            continue;
41                        }
42                        // cell itself
43                        if i == 0 && j == 0 {
44                            continue;
45                        }
46
47                        let neighbor = cells[(y + j) as usize * w + (x + i) as usize];
48                        if neighbor == CellState::Alive {
49                            neighbors_count += 1;
50                        }
51                    }
52                }
53
54                let current_cell = cells[y as usize * w + x as usize];
55                buffer[y as usize * w + x as usize] = match (current_cell, neighbors_count) {
56                    // Rule 1: Any live cell with fewer than two live neighbours
57                    // dies, as if caused by underpopulation.
58                    (CellState::Alive, x) if x < 2 => CellState::Dead,
59                    // Rule 2: Any live cell with two or three live neighbours
60                    // lives on to the next generation.
61                    (CellState::Alive, 2) | (CellState::Alive, 3) => CellState::Alive,
62                    // Rule 3: Any live cell with more than three live
63                    // neighbours dies, as if by overpopulation.
64                    (CellState::Alive, x) if x > 3 => CellState::Dead,
65                    // Rule 4: Any dead cell with exactly three live neighbours
66                    // becomes a live cell, as if by reproduction.
67                    (CellState::Dead, 3) => CellState::Alive,
68                    // All other cells remain in the same state.
69                    (otherwise, _) => otherwise,
70                };
71            }
72        }
73
74        for i in 0..buffer.len() {
75            cells[i] = buffer[i];
76
77            image.set_pixel(
78                (i % w) as u32,
79                (i / w) as u32,
80                match buffer[i as usize] {
81                    CellState::Alive => BLACK,
82                    CellState::Dead => WHITE,
83                },
84            );
85        }
86
87        texture.update(&image);
88
89        draw_texture(&texture, 0., 0., WHITE);
90
91        next_frame().await
92    }
93}
Source

pub fn get_pixel(&self, x: u32, y: u32) -> Color

Returns a pixel Color from this image.

Examples found in repository?
examples/shadertoy.rs (line 304)
47async fn main() {
48    let ferris = load_texture("examples/rust.png").await.unwrap();
49    let (color_picker_texture, color_picker_image) = color_picker_texture(200, 200);
50
51    let mut fragment_shader = DEFAULT_FRAGMENT_SHADER.to_string();
52    let mut vertex_shader = DEFAULT_VERTEX_SHADER.to_string();
53
54    let pipeline_params = PipelineParams {
55        depth_write: true,
56        depth_test: Comparison::LessOrEqual,
57        ..Default::default()
58    };
59
60    let mut material = load_material(
61        ShaderSource::Glsl {
62            vertex: &vertex_shader,
63            fragment: &fragment_shader,
64        },
65        MaterialParams {
66            pipeline_params,
67            ..Default::default()
68        },
69    )
70    .unwrap();
71    let mut error: Option<String> = None;
72
73    enum Mesh {
74        Sphere,
75        Cube,
76        Plane,
77    }
78    let mut mesh = Mesh::Sphere;
79
80    let mut camera = Camera3D {
81        position: vec3(-15., 15., -5.),
82        up: vec3(0., 1., 0.),
83        target: vec3(0., 5., -5.),
84        ..Default::default()
85    };
86
87    let mut colorpicker_window = false;
88    let mut color_picking_uniform = None;
89
90    let mut new_uniform_window = false;
91    let mut new_uniform_name = String::new();
92    let mut uniforms: Vec<(String, Uniform)> = vec![];
93
94    loop {
95        clear_background(WHITE);
96
97        set_camera(&camera);
98
99        draw_grid(
100            20,
101            1.,
102            Color::new(0.55, 0.55, 0.55, 0.75),
103            Color::new(0.75, 0.75, 0.75, 0.75),
104        );
105
106        gl_use_material(&material);
107        match mesh {
108            Mesh::Plane => draw_plane(vec3(0., 2., 0.), vec2(5., 5.), Some(&ferris), WHITE),
109            Mesh::Sphere => draw_sphere(vec3(0., 6., 0.), 5., Some(&ferris), WHITE),
110            Mesh::Cube => draw_cube(vec3(0., 5., 0.), vec3(10., 10., 10.), Some(&ferris), WHITE),
111        }
112        gl_use_default_material();
113
114        set_default_camera();
115
116        let mut need_update = false;
117
118        widgets::Window::new(hash!(), vec2(20., 20.), vec2(470., 650.))
119            .label("Shader")
120            .ui(&mut *root_ui(), |ui| {
121                ui.label(None, "Camera: ");
122                ui.same_line(0.0);
123                if ui.button(None, "Ortho") {
124                    camera.projection = Projection::Orthographics;
125                }
126                ui.same_line(0.0);
127                if ui.button(None, "Perspective") {
128                    camera.projection = Projection::Perspective;
129                }
130                ui.label(None, "Mesh: ");
131                ui.same_line(0.0);
132                if ui.button(None, "Sphere") {
133                    mesh = Mesh::Sphere;
134                }
135                ui.same_line(0.0);
136                if ui.button(None, "Cube") {
137                    mesh = Mesh::Cube;
138                }
139                ui.same_line(0.0);
140                if ui.button(None, "Plane") {
141                    mesh = Mesh::Plane;
142                }
143
144                ui.label(None, "Uniforms:");
145                ui.separator();
146
147                for (i, (name, uniform)) in uniforms.iter_mut().enumerate() {
148                    ui.label(None, &format!("{name}"));
149                    ui.same_line(120.0);
150
151                    match uniform {
152                        Uniform::Float1(x) => {
153                            widgets::InputText::new(hash!(hash!(), i))
154                                .size(vec2(200.0, 19.0))
155                                .filter_numbers()
156                                .ui(ui, x);
157
158                            if let Ok(x) = x.parse::<f32>() {
159                                material.set_uniform(name, x);
160                            }
161                        }
162                        Uniform::Float2(x, y) => {
163                            widgets::InputText::new(hash!(hash!(), i))
164                                .size(vec2(99.0, 19.0))
165                                .filter_numbers()
166                                .ui(ui, x);
167
168                            ui.same_line(0.0);
169
170                            widgets::InputText::new(hash!(hash!(), i))
171                                .size(vec2(99.0, 19.0))
172                                .filter_numbers()
173                                .ui(ui, y);
174
175                            if let (Ok(x), Ok(y)) = (x.parse::<f32>(), y.parse::<f32>()) {
176                                material.set_uniform(name, (x, y));
177                            }
178                        }
179                        Uniform::Float3(x, y, z) => {
180                            widgets::InputText::new(hash!(hash!(), i))
181                                .size(vec2(65.0, 19.0))
182                                .filter_numbers()
183                                .ui(ui, x);
184
185                            ui.same_line(0.0);
186
187                            widgets::InputText::new(hash!(hash!(), i))
188                                .size(vec2(65.0, 19.0))
189                                .filter_numbers()
190                                .ui(ui, y);
191
192                            ui.same_line(0.0);
193
194                            widgets::InputText::new(hash!(hash!(), i))
195                                .size(vec2(65.0, 19.0))
196                                .filter_numbers()
197                                .ui(ui, z);
198
199                            if let (Ok(x), Ok(y), Ok(z)) =
200                                (x.parse::<f32>(), y.parse::<f32>(), z.parse::<f32>())
201                            {
202                                material.set_uniform(name, (x, y, z));
203                            }
204                        }
205
206                        Uniform::Color(color) => {
207                            let mut canvas = ui.canvas();
208
209                            let cursor = canvas.cursor();
210
211                            canvas.rect(
212                                Rect::new(cursor.x + 20.0, cursor.y, 50.0, 18.0),
213                                Color::new(0.2, 0.2, 0.2, 1.0),
214                                Color::new(color.x, color.y, color.z, 1.0),
215                            );
216
217                            if ui.button(None, "change") {
218                                colorpicker_window = true;
219                                color_picking_uniform = Some(name.to_owned());
220                            }
221                            material.set_uniform(name, (color.x, color.y, color.z));
222                        }
223                    }
224                }
225                ui.separator();
226                if ui.button(None, "New uniform") {
227                    new_uniform_window = true;
228                }
229                TreeNode::new(hash!(), "Fragment shader")
230                    .init_unfolded()
231                    .ui(ui, |ui| {
232                        if ui.editbox(hash!(), vec2(440., 200.), &mut fragment_shader) {
233                            need_update = true;
234                        };
235                    });
236                ui.tree_node(hash!(), "Vertex shader", |ui| {
237                    if ui.editbox(hash!(), vec2(440., 300.), &mut vertex_shader) {
238                        need_update = true;
239                    };
240                });
241
242                if let Some(ref error) = error {
243                    Label::new(error).multiline(14.0).ui(ui);
244                }
245            });
246
247        if new_uniform_window {
248            widgets::Window::new(hash!(), vec2(100., 100.), vec2(200., 80.))
249                .label("New uniform")
250                .ui(&mut *root_ui(), |ui| {
251                    if ui.active_window_focused() == false {
252                        new_uniform_window = false;
253                    }
254                    ui.input_text(hash!(), "Name", &mut new_uniform_name);
255                    let uniform_type = ui.combo_box(
256                        hash!(),
257                        "Type",
258                        &["Float1", "Float2", "Float3", "Color"],
259                        None,
260                    );
261
262                    if ui.button(None, "Add") {
263                        if new_uniform_name.is_empty() == false {
264                            let uniform = match uniform_type {
265                                0 => Uniform::Float1("0".to_string()),
266                                1 => Uniform::Float2("0".to_string(), "0".to_string()),
267                                2 => Uniform::Float3(
268                                    "0".to_string(),
269                                    "0".to_string(),
270                                    "0".to_string(),
271                                ),
272                                3 => Uniform::Color(vec3(0.0, 0.0, 0.0)),
273                                _ => unreachable!(),
274                            };
275                            uniforms.push((new_uniform_name.clone(), uniform));
276                            new_uniform_name.clear();
277                            need_update = true;
278                        }
279                        new_uniform_window = false;
280                    }
281
282                    ui.same_line(0.0);
283                    if ui.button(None, "Cancel") {
284                        new_uniform_window = false;
285                    }
286                });
287        }
288
289        if colorpicker_window {
290            colorpicker_window &= widgets::Window::new(hash!(), vec2(140., 100.), vec2(210., 240.))
291                .label("Colorpicker")
292                .ui(&mut *root_ui(), |ui| {
293                    if ui.active_window_focused() == false {
294                        colorpicker_window = false;
295                    }
296
297                    let mut canvas = ui.canvas();
298                    let cursor = canvas.cursor();
299                    let mouse = mouse_position();
300                    let x = mouse.0 as i32 - cursor.x as i32;
301                    let y = mouse.1 as i32 - (cursor.y as i32 + 20);
302
303                    let color = color_picker_image
304                        .get_pixel(x.max(0).min(199) as u32, y.max(0).min(199) as u32);
305
306                    canvas.rect(
307                        Rect::new(cursor.x, cursor.y, 200.0, 18.0),
308                        Color::new(0.0, 0.0, 0.0, 1.0),
309                        Color::new(color.r, color.g, color.b, 1.0),
310                    );
311                    canvas.image(
312                        Rect::new(cursor.x, cursor.y + 20.0, 200.0, 200.0),
313                        &color_picker_texture,
314                    );
315
316                    if x >= 0 && x < 200 && y >= 0 && y < 200 {
317                        canvas.rect(
318                            Rect::new(mouse.0 - 3.5, mouse.1 - 3.5, 7.0, 7.0),
319                            Color::new(0.3, 0.3, 0.3, 1.0),
320                            Color::new(1.0, 1.0, 1.0, 1.0),
321                        );
322
323                        if is_mouse_button_down(MouseButton::Left) {
324                            colorpicker_window = false;
325                            let uniform_name = color_picking_uniform.take().unwrap();
326
327                            uniforms
328                                .iter_mut()
329                                .find(|(name, _)| name == &uniform_name)
330                                .unwrap()
331                                .1 = Uniform::Color(vec3(color.r, color.g, color.b));
332                        }
333                    }
334                });
335        }
336
337        if need_update {
338            let uniforms = uniforms
339                .iter()
340                .map(|(name, uniform)| UniformDesc::new(name, uniform.uniform_type()))
341                .collect::<Vec<_>>();
342
343            match load_material(
344                ShaderSource::Glsl {
345                    vertex: &vertex_shader,
346                    fragment: &fragment_shader,
347                },
348                MaterialParams {
349                    pipeline_params,
350                    uniforms,
351                    textures: vec![],
352                },
353            ) {
354                Ok(new_material) => {
355                    material = new_material;
356                    error = None;
357                }
358                Err(err) => {
359                    error = Some(format!("{err:#?}"));
360                }
361            }
362        }
363
364        next_frame().await
365    }
366}
Source

pub fn sub_image(&self, rect: Rect) -> Image

Returns an Image from a rect inside this image.

Source

pub fn blend(&mut self, other: &Image)

Blends this image with another image (of identical dimensions) Inspired by OpenCV saturated blending

Source

pub fn overlay(&mut self, other: &Image)

Overlays an image on top of this one. Slightly different from blending two images, overlaying a completely transparent image has no effect on the original image, though blending them would.

Source

pub fn export_png(&self, path: &str)

Saves this image as a PNG file. This method is not supported on web and will panic.

Trait Implementations§

Source§

impl Clone for Image

Source§

fn clone(&self) -> Image

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Image

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Image

§

impl RefUnwindSafe for Image

§

impl Send for Image

§

impl Sync for Image

§

impl Unpin for Image

§

impl UnwindSafe for Image

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,