1use crate::color::Color;
2use gizmo_core::{Entity, EntityName, World};
13use gizmo_math::{Quat, Vec3};
14use gizmo_physics_core::{Collider, Transform};
15use gizmo_physics_rigid::components::{RigidBody, Velocity};
16use gizmo_renderer::{
17 asset::AssetManager,
18 components::{Camera, DirectionalLight, Material, MeshRenderer, PointLight},
19 Renderer,
20};
21
22pub struct Commands<'a> {
25 pub world: &'a mut World,
26 pub renderer: &'a Renderer,
27 pub asset_manager: Option<AssetManager>,
28}
29
30impl<'a> Drop for Commands<'a> {
31 fn drop(&mut self) {
32 if let Some(am) = self.asset_manager.take() {
33 self.world.insert_resource(am);
34 }
35 }
36}
37
38impl<'a> Commands<'a> {
39 pub fn new(world: &'a mut World, renderer: &'a Renderer) -> Self {
40 let am = world.remove_resource::<AssetManager>().unwrap_or_default();
41 Self {
42 world,
43 renderer,
44 asset_manager: Some(am),
45 }
46 }
47
48 pub fn spawn_cube(&mut self, pos: Vec3, color: Color) -> EntityBuilder<'_, 'a> {
52 let mesh = AssetManager::create_cube(&self.renderer.device);
53 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
54 &self.renderer.device,
55 &self.renderer.queue,
56 &self.renderer.scene.texture_bind_group_layout,
57 );
58 let mat = Material::new(bg).with_unlit(color.to_vec4());
59 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
60 EntityBuilder {
61 commands: self,
62 entity: id,
63 }
64 }
65
66 pub fn spawn_sphere(&mut self, pos: Vec3, radius: f32, color: Color) -> EntityBuilder<'_, 'a> {
68 let mesh = AssetManager::create_sphere(&self.renderer.device, radius, 20, 20);
69 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
70 &self.renderer.device,
71 &self.renderer.queue,
72 &self.renderer.scene.texture_bind_group_layout,
73 );
74 let mat = Material::new(bg).with_unlit(color.to_vec4());
75 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
76 EntityBuilder {
77 commands: self,
78 entity: id,
79 }
80 }
81
82 pub fn spawn_plane(&mut self, pos: Vec3, size: f32, color: Color) -> EntityBuilder<'_, 'a> {
84 let mesh = AssetManager::create_plane(&self.renderer.device, size);
85 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
86 &self.renderer.device,
87 &self.renderer.queue,
88 &self.renderer.scene.texture_bind_group_layout,
89 );
90 let mat = Material::new(bg).with_unlit(color.to_vec4());
91 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
92 EntityBuilder {
93 commands: self,
94 entity: id,
95 }
96 }
97
98 pub fn spawn_model(&mut self, pos: Vec3, path: &str) -> EntityBuilder<'_, 'a> {
100 let mesh = self
101 .asset_manager
102 .as_mut()
103 .unwrap()
104 .load_obj(&self.renderer.device, path);
105 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
106 &self.renderer.device,
107 &self.renderer.queue,
108 &self.renderer.scene.texture_bind_group_layout,
109 );
110 let mat = Material::new(bg);
111 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
112 EntityBuilder {
113 commands: self,
114 entity: id,
115 }
116 }
117
118 pub fn spawn_camera(&mut self, pos: Vec3) -> EntityBuilder<'_, 'a> {
123 if let Some(mut cameras) = self.world.query::<gizmo_core::prelude::Mut<Camera>>() {
124 for (_, mut c) in cameras.iter_mut() {
125 c.primary = false;
126 }
127 }
128 let id = self.world.spawn();
129 let trans = Transform::new(pos);
130
131 self.world.add_component(id, trans);
132 self.world.add_component(
133 id,
134 Camera {
135 fov: 60.0_f32.to_radians(),
136 near: 0.1,
137 far: 1000.0,
138 yaw: -std::f32::consts::FRAC_PI_2,
139 pitch: 0.0,
140 primary: true,
141 },
142 );
143 EntityBuilder {
144 commands: self,
145 entity: id,
146 }
147 }
148
149 pub fn spawn_camera_with(
151 &mut self,
152 pos: Vec3,
153 fov_deg: f32,
154 near: f32,
155 far: f32,
156 ) -> EntityBuilder<'_, 'a> {
157 if let Some(mut cameras) = self.world.query::<gizmo_core::prelude::Mut<Camera>>() {
158 for (_, mut c) in cameras.iter_mut() {
159 c.primary = false;
160 }
161 }
162 let id = self.world.spawn();
163 let trans = Transform::new(pos);
164
165 self.world.add_component(id, trans);
166 self.world.add_component(
167 id,
168 Camera {
169 fov: fov_deg.to_radians(),
170 near,
171 far,
172 yaw: -std::f32::consts::FRAC_PI_2,
173 pitch: 0.0,
174 primary: true,
175 },
176 );
177 EntityBuilder {
178 commands: self,
179 entity: id,
180 }
181 }
182
183 pub fn spawn_point_light(
187 &mut self,
188 pos: Vec3,
189 color: Color,
190 intensity: f32,
191 ) -> EntityBuilder<'_, 'a> {
192 let id = self.world.spawn();
193 let trans = Transform::new(pos);
194
195 self.world.add_component(id, trans);
196 self.world.add_component(
197 id,
198 PointLight::new(
199 gizmo_math::Vec3::new(color.0.x, color.0.y, color.0.z),
200 intensity,
201 10.0,
202 ),
203 );
204 EntityBuilder {
205 commands: self,
206 entity: id,
207 }
208 }
209
210 pub fn spawn_sun(
213 &mut self,
214 _direction: Vec3,
215 color: Color,
216 intensity: f32,
217 ) -> EntityBuilder<'_, 'a> {
218 let id = self.world.spawn();
219 let pos = Vec3::ZERO; let trans = Transform::new(pos);
221
222 self.world.add_component(id, trans);
223 self.world.add_component(
224 id,
225 DirectionalLight {
226 color: Vec3::new(color.0.x, color.0.y, color.0.z),
227 intensity,
228 role: crate::renderer::components::LightRole::Sun,
229 },
230 );
231 EntityBuilder {
232 commands: self,
233 entity: id,
234 }
235 }
236
237 pub fn spawn_skybox(&mut self, color: Color) -> EntityBuilder<'_, 'a> {
241 let mesh = AssetManager::create_inverted_cube(&self.renderer.device);
245 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
246 &self.renderer.device,
247 &self.renderer.queue,
248 &self.renderer.scene.texture_bind_group_layout,
249 );
250 let mat = Material::new(bg).with_unlit(color.to_vec4()).with_skybox();
251 let id = self.world.spawn();
252 let mut trans = Transform::new(Vec3::ZERO);
253 trans.scale = Vec3::new(500.0, 500.0, 500.0);
254 trans.update_local_matrix();
255
256 self.world.add_component(id, trans);
257 self.world.add_component(id, mesh);
258 self.world.add_component(id, mat);
259 self.world.add_component(id, MeshRenderer::new());
260 EntityBuilder {
261 commands: self,
262 entity: id,
263 }
264 }
265
266 pub fn spawn_rigid_cube(
271 &mut self,
272 pos: Vec3,
273 half_extents: Vec3,
274 color: Color,
275 mass: f32,
276 ) -> EntityBuilder<'_, 'a> {
277 let mesh = AssetManager::create_cube(&self.renderer.device);
278 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
279 &self.renderer.device,
280 &self.renderer.queue,
281 &self.renderer.scene.texture_bind_group_layout,
282 );
283 let mat = Material::new(bg).with_unlit(color.to_vec4());
284 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
285 {
287 let mut trans_store = self.world.borrow_mut::<Transform>();
288 if let Some(mut trans) = trans_store.get_mut(id.id()) {
289 trans.scale = half_extents * 2.0;
290 trans.update_local_matrix();
291 }
292 }
293 let mut rb = if mass > 0.0 {
294 RigidBody::new(mass, 0.3, 0.5, true)
295 } else {
296 RigidBody::new_static()
297 };
298 let col = Collider::box_collider(half_extents);
299 rb.update_inertia_from_collider(&col);
300 self.world.add_component(id, rb);
301 if mass > 0.0 {
302 self.world.add_component(id, Velocity::new(Vec3::ZERO));
303 }
304 self.world.add_component(id, col);
305 EntityBuilder {
306 commands: self,
307 entity: id,
308 }
309 }
310
311 pub fn spawn_rigid_sphere(
313 &mut self,
314 pos: Vec3,
315 radius: f32,
316 color: Color,
317 mass: f32,
318 ) -> EntityBuilder<'_, 'a> {
319 let mesh = AssetManager::create_sphere(&self.renderer.device, radius, 16, 16);
320 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
321 &self.renderer.device,
322 &self.renderer.queue,
323 &self.renderer.scene.texture_bind_group_layout,
324 );
325 let mat = Material::new(bg).with_unlit(color.to_vec4());
326 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
327 let mut rb = if mass > 0.0 {
328 RigidBody::new(mass, 0.3, 0.5, true)
329 } else {
330 RigidBody::new_static()
331 };
332 let col = Collider::sphere(radius);
333 rb.update_inertia_from_collider(&col);
334 self.world.add_component(id, rb);
335 if mass > 0.0 {
336 self.world.add_component(id, Velocity::new(Vec3::ZERO));
337 }
338 self.world.add_component(id, col);
339 EntityBuilder {
340 commands: self,
341 entity: id,
342 }
343 }
344
345 pub fn spawn_static_plane(
347 &mut self,
348 pos: Vec3,
349 size: f32,
350 color: Color,
351 ) -> EntityBuilder<'_, 'a> {
352 let mesh = AssetManager::create_plane(&self.renderer.device, size);
353 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
354 &self.renderer.device,
355 &self.renderer.queue,
356 &self.renderer.scene.texture_bind_group_layout,
357 );
358 let mat = Material::new(bg).with_pbr(color.to_vec4(), 0.9, 0.0);
359 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
360 self.world.add_component(id, RigidBody::new_static());
361 self.world.add_component(
362 id,
363 Collider::box_collider(Vec3::new(size / 2.0, 0.05, size / 2.0)),
364 );
365 EntityBuilder {
366 commands: self,
367 entity: id,
368 }
369 }
370
371 pub fn spawn_textured_cube(&mut self, pos: Vec3, texture_path: &str) -> EntityBuilder<'_, 'a> {
375 let mesh = AssetManager::create_cube(&self.renderer.device);
376 let bg = self
377 .asset_manager
378 .as_mut()
379 .unwrap()
380 .load_material_texture(
381 &self.renderer.device,
382 &self.renderer.queue,
383 &self.renderer.scene.texture_bind_group_layout,
384 texture_path,
385 )
386 .unwrap_or_else(|_| {
387 self.asset_manager.as_mut().unwrap().create_white_texture(
388 &self.renderer.device,
389 &self.renderer.queue,
390 &self.renderer.scene.texture_bind_group_layout,
391 )
392 });
393 let mat = Material::new(bg);
394 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
395 EntityBuilder {
396 commands: self,
397 entity: id,
398 }
399 }
400
401 pub fn spawn_textured_plane(
403 &mut self,
404 pos: Vec3,
405 size: f32,
406 texture_path: &str,
407 ) -> EntityBuilder<'_, 'a> {
408 let mesh = AssetManager::create_plane(&self.renderer.device, size);
409 let bg = self
410 .asset_manager
411 .as_mut()
412 .unwrap()
413 .load_material_texture(
414 &self.renderer.device,
415 &self.renderer.queue,
416 &self.renderer.scene.texture_bind_group_layout,
417 texture_path,
418 )
419 .unwrap_or_else(|_| {
420 self.asset_manager.as_mut().unwrap().create_white_texture(
421 &self.renderer.device,
422 &self.renderer.queue,
423 &self.renderer.scene.texture_bind_group_layout,
424 )
425 });
426 let mat = Material::new(bg);
427 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
428 EntityBuilder {
429 commands: self,
430 entity: id,
431 }
432 }
433
434 pub fn spawn_gltf(
439 &mut self,
440 pos: Vec3,
441 path: &str,
442 attach_colliders: bool,
443 ) -> Result<EntityBuilder<'_, 'a>, String> {
444 let default_bg = self.asset_manager.as_mut().unwrap().create_white_texture(
445 &self.renderer.device,
446 &self.renderer.queue,
447 &self.renderer.scene.texture_bind_group_layout,
448 );
449 let default_mat = Material::new(default_bg.clone());
450
451 match self.asset_manager.as_mut().unwrap().load_gltf_scene(
452 &self.renderer.device,
453 &self.renderer.queue,
454 &self.renderer.scene.texture_bind_group_layout,
455 default_bg,
456 path,
457 ) {
458 Ok(asset) => {
459 let root = self.world.spawn();
460 let mut trans = Transform::new(pos);
461 trans.update_local_matrix();
462
463 self.world.add_component(root, trans);
464 self.world
465 .add_component(root, gizmo_physics_core::components::GlobalTransform::default());
466 self.world
467 .add_component(root, EntityName(format!("GLTF: {}", path)));
468 self.world
469 .add_component(root, gizmo_core::component::Children(Vec::new()));
470
471 let mut skeletons = Vec::new();
472 for skel_data in &asset.skeletons {
473 skeletons.push(self.renderer.create_skeleton(std::sync::Arc::new(skel_data.clone())));
474 }
475
476 for node in &asset.roots {
477 spawn_gltf_node_flat(
478 self.world,
479 node,
480 root.id(),
481 default_mat.clone(),
482 attach_colliders,
483 &skeletons,
484 );
485 }
486
487 if !skeletons.is_empty() {
488 self.world.add_component(root, skeletons[0].clone());
489 }
490
491 if !asset.animations.is_empty() {
492 self.world.add_component(
493 root,
494 gizmo_renderer::components::AnimationPlayer {
495 active_animation: 0,
496 current_time: 0.0,
497 loop_anim: true,
498 speed: 1.0,
499 animations: std::sync::Arc::from(
500 asset.animations.clone().into_boxed_slice(),
501 ),
502 ..Default::default()
503 },
504 );
505 }
506
507 Ok(EntityBuilder {
508 commands: self,
509 entity: root,
510 })
511 }
512 Err(e) => Err(format!(
513 "[Commands::spawn_gltf] '{}' yuklenemedi: {}",
514 path, e
515 )),
516 }
517 }
518
519 pub fn spawn_gltf_async_completed(
521 &mut self,
522 completion: gizmo_renderer::async_assets::GltfImportCompletion,
523 pos: Vec3,
524 attach_colliders: bool,
525 ) -> Result<EntityBuilder<'_, 'a>, String> {
526 let default_bg = self.asset_manager.as_mut().unwrap().create_white_texture(
527 &self.renderer.device,
528 &self.renderer.queue,
529 &self.renderer.scene.texture_bind_group_layout,
530 );
531 let default_mat = Material::new(default_bg.clone());
532
533 match self.asset_manager.as_mut().unwrap().load_gltf_from_import(
534 &self.renderer.device,
535 &self.renderer.queue,
536 &self.renderer.scene.texture_bind_group_layout,
537 default_bg,
538 &completion.path,
539 completion.document,
540 completion.buffers,
541 completion.images,
542 ) {
543 Ok(asset) => {
544 let root = self.world.spawn();
545 let mut trans = Transform::new(pos);
546 trans.update_local_matrix();
547
548 self.world.add_component(root, trans);
549 self.world
550 .add_component(root, gizmo_physics_core::components::GlobalTransform::default());
551 self.world
552 .add_component(root, EntityName(format!("GLTF: {}", completion.path)));
553 self.world
554 .add_component(root, gizmo_core::component::Children(Vec::new()));
555
556 let mut skeletons = Vec::new();
557 for skel_data in &asset.skeletons {
558 skeletons.push(self.renderer.create_skeleton(std::sync::Arc::new(skel_data.clone())));
559 }
560
561 for node in &asset.roots {
562 spawn_gltf_node_flat(
563 self.world,
564 node,
565 root.id(),
566 default_mat.clone(),
567 attach_colliders,
568 &skeletons,
569 );
570 }
571
572 if !skeletons.is_empty() {
573 self.world.add_component(root, skeletons[0].clone());
574 }
575
576 if !asset.animations.is_empty() {
577 self.world.add_component(
578 root,
579 gizmo_renderer::components::AnimationPlayer {
580 active_animation: 0,
581 current_time: 0.0,
582 loop_anim: true,
583 speed: 1.0,
584 animations: std::sync::Arc::from(
585 asset.animations.clone().into_boxed_slice(),
586 ),
587 ..Default::default()
588 },
589 );
590 }
591
592 Ok(EntityBuilder {
593 commands: self,
594 entity: root,
595 })
596 }
597 Err(e) => Err(format!(
598 "[Commands::spawn_gltf_async_completed] '{}' yüklenemedi: {}",
599 completion.path, e
600 )),
601 }
602 }
603}
604
605pub struct EntityBuilder<'b, 'a> {
609 commands: &'b mut Commands<'a>,
610 entity: Entity,
611}
612
613impl<'b, 'a> EntityBuilder<'b, 'a> {
614 pub fn with_name(self, name: &str) -> Self {
616 self.commands
617 .world
618 .add_component(self.entity, EntityName(name.to_string()));
619 self
620 }
621
622 pub fn with<C: gizmo_core::Component + 'static>(self, component: C) -> Self {
624 self.commands.world.add_component(self.entity, component);
625 self
626 }
627
628 pub fn id(self) -> Entity {
630 self.entity
631 }
632}
633
634impl<'b, 'a> From<EntityBuilder<'b, 'a>> for Entity {
635 fn from(b: EntityBuilder<'b, 'a>) -> Entity {
636 b.entity
637 }
638}
639
640fn spawn_mesh_entity(
643 world: &mut World,
644 pos: Vec3,
645 mesh: gizmo_renderer::components::Mesh,
646 mat: Material,
647) -> Entity {
648 let id = world.spawn();
649 let mut trans = Transform::new(pos);
650 trans.update_local_matrix();
651
652 world.add_component(id, trans);
653 world.add_component(id, gizmo_physics_core::components::GlobalTransform::default());
654 world.add_component(id, mesh);
655 world.add_component(id, mat);
656 world.add_component(id, MeshRenderer::new());
657 id
658}
659
660fn spawn_gltf_node_flat(
662 world: &mut World,
663 node: &gizmo_renderer::asset::GltfNodeData,
664 parent_id: u32,
665 default_mat: Material,
666 attach_colliders: bool,
667 skeletons: &[gizmo_renderer::components::Skeleton],
668) {
669 use gizmo_core::component::{Children, Parent};
670 let entity = world.spawn();
671 let name = node.name.clone().unwrap_or_else(|| "GLTF_Node".to_string());
672 world.add_component(entity, EntityName(name));
673 world.add_component(entity, Parent(parent_id));
674 world.add_component(entity, Children(Vec::new()));
675
676 {
677 let mut ch_store = world.borrow_mut::<Children>();
678 if let Some(mut parent_ch) = ch_store.get_mut(parent_id) {
680 parent_ch.0.push(entity.id());
681 }
682 }
683
684 let raw_rot = Quat::from_xyzw(
685 node.rotation[0],
686 node.rotation[1],
687 node.rotation[2],
688 node.rotation[3],
689 );
690 let rot = if raw_rot.is_nan() || raw_rot.length() < 0.0001 {
691 Quat::IDENTITY
692 } else {
693 raw_rot.normalize()
694 };
695
696 let mut t = Transform::new(Vec3::new(
697 node.translation[0],
698 node.translation[1],
699 node.translation[2],
700 ))
701 .with_rotation(rot)
702 .with_scale(Vec3::new(node.scale[0], node.scale[1], node.scale[2]));
703
704 if node.skin_index.is_some() || node.name.as_deref() == Some("Armature") {
705 t = Transform::default();
706 }
707
708 world.add_component(entity, t);
709 world.add_component(entity, gizmo_physics_core::components::GlobalTransform::default());
710
711 let mut newly_added_prims = Vec::new();
712 for (mesh, mat_opt) in node.primitives.iter() {
713 let prim = world.spawn();
714 world.add_component(prim, Transform::new(Vec3::ZERO));
715 world.add_component(prim, gizmo_physics_core::components::GlobalTransform::default());
716 world.add_component(prim, Parent(entity.id()));
717 world.add_component(prim, Children(Vec::new()));
718
719 newly_added_prims.push(prim.id());
720
721 world.add_component(prim, mesh.clone());
722 world.add_component(prim, mat_opt.clone().unwrap_or_else(|| default_mat.clone()));
723 world.add_component(prim, MeshRenderer::new());
724
725 if let Some(skin_idx) = node.skin_index {
726 if skin_idx < skeletons.len() {
727 world.add_component(prim, skeletons[skin_idx].clone());
728 }
729 }
730
731 if attach_colliders {
732 let extents = (mesh.bounds.max - mesh.bounds.min) / 2.0;
733 let center_offset = (mesh.bounds.max + mesh.bounds.min) / 2.0;
734 let cx = extents.x.max(0.01);
735 let cy = extents.y.max(0.01);
736 let cz = extents.z.max(0.01);
737
738 if center_offset.length_squared() > 0.0001 {
740 world.add_component(
741 prim,
742 gizmo_physics_core::Collider::offset_box(center_offset.into(), gizmo_math::Vec3::new(cx, cy, cz)),
743 );
744 } else {
745 world.add_component(prim, gizmo_physics_core::Collider::new_aabb(cx, cy, cz));
746 }
747 }
748 }
749
750 if !newly_added_prims.is_empty() {
752 {
753 let mut ch_store = world.borrow_mut::<Children>();
754 if let Some(mut parent_ch) = ch_store.get_mut(entity.id()) {
755 parent_ch.0.extend(newly_added_prims);
756 }
757 }
758 }
759
760 for child_node in &node.children {
761 spawn_gltf_node_flat(
762 world,
763 child_node,
764 entity.id(),
765 default_mat.clone(),
766 attach_colliders,
767 skeletons,
768 );
769 }
770}
771
772pub trait WorldExt {
777 fn entity_named(&self, name: &str) -> Option<u32>;
779
780 fn move_entity_named<F: FnMut(&mut gizmo_physics_core::Transform)>(&mut self, name: &str, f: F);
782
783 fn position_of(&self, name: &str) -> Option<Vec3>;
785
786 fn modify<T: gizmo_core::Component + 'static, F: FnMut(&mut T)>(&mut self, name: &str, f: F);
794}
795
796impl WorldExt for World {
797 fn entity_named(&self, name: &str) -> Option<u32> {
798 let mut names = self.query::<&EntityName>()?;
799 for (id, n) in names.iter_mut() {
800 if n.0 == name {
801 return Some(id);
802 }
803 }
804 None
805 }
806
807 fn move_entity_named<F: FnMut(&mut gizmo_physics_core::Transform)>(&mut self, name: &str, mut f: F) {
808 let target: Option<u32> = {
809 if let Some(mut names) = self.query::<&EntityName>() {
810 let mut found = None;
811 for (id, n) in names.iter_mut() {
812 if n.0 == name {
813 found = Some(id);
814 break;
815 }
816 }
817 found
818 } else {
819 None
820 }
821 };
822 if let Some(target_id) = target {
823 if let Some(mut transforms) =
824 self.query::<gizmo_core::prelude::Mut<gizmo_physics_core::Transform>>()
825 {
826 for (tid, mut trans) in transforms.iter_mut() {
827 if tid == target_id {
828 f(&mut trans);
829 trans.update_local_matrix();
830 }
831 }
832 }
833 }
834 }
835
836 fn position_of(&self, name: &str) -> Option<Vec3> {
837 let target_id = self.entity_named(name)?;
838 let transforms = self.borrow::<gizmo_physics_core::Transform>();
839 transforms.get(target_id).map(|t| t.position)
840 }
841
842 fn modify<T: gizmo_core::Component + 'static, F: FnMut(&mut T)>(
843 &mut self,
844 name: &str,
845 mut f: F,
846 ) {
847 let target: Option<u32> = {
848 if let Some(mut names) = self.query::<&EntityName>() {
849 let mut found = None;
850 for (id, n) in names.iter_mut() {
851 if n.0 == name {
852 found = Some(id);
853 break;
854 }
855 }
856 found
857 } else {
858 None
859 }
860 };
861 if let Some(target_id) = target {
862 {
863 let mut storage = self.borrow_mut::<T>();
864 if let Some(mut comp) = storage.get_mut(target_id) {
865 f(&mut *comp);
866 }
867 }
868 }
869 }
870}
871
872pub trait InputExt {
884 fn pressed(&self, keycode: winit::keyboard::KeyCode) -> bool;
886
887 fn just_pressed(&self, keycode: winit::keyboard::KeyCode) -> bool;
889
890 fn just_released(&self, keycode: winit::keyboard::KeyCode) -> bool;
892}
893
894impl InputExt for gizmo_core::input::Input {
895 #[inline]
896 fn pressed(&self, keycode: winit::keyboard::KeyCode) -> bool {
897 self.is_key_pressed(keycode as u32)
898 }
899 #[inline]
900 fn just_pressed(&self, keycode: winit::keyboard::KeyCode) -> bool {
901 self.is_key_just_pressed(keycode as u32)
902 }
903 #[inline]
904 fn just_released(&self, keycode: winit::keyboard::KeyCode) -> bool {
905 self.is_key_just_released(keycode as u32)
906 }
907}