pub struct Core {
pub surface: Surface<'static>,
pub device: Arc<Device>,
pub queue: Queue,
pub config: SurfaceConfiguration,
pub size: PhysicalSize<u32>,
pub window: Window,
}Fields§
§surface: Surface<'static>§device: Arc<Device>§queue: Queue§config: SurfaceConfiguration§size: PhysicalSize<u32>§window: WindowImplementations§
Source§impl Core
impl Core
pub async fn new(window: Window) -> Self
Sourcepub fn window(&self) -> &Window
pub fn window(&self) -> &Window
Examples found in repository?
examples/fluidsim.rs (line 399)
398 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
399 if self.base.egui_state.on_window_event(core.window(), event).consumed {
400 return true;
401 }
402 if self.base.handle_mouse_input(core, event, false) {
403 if let WindowEvent::MouseInput { state, button, .. } = event {
404 if *button == winit::event::MouseButton::Left && state.is_pressed() {
405 self.current_color = Self::generate_color();
406 }
407 }
408 return true;
409 }
410
411 if let WindowEvent::KeyboardInput { event, .. } = event {
412 return self.base.key_handler.handle_keyboard_input(core.window(), event);
413 }
414
415 false
416 }More examples
examples/veridisquo.rs (line 203)
199 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
200 if self
201 .base
202 .egui_state
203 .on_window_event(core.window(), event)
204 .consumed
205 {
206 return true;
207 }
208
209 if let WindowEvent::KeyboardInput { event, .. } = event {
210 if event.state == winit::event::ElementState::Pressed {
211 if let winit::keyboard::Key::Character(ref s) = event.logical_key {
212 if s.as_str() == "r" || s.as_str() == "R" {
213 self.base.start_time = std::time::Instant::now();
214 // Reset audio stream
215 if let Some(ref mut stream) = self.pcm_stream {
216 let _ = stream.stop();
217 let _ = stream.start();
218 }
219 return true;
220 }
221 }
222 }
223 return self
224 .base
225 .key_handler
226 .handle_keyboard_input(core.window(), event);
227 }
228
229 false
230 }examples/blockgame.rs (line 212)
208 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
209 let ui_handled = self
210 .base
211 .egui_state
212 .on_window_event(core.window(), event)
213 .consumed;
214
215 if self.base.handle_mouse_input(core, event, ui_handled) {
216 return true;
217 }
218
219 if let WindowEvent::KeyboardInput { event, .. } = event {
220 if let winit::keyboard::PhysicalKey::Code(key_code) = event.physical_key {
221 if event.state == ElementState::Pressed {
222 let camera_speed = 0.5;
223
224 match key_code {
225 winit::keyboard::KeyCode::KeyQ => {
226 self.game_params.camera_height += camera_speed;
227 return true;
228 }
229 winit::keyboard::KeyCode::KeyE => {
230 self.game_params.camera_height -= camera_speed;
231 return true;
232 }
233 winit::keyboard::KeyCode::KeyW => {
234 self.game_params.camera_angle += 0.1;
235 return true;
236 }
237 winit::keyboard::KeyCode::KeyS => {
238 self.game_params.camera_angle -= 0.1;
239 return true;
240 }
241 _ => {}
242 }
243 }
244 }
245 return self
246 .base
247 .key_handler
248 .handle_keyboard_input(core.window(), event);
249 }
250
251 false
252 }examples/synth.rs (line 306)
302 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
303 if self
304 .base
305 .egui_state
306 .on_window_event(core.window(), event)
307 .consumed
308 {
309 return true;
310 }
311
312 if let WindowEvent::KeyboardInput { event, .. } = event {
313 if let winit::keyboard::Key::Character(ref s) = event.logical_key {
314 if let Some(key_index) = s.chars().next().and_then(|c| c.to_digit(10)) {
315 if (1..=9).contains(&key_index) {
316 let index = (key_index - 1) as usize;
317
318 let current_time = self.base.controls.get_time(&self.base.start_time);
319 if event.state == winit::event::ElementState::Pressed && !self.keys_held[index] {
320 self.keys_held[index] = true;
321 let has_previous = self.current_params.key_states[index / 4][index % 4] > 0.0;
322 let in_release = self.current_params.key_decay[index / 4][index % 4] > 0.0;
323 if has_previous && in_release {
324 // Retrigger: just cancel the release, note continues from current level
325 self.set_key_release_time(index, 0.0);
326 } else {
327 // Fresh note
328 self.set_key_press_time(index, current_time);
329 self.set_key_release_time(index, 0.0);
330 }
331 self.compute_shader
332 .set_custom_params(self.current_params, &core.queue);
333 } else if event.state == winit::event::ElementState::Released {
334 self.keys_held[index] = false;
335 // Store release time — shader ADSR handles the fade
336 self.set_key_release_time(index, current_time);
337 self.compute_shader
338 .set_custom_params(self.current_params, &core.queue);
339 }
340 return true;
341 }
342 }
343 }
344 return self
345 .base
346 .key_handler
347 .handle_keyboard_input(core.window(), event);
348 }
349
350 false
351 }examples/gaussian3d.rs (line 432)
431 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
432 if self.base.egui_state.on_window_event(core.window(), event).consumed {
433 return true;
434 }
435
436 if let WindowEvent::KeyboardInput { event, .. } = event {
437 if self.base.key_handler.handle_keyboard_input(core.window(), event) {
438 return true;
439 }
440 if let winit::keyboard::Key::Character(ch) = &event.logical_key {
441 let key = ch.as_str().to_lowercase();
442 match event.state {
443 winit::event::ElementState::Pressed => {
444 if key == "r" {
445 self.camera.reset();
446 self.sorter.force_sort();
447 return true;
448 }
449 if matches!(key.as_str(), "w" | "a" | "s" | "d" | "q" | "e") {
450 self.camera.keys_held.insert(key);
451 return true;
452 }
453 }
454 winit::event::ElementState::Released => {
455 self.camera.keys_held.remove(&key);
456 }
457 }
458 }
459 }
460
461 if let WindowEvent::MouseInput { state, button, .. } = event {
462 if *button == winit::event::MouseButton::Left {
463 self.camera.is_dragging = *state == winit::event::ElementState::Pressed;
464 return true;
465 }
466 }
467
468 if let WindowEvent::CursorMoved { position, .. } = event {
469 let x = position.x as f32;
470 let y = position.y as f32;
471 if self.camera.is_dragging {
472 let dx = x - self.camera.last_mouse[0];
473 let dy = y - self.camera.last_mouse[1];
474 self.camera.yaw += dx * 0.01;
475 self.camera.pitch = (self.camera.pitch + dy * 0.01).clamp(-1.5, 1.5);
476 }
477 self.camera.last_mouse = [x, y];
478 return self.camera.is_dragging;
479 }
480
481 if let WindowEvent::MouseWheel { delta, .. } = event {
482 let d = match delta {
483 winit::event::MouseScrollDelta::LineDelta(_, y) => *y,
484 winit::event::MouseScrollDelta::PixelDelta(p) => (p.y as f32 / 100.0).clamp(-3.0, 3.0)};
485 let factor = (1.0 + d * 0.1).clamp(0.5, 2.0);
486 self.camera.distance = (self.camera.distance * factor).clamp(0.1, 500.0);
487 return true;
488 }
489
490 if let WindowEvent::DroppedFile(path) = event {
491 if path.extension().map(|e| e == "ply").unwrap_or(false) {
492 self.load_ply(core, path);
493 }
494 return true;
495 }
496
497 false
498 }examples/mandelbulb.rs (line 586)
582 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
583 if self
584 .base
585 .egui_state
586 .on_window_event(core.window(), event)
587 .consumed
588 {
589 return true;
590 }
591
592 if self.base.handle_mouse_input(core, event, false) {
593 return true;
594 }
595
596 if let WindowEvent::KeyboardInput { event, .. } = event {
597 if let winit::keyboard::Key::Character(ch) = &event.logical_key {
598 match ch.as_str() {
599 " " => {
600 if event.state == winit::event::ElementState::Released {
601 self.current_params.accumulate = 1 - self.current_params.accumulate;
602 self.should_reset_accumulation = true;
603 self.compute_shader
604 .set_custom_params(self.current_params, &core.queue);
605 return true;
606 }
607 }
608 "m" | "M" => {
609 if event.state == winit::event::ElementState::Released {
610 self.mouse_enabled = !self.mouse_enabled;
611 self.mouse_initialized = false;
612 return true;
613 }
614 }
615 "w" | "W" => {
616 if event.state == winit::event::ElementState::Pressed {
617 self.accumulated_rotation[1] -= 0.1;
618 self.should_reset_accumulation = true;
619 return true;
620 }
621 }
622 "s" | "S" => {
623 if event.state == winit::event::ElementState::Pressed {
624 self.accumulated_rotation[1] += 0.1;
625 self.should_reset_accumulation = true;
626 return true;
627 }
628 }
629 "a" | "A" => {
630 if event.state == winit::event::ElementState::Pressed {
631 self.accumulated_rotation[0] -= 0.1;
632 self.should_reset_accumulation = true;
633 return true;
634 }
635 }
636 "d" | "D" => {
637 if event.state == winit::event::ElementState::Pressed {
638 self.accumulated_rotation[0] += 0.1;
639 self.should_reset_accumulation = true;
640 return true;
641 }
642 }
643 "q" | "Q" => {
644 if event.state == winit::event::ElementState::Pressed {
645 self.accumulated_rotation[2] -= 0.1;
646 self.should_reset_accumulation = true;
647 return true;
648 }
649 }
650 "e" | "E" => {
651 if event.state == winit::event::ElementState::Pressed {
652 self.accumulated_rotation[2] += 0.1;
653 self.should_reset_accumulation = true;
654 return true;
655 }
656 }
657 _ => {}
658 }
659 }
660 }
661
662 if let WindowEvent::KeyboardInput { event, .. } = event {
663 if self
664 .base
665 .key_handler
666 .handle_keyboard_input(core.window(), event)
667 {
668 return true;
669 }
670 }
671
672 false
673 }Additional examples can be found in:
pub fn resize(&mut self, new_size: PhysicalSize<u32>)
Sourcepub fn flush_encoder(&self, encoder: CommandEncoder) -> CommandEncoder
pub fn flush_encoder(&self, encoder: CommandEncoder) -> CommandEncoder
Submit the current encoder and create a new one.
Useful for multi-pass simulations where you need buffer updates to take effect before the next dispatch. wgpu batches all write_buffer calls before dispatches in the same submit, so this forces the GPU to see your changes.
Examples found in repository?
examples/gaussian3d.rs (line 394)
264 fn render(&mut self, core: &Core) -> Result<(), cuneus::SurfaceError> {
265 let output = match core.surface.get_current_texture() {
266 wgpu::CurrentSurfaceTexture::Success(texture)
267 | wgpu::CurrentSurfaceTexture::Suboptimal(texture) => texture,
268 wgpu::CurrentSurfaceTexture::Timeout
269 | wgpu::CurrentSurfaceTexture::Occluded => {
270 return Err(cuneus::SurfaceError::SkipFrame);
271 }
272 wgpu::CurrentSurfaceTexture::Outdated => {
273 return Err(cuneus::SurfaceError::Outdated);
274 }
275 wgpu::CurrentSurfaceTexture::Lost => {
276 return Err(cuneus::SurfaceError::Lost);
277 }
278 wgpu::CurrentSurfaceTexture::Validation => {
279 return Err(cuneus::SurfaceError::Lost);
280 }
281 };
282 let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
283
284 let mut params = self.params;
285 let mut changed = false;
286 let mut load_ply_path: Option<std::path::PathBuf> = None;
287 let mut should_start_export = false;
288 let mut export_request = self.base.export_manager.get_ui_request();
289 let mut controls_request = self.base.controls.get_ui_request(&self.base.start_time, &core.size, self.base.fps_tracker.fps());
290
291 let full_output = if self.base.key_handler.show_ui {
292 self.base.render_ui(core, |ctx| {
293 RenderKit::apply_default_style(ctx);
294
295 egui::Window::new("3D Gaussian Splatting")
296 .collapsible(true)
297 .resizable(true)
298 .default_width(300.0)
299 .show(ctx, |ui| {
300 if params.num_gaussians > 0 {
301 ui.label(format!("Gaussians: {}", params.num_gaussians));
302 } else {
303 ui.label("Drag & drop a .ply file");
304 }
305 ui.small("WASD: move | QE: up/down | R: reset | Drag: rotate");
306
307 if ui.button("Load PLY...").clicked() {
308 if let Some(p) = rfd::FileDialog::new().add_filter("PLY", &["ply"]).pick_file() {
309 load_ply_path = Some(p);
310 }
311 }
312
313 ui.separator();
314
315 egui::CollapsingHeader::new("Visual Settings")
316 .default_open(true)
317 .show(ui, |ui| {
318 changed |= ui.add(egui::Slider::new(&mut params.scene_scale, 0.01..=100.0)
319 .logarithmic(true).text("Scene Scale")).changed();
320 changed |= ui.add(egui::Slider::new(&mut params.gaussian_size, 0.1..=2.0)
321 .text("Gaussian Size")).changed();
322 changed |= ui.add(egui::Slider::new(&mut params.gamma, 0.1..=2.2)
323 .text("Gamma")).changed();
324
325 let mut depth_shift_f = params.depth_shift as f32;
326 if ui.add(egui::Slider::new(&mut depth_shift_f, 1.0..=30.0)
327 .step_by(1.0)
328 .text("Depth Blur")).changed() {
329 params.depth_shift = depth_shift_f as u32;
330 changed = true;
331 }
332 });
333
334 egui::CollapsingHeader::new("Camera Settings")
335 .default_open(false)
336 .show(ui, |ui| {
337 changed |= ui.add(egui::Slider::new(&mut self.camera.distance, 0.1..=100.0)
338 .logarithmic(true).text("Distance")).changed();
339 changed |= ui.add(egui::Slider::new(&mut self.camera.fov, 20.0..=120.0)
340 .text("FOV")).changed();
341 changed |= ui.add(egui::DragValue::new(&mut self.camera.yaw)
342 .speed(0.05).prefix("Yaw: ")).changed();
343 changed |= ui.add(egui::Slider::new(&mut self.camera.pitch, -1.5..=1.5)
344 .text("Pitch")).changed();
345
346 if ui.button("Reset Camera").clicked() {
347 self.camera.reset();
348 changed = true;
349 }
350 });
351
352 ui.separator();
353 ShaderControls::render_controls_widget(ui, &mut controls_request);
354
355 ui.separator();
356 should_start_export =
357 ExportManager::render_export_ui_widget(ui, &mut export_request);
358 });
359 })
360 } else {
361 self.base.render_ui(core, |_ctx| {})
362 };
363
364 self.base.export_manager.apply_ui_request(export_request);
365 self.base.apply_control_request(controls_request);
366
367 if should_start_export {
368 self.base.export_manager.start_export();
369 }
370
371 if let Some(path) = load_ply_path {
372 self.load_ply(core, &path);
373 }
374 if changed {
375 self.params = params;
376 self.sync_params(core);
377 }
378
379 let mut encoder = core.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
380 label: Some("Gaussian3D")});
381
382 let count = self.params.num_gaussians;
383 if count > 0 && self.render_bind_group.is_some() {
384 self.update_camera(core);
385
386 // Compute preprocess
387 let workgroups = (count + 255) / 256;
388 self.preprocess.dispatch_stage_with_workgroups(&mut encoder, 0, [workgroups, 1, 1]);
389
390 // GPU Radix Sort
391 self.sorter.sort(&mut encoder, count);
392
393 // Split submission: submit preprocess+sort, start new encoder for render
394 encoder = core.flush_encoder(encoder);
395
396 // Fragment render
397 {
398 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
399 label: Some("Gaussian Render"),
400 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
401 view: &view,
402 resolve_target: None,
403 ops: wgpu::Operations {
404 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
405 store: wgpu::StoreOp::Store},
406 depth_slice: None})],
407 ..Default::default()
408 });
409 self.renderer.render(&mut pass, self.render_bind_group.as_ref().unwrap(), count);
410 }
411 } else {
412 let _pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
413 label: Some("Clear"),
414 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
415 view: &view,
416 resolve_target: None,
417 ops: wgpu::Operations {
418 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
419 store: wgpu::StoreOp::Store},
420 depth_slice: None})],
421 ..Default::default()
422 });
423 }
424
425 self.base.handle_render_output(core, &view, full_output, &mut encoder);
426 core.queue.submit(Some(encoder.finish()));
427 output.present();
428 Ok(())
429 }More examples
examples/fluidsim.rs (line 254)
209 fn render(&mut self, core: &Core) -> Result<(), cuneus::SurfaceError> {
210 let mut frame = self.base.begin_frame(core)?;
211
212 // Update params
213 self.compute_shader.set_custom_params(self.params, &core.queue);
214
215 let sim_workgroups = [
216 self.params.sim_width.div_ceil(16),
217 self.params.sim_height.div_ceil(16),
218 1,
219 ];
220 let display_workgroups = [
221 self.params.display_width.div_ceil(16),
222 self.params.display_height.div_ceil(16),
223 1,
224 ];
225 let output_workgroups = [
226 core.size.width.div_ceil(16),
227 core.size.height.div_ceil(16),
228 1,
229 ];
230
231 // Stage indices
232 const CLEAR_BUFFERS: usize = 0;
233 const SPLAT_VELOCITY: usize = 1;
234 const SPLAT_DYE: usize = 2;
235 const CURL_COMPUTE: usize = 3;
236 const VORTICITY_APPLY: usize = 4;
237 const DIVERGENCE_COMPUTE: usize = 5;
238 const PRESSURE_CLEAR: usize = 6;
239 const PRESSURE_ITERATE: usize = 7;
240 const GRADIENT_SUBTRACT: usize = 8;
241 const ADVECT_VELOCITY: usize = 9;
242 const ADVECT_DYE: usize = 10;
243 const MAIN_IMAGE: usize = 11;
244
245
246 if self.needs_clear {
247 self.needs_clear = false;
248 let max_workgroups = [
249 self.params.display_width.div_ceil(16),
250 self.params.display_height.div_ceil(16),
251 1,
252 ];
253 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, CLEAR_BUFFERS, max_workgroups);
254 frame.encoder = core.flush_encoder(frame.encoder);
255 self.compute_shader.set_custom_params(self.params, &core.queue);
256 }
257
258 // Apply splat (additive, in-place on current read buffer)
259 if self.params.do_splat == 1 {
260 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, SPLAT_VELOCITY, sim_workgroups);
261 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, SPLAT_DYE, display_workgroups);
262 }
263
264 // Curl: reads vel[vel_ping]
265 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, CURL_COMPUTE, sim_workgroups);
266
267 // Vorticity: reads vel[vel_ping], writes vel[1-vel_ping]
268 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, VORTICITY_APPLY, sim_workgroups);
269
270 // Submit before changing ping
271 frame.encoder = core.flush_encoder(frame.encoder);
272 self.params.vel_ping = 1 - self.params.vel_ping;
273 self.compute_shader.set_custom_params(self.params, &core.queue);
274
275 // Divergence: reads vel[vel_ping] (where vorticity wrote)
276 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, DIVERGENCE_COMPUTE, sim_workgroups);
277
278 // Pressure clear: reads prs[prs_ping], writes prs[1-prs_ping]
279 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, PRESSURE_CLEAR, sim_workgroups);
280
281 frame.encoder = core.flush_encoder(frame.encoder);
282 self.params.prs_ping = 1 - self.params.prs_ping;
283 self.compute_shader.set_custom_params(self.params, &core.queue);
284
285 // Jacobi solver
286 for _ in 0..PRESSURE_ITERATIONS {
287 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, PRESSURE_ITERATE, sim_workgroups);
288 frame.encoder = core.flush_encoder(frame.encoder);
289 self.params.prs_ping = 1 - self.params.prs_ping;
290 self.compute_shader.set_custom_params(self.params, &core.queue);
291 }
292
293 // Gradient subtract: reads vel[vel_ping], prs[prs_ping], writes vel[1-vel_ping]
294 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, GRADIENT_SUBTRACT, sim_workgroups);
295
296 frame.encoder = core.flush_encoder(frame.encoder);
297 self.params.vel_ping = 1 - self.params.vel_ping;
298 self.compute_shader.set_custom_params(self.params, &core.queue);
299
300 // Advect velocity: reads vel[vel_ping], writes vel[1-vel_ping]
301 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, ADVECT_VELOCITY, sim_workgroups);
302
303 frame.encoder = core.flush_encoder(frame.encoder);
304 self.params.vel_ping = 1 - self.params.vel_ping;
305 self.compute_shader.set_custom_params(self.params, &core.queue);
306
307 // Advect dye: reads vel[vel_ping], dye[dye_ping], writes dye[1-dye_ping]
308 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, ADVECT_DYE, display_workgroups);
309
310 frame.encoder = core.flush_encoder(frame.encoder);
311 self.params.dye_ping = 1 - self.params.dye_ping;
312 self.compute_shader.set_custom_params(self.params, &core.queue);
313
314 // Display: reads dye[dye_ping]
315 self.compute_shader.dispatch_stage_with_workgroups(&mut frame.encoder, MAIN_IMAGE, output_workgroups);
316
317 self.base.renderer.render_to_view(&mut frame.encoder, &frame.view, &self.compute_shader.get_output_texture().bind_group);
318
319 let mut params = self.params;
320 let mut should_clear = false;
321 let mut should_start_export = false;
322 let mut export_request = self.base.export_manager.get_ui_request();
323 let mut controls_request = self.base.controls.get_ui_request(&self.base.start_time, &core.size, self.base.fps_tracker.fps());
324
325 let full_output = if self.base.key_handler.show_ui {
326 self.base.render_ui(core, |ctx| {
327 ctx.global_style_mut(|style| {
328 style.visuals.window_fill = egui::Color32::from_rgba_premultiplied(0, 0, 0, 180);
329 style.text_styles.get_mut(&egui::TextStyle::Body).unwrap().size = 11.0;
330 style.text_styles.get_mut(&egui::TextStyle::Button).unwrap().size = 10.0;
331 });
332
333 egui::Window::new("Fluid Simulation")
334 .collapsible(true)
335 .resizable(true)
336 .default_width(280.0)
337 .show(ctx, |ui| {
338 egui::CollapsingHeader::new("Fluid Parameters")
339 .default_open(true)
340 .show(ui, |ui| {
341 ui.add(egui::Slider::new(&mut params.curl_strength, 0.0..=50.0).text("Vorticity"));
342 ui.add(egui::Slider::new(&mut params.velocity_dissipation, 0.0..=4.0).text("Vel Dissipation"));
343 ui.add(egui::Slider::new(&mut params.density_dissipation, 0.0..=4.0).text("Dye Dissipation"));
344 ui.add(egui::Slider::new(&mut params.pressure, 0.0..=1.0).text("Pressure"));
345 });
346
347 egui::CollapsingHeader::new("Splat Settings")
348 .default_open(false)
349 .show(ui, |ui| {
350 ui.add(egui::Slider::new(&mut params.splat_radius, 0.01..=1.0).text("Radius"));
351 ui.add(egui::Slider::new(&mut params.splat_force, 1000.0..=20000.0).text("Force"));
352 });
353
354 ui.separator();
355 ShaderControls::render_controls_widget(ui, &mut controls_request);
356
357 ui.separator();
358 should_start_export = ExportManager::render_export_ui_widget(ui, &mut export_request);
359
360 ui.separator();
361 if ui.button("Clear Fluid").clicked() {
362 should_clear = true;
363 }
364 ui.label(format!("Internal: {}x{}", INTERNAL_WIDTH, INTERNAL_HEIGHT));
365 ui.label("Drag mouse to add fluid");
366 });
367 })
368 } else {
369 self.base.render_ui(core, |_| {})
370 };
371
372 if controls_request.should_clear_buffers || should_clear {
373 self.params.vel_ping = 0;
374 self.params.prs_ping = 0;
375 self.params.dye_ping = 0;
376 self.first_frame = true;
377 self.needs_clear = true;
378 }
379
380 // Apply UI changes
381 self.base.apply_control_request(controls_request);
382 self.base.export_manager.apply_ui_request(export_request);
383 self.params = params;
384
385 if should_start_export {
386 self.base.export_manager.start_export();
387 }
388
389 self.base.end_frame(core, frame, full_output);
390
391 Ok(())
392 }Auto Trait Implementations§
impl !Freeze for Core
impl !RefUnwindSafe for Core
impl Send for Core
impl Sync for Core
impl Unpin for Core
impl UnsafeUnpin for Core
impl !UnwindSafe for Core
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more