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 exposure: 1.0,
141 primary: true,
142 },
143 );
144 EntityBuilder {
145 commands: self,
146 entity: id,
147 }
148 }
149
150 pub fn spawn_camera_with(
152 &mut self,
153 pos: Vec3,
154 fov_deg: f32,
155 near: f32,
156 far: f32,
157 ) -> EntityBuilder<'_, 'a> {
158 if let Some(mut cameras) = self.world.query::<gizmo_core::prelude::Mut<Camera>>() {
159 for (_, mut c) in cameras.iter_mut() {
160 c.primary = false;
161 }
162 }
163 let id = self.world.spawn();
164 let trans = Transform::new(pos);
165
166 self.world.add_component(id, trans);
167 self.world.add_component(
168 id,
169 Camera {
170 fov: fov_deg.to_radians(),
171 near,
172 far,
173 yaw: -std::f32::consts::FRAC_PI_2,
174 pitch: 0.0,
175 exposure: 1.0,
176 primary: true,
177 },
178 );
179 EntityBuilder {
180 commands: self,
181 entity: id,
182 }
183 }
184
185 pub fn spawn_point_light(
189 &mut self,
190 pos: Vec3,
191 color: Color,
192 intensity: f32,
193 ) -> EntityBuilder<'_, 'a> {
194 let id = self.world.spawn();
195 let trans = Transform::new(pos);
196
197 self.world.add_component(id, trans);
198 self.world.add_component(
199 id,
200 PointLight::new(
201 gizmo_math::Vec3::new(color.0.x, color.0.y, color.0.z),
202 intensity,
203 10.0,
204 ),
205 );
206 EntityBuilder {
207 commands: self,
208 entity: id,
209 }
210 }
211
212 pub fn spawn_sun(
215 &mut self,
216 _direction: Vec3,
217 color: Color,
218 intensity: f32,
219 ) -> EntityBuilder<'_, 'a> {
220 let id = self.world.spawn();
221 let pos = Vec3::ZERO; let trans = Transform::new(pos);
223
224 self.world.add_component(id, trans);
225 self.world.add_component(
226 id,
227 DirectionalLight {
228 color: Vec3::new(color.0.x, color.0.y, color.0.z),
229 intensity,
230 role: crate::renderer::components::LightRole::Sun,
231 },
232 );
233 EntityBuilder {
234 commands: self,
235 entity: id,
236 }
237 }
238
239 pub fn spawn_skybox(&mut self, color: Color) -> EntityBuilder<'_, 'a> {
243 let mesh = AssetManager::create_inverted_cube(&self.renderer.device);
247 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
248 &self.renderer.device,
249 &self.renderer.queue,
250 &self.renderer.scene.texture_bind_group_layout,
251 );
252 let mat = Material::new(bg).with_unlit(color.to_vec4()).with_skybox();
253 let id = self.world.spawn();
254 let mut trans = Transform::new(Vec3::ZERO);
255 trans.scale = Vec3::new(500.0, 500.0, 500.0);
256 trans.update_local_matrix();
257
258 self.world.add_component(id, trans);
259 self.world.add_component(id, mesh);
260 self.world.add_component(id, mat);
261 self.world.add_component(id, MeshRenderer::new());
262 EntityBuilder {
263 commands: self,
264 entity: id,
265 }
266 }
267
268 pub fn spawn_rigid_cube(
273 &mut self,
274 pos: Vec3,
275 half_extents: Vec3,
276 color: Color,
277 mass: f32,
278 ) -> EntityBuilder<'_, 'a> {
279 let mesh = AssetManager::create_cube(&self.renderer.device);
280 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
281 &self.renderer.device,
282 &self.renderer.queue,
283 &self.renderer.scene.texture_bind_group_layout,
284 );
285 let mat = Material::new(bg).with_unlit(color.to_vec4());
286 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
287 {
289 let trans_store = self.world.borrow_mut::<Transform>();
290 if let Some(mut trans) = trans_store.get_mut(id.id()) {
291 trans.scale = half_extents * 2.0;
292 trans.update_local_matrix();
293 }
294 }
295 let mut rb = if mass > 0.0 {
296 RigidBody::new(mass, 0.3, 0.5, true)
297 } else {
298 RigidBody::new_static()
299 };
300 let col = Collider::box_collider(half_extents);
301 rb.update_inertia_from_collider(&col);
302 self.world.add_component(id, rb);
303 if mass > 0.0 {
304 self.world.add_component(id, Velocity::new(Vec3::ZERO));
305 }
306 self.world.add_component(id, col);
307 EntityBuilder {
308 commands: self,
309 entity: id,
310 }
311 }
312
313 pub fn spawn_rigid_sphere(
315 &mut self,
316 pos: Vec3,
317 radius: f32,
318 color: Color,
319 mass: f32,
320 ) -> EntityBuilder<'_, 'a> {
321 let mesh = AssetManager::create_sphere(&self.renderer.device, radius, 16, 16);
322 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
323 &self.renderer.device,
324 &self.renderer.queue,
325 &self.renderer.scene.texture_bind_group_layout,
326 );
327 let mat = Material::new(bg).with_unlit(color.to_vec4());
328 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
329 let mut rb = if mass > 0.0 {
330 RigidBody::new(mass, 0.3, 0.5, true)
331 } else {
332 RigidBody::new_static()
333 };
334 let col = Collider::sphere(radius);
335 rb.update_inertia_from_collider(&col);
336 self.world.add_component(id, rb);
337 if mass > 0.0 {
338 self.world.add_component(id, Velocity::new(Vec3::ZERO));
339 }
340 self.world.add_component(id, col);
341 EntityBuilder {
342 commands: self,
343 entity: id,
344 }
345 }
346
347 pub fn spawn_static_plane(
349 &mut self,
350 pos: Vec3,
351 size: f32,
352 color: Color,
353 ) -> EntityBuilder<'_, 'a> {
354 let mesh = AssetManager::create_plane(&self.renderer.device, size);
355 let bg = self.asset_manager.as_mut().unwrap().create_white_texture(
356 &self.renderer.device,
357 &self.renderer.queue,
358 &self.renderer.scene.texture_bind_group_layout,
359 );
360 let mat = Material::new(bg).with_pbr(color.to_vec4(), 0.9, 0.0);
361 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
362 self.world.add_component(id, RigidBody::new_static());
363 self.world.add_component(
364 id,
365 Collider::box_collider(Vec3::new(size / 2.0, 0.05, size / 2.0)),
366 );
367 EntityBuilder {
368 commands: self,
369 entity: id,
370 }
371 }
372
373 pub fn spawn_textured_cube(&mut self, pos: Vec3, texture_path: &str) -> EntityBuilder<'_, 'a> {
377 let mesh = AssetManager::create_cube(&self.renderer.device);
378 let bg = self
379 .asset_manager
380 .as_mut()
381 .unwrap()
382 .load_material_texture(
383 &self.renderer.device,
384 &self.renderer.queue,
385 &self.renderer.scene.texture_bind_group_layout,
386 texture_path,
387 )
388 .unwrap_or_else(|_| {
389 self.asset_manager.as_mut().unwrap().create_white_texture(
390 &self.renderer.device,
391 &self.renderer.queue,
392 &self.renderer.scene.texture_bind_group_layout,
393 )
394 });
395 let mat = Material::new(bg);
396 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
397 EntityBuilder {
398 commands: self,
399 entity: id,
400 }
401 }
402
403 pub fn spawn_textured_plane(
405 &mut self,
406 pos: Vec3,
407 size: f32,
408 texture_path: &str,
409 ) -> EntityBuilder<'_, 'a> {
410 let mesh = AssetManager::create_plane(&self.renderer.device, size);
411 let bg = self
412 .asset_manager
413 .as_mut()
414 .unwrap()
415 .load_material_texture(
416 &self.renderer.device,
417 &self.renderer.queue,
418 &self.renderer.scene.texture_bind_group_layout,
419 texture_path,
420 )
421 .unwrap_or_else(|_| {
422 self.asset_manager.as_mut().unwrap().create_white_texture(
423 &self.renderer.device,
424 &self.renderer.queue,
425 &self.renderer.scene.texture_bind_group_layout,
426 )
427 });
428 let mat = Material::new(bg);
429 let id = spawn_mesh_entity(self.world, pos, mesh, mat);
430 EntityBuilder {
431 commands: self,
432 entity: id,
433 }
434 }
435
436 pub fn spawn_gltf(
441 &mut self,
442 pos: Vec3,
443 path: &str,
444 attach_colliders: bool,
445 ) -> Result<EntityBuilder<'_, 'a>, String> {
446 let default_bg = self.asset_manager.as_mut().unwrap().create_white_texture(
447 &self.renderer.device,
448 &self.renderer.queue,
449 &self.renderer.scene.texture_bind_group_layout,
450 );
451 let default_mat = Material::new(default_bg.clone());
452
453 match self.asset_manager.as_mut().unwrap().load_gltf_scene(
454 &self.renderer.device,
455 &self.renderer.queue,
456 &self.renderer.scene.texture_bind_group_layout,
457 default_bg,
458 path,
459 ) {
460 Ok(asset) => {
461 let root = self.world.spawn();
462 let mut trans = Transform::new(pos);
463 trans.update_local_matrix();
464
465 self.world.add_component(root, trans);
466 self.world
467 .add_component(root, gizmo_physics_core::components::GlobalTransform::default());
468 self.world
469 .add_component(root, EntityName(format!("GLTF: {}", path)));
470 self.world
471 .add_component(root, gizmo_core::component::Children(Vec::new()));
472
473 let mut skeletons = Vec::new();
474 for skel_data in &asset.skeletons {
475 skeletons.push(self.renderer.create_skeleton(std::sync::Arc::new(skel_data.clone())));
476 }
477
478 for node in &asset.roots {
479 spawn_gltf_node_flat(
480 self.world,
481 node,
482 root.id(),
483 default_mat.clone(),
484 attach_colliders,
485 &skeletons,
486 );
487 }
488
489 if !skeletons.is_empty() {
490 self.world.add_component(root, skeletons[0].clone());
491 }
492
493 if !asset.animations.is_empty() {
494 self.world.add_component(
495 root,
496 gizmo_renderer::components::AnimationPlayer {
497 active_animation: 0,
498 current_time: 0.0,
499 loop_anim: true,
500 speed: 1.0,
501 animations: std::sync::Arc::from(
502 asset.animations.clone().into_boxed_slice(),
503 ),
504 ..Default::default()
505 },
506 );
507 }
508
509 Ok(EntityBuilder {
510 commands: self,
511 entity: root,
512 })
513 }
514 Err(e) => Err(format!(
515 "[Commands::spawn_gltf] '{}' yuklenemedi: {}",
516 path, e
517 )),
518 }
519 }
520
521 pub fn spawn_gltf_async_completed(
523 &mut self,
524 completion: gizmo_renderer::async_assets::GltfImportCompletion,
525 pos: Vec3,
526 attach_colliders: bool,
527 ) -> Result<EntityBuilder<'_, 'a>, String> {
528 let default_bg = self.asset_manager.as_mut().unwrap().create_white_texture(
529 &self.renderer.device,
530 &self.renderer.queue,
531 &self.renderer.scene.texture_bind_group_layout,
532 );
533 let default_mat = Material::new(default_bg.clone());
534
535 match self.asset_manager.as_mut().unwrap().load_gltf_from_import(
536 &self.renderer.device,
537 &self.renderer.queue,
538 &self.renderer.scene.texture_bind_group_layout,
539 default_bg,
540 &completion.path,
541 completion.document,
542 completion.buffers,
543 completion.images,
544 ) {
545 Ok(asset) => {
546 let root = self.world.spawn();
547 let mut trans = Transform::new(pos);
548 trans.update_local_matrix();
549
550 self.world.add_component(root, trans);
551 self.world
552 .add_component(root, gizmo_physics_core::components::GlobalTransform::default());
553 self.world
554 .add_component(root, EntityName(format!("GLTF: {}", completion.path)));
555 self.world
556 .add_component(root, gizmo_core::component::Children(Vec::new()));
557
558 let mut skeletons = Vec::new();
559 for skel_data in &asset.skeletons {
560 skeletons.push(self.renderer.create_skeleton(std::sync::Arc::new(skel_data.clone())));
561 }
562
563 for node in &asset.roots {
564 spawn_gltf_node_flat(
565 self.world,
566 node,
567 root.id(),
568 default_mat.clone(),
569 attach_colliders,
570 &skeletons,
571 );
572 }
573
574 if !skeletons.is_empty() {
575 self.world.add_component(root, skeletons[0].clone());
576 }
577
578 if !asset.animations.is_empty() {
579 self.world.add_component(
580 root,
581 gizmo_renderer::components::AnimationPlayer {
582 active_animation: 0,
583 current_time: 0.0,
584 loop_anim: true,
585 speed: 1.0,
586 animations: std::sync::Arc::from(
587 asset.animations.clone().into_boxed_slice(),
588 ),
589 ..Default::default()
590 },
591 );
592 }
593
594 Ok(EntityBuilder {
595 commands: self,
596 entity: root,
597 })
598 }
599 Err(e) => Err(format!(
600 "[Commands::spawn_gltf_async_completed] '{}' yüklenemedi: {}",
601 completion.path, e
602 )),
603 }
604 }
605}
606
607pub struct EntityBuilder<'b, 'a> {
611 commands: &'b mut Commands<'a>,
612 entity: Entity,
613}
614
615impl<'b, 'a> EntityBuilder<'b, 'a> {
616 pub fn with_name(self, name: &str) -> Self {
618 self.commands
619 .world
620 .add_component(self.entity, EntityName(name.to_string()));
621 self
622 }
623
624 pub fn with<C: gizmo_core::Component + 'static>(self, component: C) -> Self {
626 self.commands.world.add_component(self.entity, component);
627 self
628 }
629
630 pub fn id(self) -> Entity {
632 self.entity
633 }
634}
635
636impl<'b, 'a> From<EntityBuilder<'b, 'a>> for Entity {
637 fn from(b: EntityBuilder<'b, 'a>) -> Entity {
638 b.entity
639 }
640}
641
642fn spawn_mesh_entity(
645 world: &mut World,
646 pos: Vec3,
647 mesh: gizmo_renderer::components::Mesh,
648 mat: Material,
649) -> Entity {
650 let id = world.spawn();
651 let mut trans = Transform::new(pos);
652 trans.update_local_matrix();
653
654 world.add_component(id, trans);
655 world.add_component(id, gizmo_physics_core::components::GlobalTransform::default());
656 world.add_component(id, mesh);
657 world.add_component(id, mat);
658 world.add_component(id, MeshRenderer::new());
659 id
660}
661
662fn spawn_gltf_node_flat(
664 world: &mut World,
665 node: &gizmo_renderer::asset::GltfNodeData,
666 parent_id: u32,
667 default_mat: Material,
668 attach_colliders: bool,
669 skeletons: &[gizmo_renderer::components::Skeleton],
670) {
671 use gizmo_core::component::{Children, Parent};
672 let entity = world.spawn();
673 let name = node.name.clone().unwrap_or_else(|| "GLTF_Node".to_string());
674 world.add_component(entity, EntityName(name));
675 world.add_component(entity, Parent(parent_id));
676 world.add_component(entity, Children(Vec::new()));
677
678 {
679 let ch_store = world.borrow_mut::<Children>();
680 if let Some(mut parent_ch) = ch_store.get_mut(parent_id) {
682 parent_ch.0.push(entity.id());
683 }
684 }
685
686 let raw_rot = Quat::from_xyzw(
687 node.rotation[0],
688 node.rotation[1],
689 node.rotation[2],
690 node.rotation[3],
691 );
692 let rot = if raw_rot.is_nan() || raw_rot.length() < 0.0001 {
693 Quat::IDENTITY
694 } else {
695 raw_rot.normalize()
696 };
697
698 let mut t = Transform::new(Vec3::new(
699 node.translation[0],
700 node.translation[1],
701 node.translation[2],
702 ))
703 .with_rotation(rot)
704 .with_scale(Vec3::new(node.scale[0], node.scale[1], node.scale[2]));
705 t.update_local_matrix();
706
707 if node.skin_index.is_some() || node.name.as_deref() == Some("Armature") {
708 t = Transform::default();
709 t.update_local_matrix();
710 }
711
712 world.add_component(entity, t);
713 world.add_component(entity, gizmo_physics_core::components::GlobalTransform::default());
714
715 println!("SPAWN GLTF NODE: name={:?}, num_primitives={}", node.name, node.primitives.len());
716 let mut newly_added_prims = Vec::new();
717 for (mesh, mat_opt) in node.primitives.iter() {
718 println!(" SPAWN PRIM: mesh_source='{}', bounds_min={:?}, bounds_max={:?}", mesh.source, mesh.bounds.min, mesh.bounds.max);
719 let prim = world.spawn();
720 let mut prim_t = Transform::new(Vec3::ZERO);
721 prim_t.update_local_matrix();
722 world.add_component(prim, prim_t);
723 world.add_component(prim, gizmo_physics_core::components::GlobalTransform::default());
724 world.add_component(prim, Parent(entity.id()));
725 world.add_component(prim, Children(Vec::new()));
726
727 newly_added_prims.push(prim.id());
728
729 world.add_component(prim, mesh.clone());
730 world.add_component(prim, mat_opt.clone().unwrap_or_else(|| default_mat.clone()));
731 world.add_component(prim, MeshRenderer::new());
732
733 if let Some(skin_idx) = node.skin_index {
734 if skin_idx < skeletons.len() {
735 world.add_component(prim, skeletons[skin_idx].clone());
736 }
737 }
738
739 if attach_colliders {
740 let extents = (mesh.bounds.max - mesh.bounds.min) / 2.0;
741 let center_offset = (mesh.bounds.max + mesh.bounds.min) / 2.0;
742 let cx = extents.x.max(0.01);
743 let cy = extents.y.max(0.01);
744 let cz = extents.z.max(0.01);
745
746 if center_offset.length_squared() > 0.0001 {
748 world.add_component(
749 prim,
750 gizmo_physics_core::Collider::offset_box(center_offset.into(), gizmo_math::Vec3::new(cx, cy, cz)),
751 );
752 } else {
753 world.add_component(prim, gizmo_physics_core::Collider::new_aabb(cx, cy, cz));
754 }
755 }
756 }
757
758 if !newly_added_prims.is_empty() {
760 {
761 let ch_store = world.borrow_mut::<Children>();
762 if let Some(mut parent_ch) = ch_store.get_mut(entity.id()) {
763 parent_ch.0.extend(newly_added_prims);
764 }
765 }
766 }
767
768 for child_node in &node.children {
769 spawn_gltf_node_flat(
770 world,
771 child_node,
772 entity.id(),
773 default_mat.clone(),
774 attach_colliders,
775 skeletons,
776 );
777 }
778}
779
780pub trait WorldExt {
785 fn entity_named(&self, name: &str) -> Option<u32>;
787
788 fn move_entity_named<F: FnMut(&mut gizmo_physics_core::Transform)>(&mut self, name: &str, f: F);
790
791 fn position_of(&self, name: &str) -> Option<Vec3>;
793
794 fn modify<T: gizmo_core::Component + 'static, F: FnMut(&mut T)>(&mut self, name: &str, f: F);
802}
803
804impl WorldExt for World {
805 fn entity_named(&self, name: &str) -> Option<u32> {
806 let mut names = self.query::<&EntityName>()?;
807 for (id, n) in names.iter_mut() {
808 if n.0 == name {
809 return Some(id);
810 }
811 }
812 None
813 }
814
815 fn move_entity_named<F: FnMut(&mut gizmo_physics_core::Transform)>(&mut self, name: &str, mut f: F) {
816 let target: Option<u32> = {
817 if let Some(mut names) = self.query::<&EntityName>() {
818 let mut found = None;
819 for (id, n) in names.iter_mut() {
820 if n.0 == name {
821 found = Some(id);
822 break;
823 }
824 }
825 found
826 } else {
827 None
828 }
829 };
830 if let Some(target_id) = target {
831 if let Some(mut transforms) =
832 self.query::<gizmo_core::prelude::Mut<gizmo_physics_core::Transform>>()
833 {
834 for (tid, mut trans) in transforms.iter_mut() {
835 if tid == target_id {
836 f(&mut trans);
837 trans.update_local_matrix();
838 }
839 }
840 }
841 }
842 }
843
844 fn position_of(&self, name: &str) -> Option<Vec3> {
845 let target_id = self.entity_named(name)?;
846 let transforms = self.borrow::<gizmo_physics_core::Transform>();
847 transforms.get(target_id).map(|t| t.position)
848 }
849
850 fn modify<T: gizmo_core::Component + 'static, F: FnMut(&mut T)>(
851 &mut self,
852 name: &str,
853 mut f: F,
854 ) {
855 let target: Option<u32> = {
856 if let Some(mut names) = self.query::<&EntityName>() {
857 let mut found = None;
858 for (id, n) in names.iter_mut() {
859 if n.0 == name {
860 found = Some(id);
861 break;
862 }
863 }
864 found
865 } else {
866 None
867 }
868 };
869 if let Some(target_id) = target {
870 {
871 let storage = self.borrow_mut::<T>();
872 if let Some(mut comp) = storage.get_mut(target_id) {
873 f(&mut *comp);
874 }
875 }
876 }
877 }
878}
879
880pub trait InputExt {
892 fn pressed(&self, keycode: winit::keyboard::KeyCode) -> bool;
894
895 fn just_pressed(&self, keycode: winit::keyboard::KeyCode) -> bool;
897
898 fn just_released(&self, keycode: winit::keyboard::KeyCode) -> bool;
900}
901
902impl InputExt for gizmo_core::input::Input {
903 #[inline]
904 fn pressed(&self, keycode: winit::keyboard::KeyCode) -> bool {
905 self.is_key_pressed(keycode as u32)
906 }
907 #[inline]
908 fn just_pressed(&self, keycode: winit::keyboard::KeyCode) -> bool {
909 self.is_key_just_pressed(keycode as u32)
910 }
911 #[inline]
912 fn just_released(&self, keycode: winit::keyboard::KeyCode) -> bool {
913 self.is_key_just_released(keycode as u32)
914 }
915}