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/veridisquo.rs (line 221)
199 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
200 if self.base.forward_to_egui(core, event) {
201 return true;
202 }
203
204 if let WindowEvent::KeyboardInput { event, .. } = event {
205 if event.state == winit::event::ElementState::Pressed {
206 if let winit::keyboard::Key::Character(ref s) = event.logical_key {
207 if s.as_str() == "r" || s.as_str() == "R" {
208 self.base.start_time = std::time::Instant::now();
209 // Reset audio stream
210 if let Some(ref mut stream) = self.pcm_stream {
211 let _ = stream.stop();
212 let _ = stream.start();
213 }
214 return true;
215 }
216 }
217 }
218 return self
219 .base
220 .key_handler
221 .handle_keyboard_input(core.window(), event);
222 }
223
224 false
225 }More examples
examples/blockgame.rs (line 244)
208 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
209 let ui_handled = self.base.forward_to_egui(core, event);
210
211 if self.base.handle_mouse_input(core, event, ui_handled) {
212 return true;
213 }
214
215 if let WindowEvent::KeyboardInput { event, .. } = event {
216 if let winit::keyboard::PhysicalKey::Code(key_code) = event.physical_key {
217 if event.state == ElementState::Pressed {
218 let camera_speed = 0.5;
219
220 match key_code {
221 winit::keyboard::KeyCode::KeyQ => {
222 self.game_params.camera_height += camera_speed;
223 return true;
224 }
225 winit::keyboard::KeyCode::KeyE => {
226 self.game_params.camera_height -= camera_speed;
227 return true;
228 }
229 winit::keyboard::KeyCode::KeyW => {
230 self.game_params.camera_angle += 0.1;
231 return true;
232 }
233 winit::keyboard::KeyCode::KeyS => {
234 self.game_params.camera_angle -= 0.1;
235 return true;
236 }
237 _ => {}
238 }
239 }
240 }
241 return self
242 .base
243 .key_handler
244 .handle_keyboard_input(core.window(), event);
245 }
246
247 false
248 }examples/synth.rs (line 342)
302 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
303 if self.base.forward_to_egui(core, event) {
304 return true;
305 }
306
307 if let WindowEvent::KeyboardInput { event, .. } = event {
308 if let winit::keyboard::Key::Character(ref s) = event.logical_key {
309 if let Some(key_index) = s.chars().next().and_then(|c| c.to_digit(10)) {
310 if (1..=9).contains(&key_index) {
311 let index = (key_index - 1) as usize;
312
313 let current_time = self.base.controls.get_time(&self.base.start_time);
314 if event.state == winit::event::ElementState::Pressed && !self.keys_held[index] {
315 self.keys_held[index] = true;
316 let has_previous = self.current_params.key_states[index / 4][index % 4] > 0.0;
317 let in_release = self.current_params.key_decay[index / 4][index % 4] > 0.0;
318 if has_previous && in_release {
319 // Retrigger: just cancel the release, note continues from current level
320 self.set_key_release_time(index, 0.0);
321 } else {
322 // Fresh note
323 self.set_key_press_time(index, current_time);
324 self.set_key_release_time(index, 0.0);
325 }
326 self.compute_shader
327 .set_custom_params(self.current_params, &core.queue);
328 } else if event.state == winit::event::ElementState::Released {
329 self.keys_held[index] = false;
330 // Store release time — shader ADSR handles the fade
331 self.set_key_release_time(index, current_time);
332 self.compute_shader
333 .set_custom_params(self.current_params, &core.queue);
334 }
335 return true;
336 }
337 }
338 }
339 return self
340 .base
341 .key_handler
342 .handle_keyboard_input(core.window(), event);
343 }
344
345 false
346 }examples/gaussian3d.rs (line 437)
431 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
432 if self.base.forward_to_egui(core, event) {
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 661)
582 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
583 if self.base.forward_to_egui(core, event) {
584 return true;
585 }
586
587 if self.base.handle_mouse_input(core, event, false) {
588 return true;
589 }
590
591 if let WindowEvent::KeyboardInput { event, .. } = event {
592 if let winit::keyboard::Key::Character(ch) = &event.logical_key {
593 match ch.as_str() {
594 " " => {
595 if event.state == winit::event::ElementState::Released {
596 self.current_params.accumulate = 1 - self.current_params.accumulate;
597 self.should_reset_accumulation = true;
598 self.compute_shader
599 .set_custom_params(self.current_params, &core.queue);
600 return true;
601 }
602 }
603 "m" | "M" => {
604 if event.state == winit::event::ElementState::Released {
605 self.mouse_enabled = !self.mouse_enabled;
606 self.mouse_initialized = false;
607 return true;
608 }
609 }
610 "w" | "W" => {
611 if event.state == winit::event::ElementState::Pressed {
612 self.accumulated_rotation[1] -= 0.1;
613 self.should_reset_accumulation = true;
614 return true;
615 }
616 }
617 "s" | "S" => {
618 if event.state == winit::event::ElementState::Pressed {
619 self.accumulated_rotation[1] += 0.1;
620 self.should_reset_accumulation = true;
621 return true;
622 }
623 }
624 "a" | "A" => {
625 if event.state == winit::event::ElementState::Pressed {
626 self.accumulated_rotation[0] -= 0.1;
627 self.should_reset_accumulation = true;
628 return true;
629 }
630 }
631 "d" | "D" => {
632 if event.state == winit::event::ElementState::Pressed {
633 self.accumulated_rotation[0] += 0.1;
634 self.should_reset_accumulation = true;
635 return true;
636 }
637 }
638 "q" | "Q" => {
639 if event.state == winit::event::ElementState::Pressed {
640 self.accumulated_rotation[2] -= 0.1;
641 self.should_reset_accumulation = true;
642 return true;
643 }
644 }
645 "e" | "E" => {
646 if event.state == winit::event::ElementState::Pressed {
647 self.accumulated_rotation[2] += 0.1;
648 self.should_reset_accumulation = true;
649 return true;
650 }
651 }
652 _ => {}
653 }
654 }
655 }
656
657 if let WindowEvent::KeyboardInput { event, .. } = event {
658 if self
659 .base
660 .key_handler
661 .handle_keyboard_input(core.window(), event)
662 {
663 return true;
664 }
665 }
666
667 false
668 }examples/pathtracing.rs (line 544)
454 fn handle_input(&mut self, core: &Core, event: &WindowEvent) -> bool {
455 if self.base.forward_to_egui(core, event) {
456 return true;
457 }
458
459 if let WindowEvent::KeyboardInput { event, .. } = event {
460 if let winit::keyboard::Key::Character(ch) = &event.logical_key {
461 match ch.as_str() {
462 "w" | "W" => {
463 self.camera_movement.forward =
464 event.state == winit::event::ElementState::Pressed;
465 self.should_reset_accumulation = true;
466 return true;
467 }
468 "s" | "S" => {
469 self.camera_movement.backward =
470 event.state == winit::event::ElementState::Pressed;
471 self.should_reset_accumulation = true;
472 return true;
473 }
474 "a" | "A" => {
475 self.camera_movement.left =
476 event.state == winit::event::ElementState::Pressed;
477 self.should_reset_accumulation = true;
478 return true;
479 }
480 "d" | "D" => {
481 self.camera_movement.right =
482 event.state == winit::event::ElementState::Pressed;
483 self.should_reset_accumulation = true;
484 return true;
485 }
486 "q" | "Q" => {
487 self.camera_movement.down =
488 event.state == winit::event::ElementState::Pressed;
489 self.should_reset_accumulation = true;
490 return true;
491 }
492 "e" | "E" => {
493 self.camera_movement.up =
494 event.state == winit::event::ElementState::Pressed;
495 self.should_reset_accumulation = true;
496 return true;
497 }
498 " " => {
499 if event.state == winit::event::ElementState::Released {
500 self.current_params.accumulate = 1 - self.current_params.accumulate;
501 self.should_reset_accumulation = true;
502 self.compute_shader
503 .set_custom_params(self.current_params, &core.queue);
504 return true;
505 }
506 }
507 _ => {}
508 }
509 }
510 }
511
512 if let WindowEvent::CursorMoved { position, .. } = event {
513 let x = position.x as f32;
514 let y = position.y as f32;
515
516 self.base.handle_mouse_input(core, event, false);
517
518 if self.camera_movement.handle_mouse_movement(x, y) {
519 self.should_reset_accumulation = true;
520 return true;
521 }
522 }
523
524 if let WindowEvent::MouseInput { state, button, .. } = event {
525 if *button == winit::event::MouseButton::Right
526 && *state == winit::event::ElementState::Released
527 {
528 self.camera_movement.toggle_mouse_look();
529 return true;
530 }
531 }
532
533 if let WindowEvent::DroppedFile(path) = event {
534 if let Err(e) = self.base.load_media(core, path) {
535 error!("Failed to load dropped file: {e:?}");
536 }
537 return true;
538 }
539
540 if let WindowEvent::KeyboardInput { event, .. } = event {
541 if self
542 .base
543 .key_handler
544 .handle_keyboard_input(core.window(), event)
545 {
546 return true;
547 }
548 }
549
550 false
551 }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 }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