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
impl Image
Sourcepub fn from_file_with_format(
bytes: &[u8],
format: Option<ImageFormat>,
) -> Result<Image, Error>
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?
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}
Sourcepub fn gen_image_color(width: u16, height: u16, color: Color) -> Image
pub fn gen_image_color(width: u16, height: u16, color: Color) -> Image
Creates an Image filled with the provided Color.
Examples found in repository?
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
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}
Sourcepub const fn width(&self) -> usize
pub const fn width(&self) -> usize
Returns the width of this image.
Examples found in repository?
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}
Sourcepub const fn height(&self) -> usize
pub const fn height(&self) -> usize
Returns the height of this image.
Examples found in repository?
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}
Sourcepub fn get_image_data(&self) -> &[[u8; 4]]
pub fn get_image_data(&self) -> &[[u8; 4]]
Returns this image’s data as a slice of 4-byte arrays.
Sourcepub fn get_image_data_mut(&mut self) -> &mut [[u8; 4]]
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?
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}
Sourcepub fn set_pixel(&mut self, x: u32, y: u32, color: Color)
pub fn set_pixel(&mut self, x: u32, y: u32, color: Color)
Modifies a pixel Color in this image.
Examples found in repository?
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}
Sourcepub fn get_pixel(&self, x: u32, y: u32) -> Color
pub fn get_pixel(&self, x: u32, y: u32) -> Color
Returns a pixel Color from this image.
Examples found in repository?
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}
Sourcepub fn blend(&mut self, other: &Image)
pub fn blend(&mut self, other: &Image)
Blends this image with another image (of identical dimensions) Inspired by OpenCV saturated blending
Sourcepub fn overlay(&mut self, other: &Image)
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.
Sourcepub fn export_png(&self, path: &str)
pub fn export_png(&self, path: &str)
Saves this image as a PNG file. This method is not supported on web and will panic.