1use bevy::{ecs::system::EntityCommands, utils::HashMap};
2
3use space_prefab::{component::*, ext::*};
4use space_shared::PrefabMarker;
5
6pub const MESH_CATEGORY: &str = "mesh";
7
8#[derive(Resource, Default)]
10pub struct BundleReg {
11 pub bundles: HashMap<String, HashMap<String, EditorBundleUntyped>>,
12}
13
14impl BundleReg {
15 pub fn add_bundle<T: Bundle + Clone>(&mut self, bundle: EditorBundle<T>) {
16 let dyn_bundle = EditorBundleUntyped::new(bundle.data.clone(), bundle.name.clone());
17
18 self.bundles
19 .entry(bundle.category)
20 .or_default()
21 .insert(bundle.name, dyn_bundle);
22 }
23}
24
25pub struct EditorBundle<T: Bundle + Clone> {
27 pub data: T,
28 pub category: String,
29 pub name: String,
30}
31
32pub struct EditorBundleUntyped {
34 pub data: Box<dyn Fn(&mut EntityCommands) + Send + Sync>,
35 pub name: String,
36}
37
38impl EditorBundleUntyped {
39 pub fn new<T: Bundle + Clone>(data: T, name: String) -> Self {
41 Self {
42 data: Box::new(move |cmds| {
43 cmds.insert(data.clone());
44 }),
45 name,
46 }
47 }
48
49 pub fn spawn(&self, commands: &mut Commands) -> Entity {
51 let mut cmds = commands.spawn_empty();
52 (self.data)(&mut cmds);
53 cmds.insert(PrefabMarker);
54 cmds.id()
55 }
56}
57
58pub trait EditorUiExt {
60 fn editor_bundle<T: Bundle + Clone>(&mut self, category: &str, name: &str, bundle: T);
62}
63
64impl EditorUiExt for App {
65 fn editor_bundle<T: Bundle + Clone>(&mut self, category: &str, name: &str, bundle: T) {
66 let mut reg = if let Some(reg) = self.world.get_resource_mut::<BundleReg>() {
67 reg
68 } else {
69 self.init_resource::<BundleReg>();
70 self.world.get_resource_mut::<BundleReg>().unwrap()
71 };
72
73 reg.add_bundle(EditorBundle {
74 data: bundle,
75 category: category.to_string(),
76 name: name.to_string(),
77 });
78 }
79}
80
81pub fn register_light_editor_bundles(app: &mut App) {
82 app.editor_bundle(
83 "Light",
84 "Point light",
85 (Name::new("Point light"), PointLight::default()),
86 );
87
88 app.editor_bundle(
89 "Light",
90 "Directional light",
91 (Name::new("Directional light"), DirectionalLight::default()),
92 );
93
94 app.editor_bundle(
95 "Light",
96 "Spot light",
97 (Name::new("Spot light"), SpotLight::default()),
98 );
99}
100
101pub fn register_mesh_editor_bundles(app: &mut App) {
103 app.editor_bundle(
104 "Mesh",
105 "Cube",
106 (
107 MeshPrimitivePrefab::Cube(1.0),
108 Name::new("Cube".to_string()),
109 Transform::default(),
110 Visibility::default(),
111 ),
112 );
113 app.editor_bundle(
114 "Mesh",
115 "Box",
116 (
117 MeshPrimitivePrefab::Box(BoxPrefab::default()),
118 Name::new("Box".to_string()),
119 Transform::default(),
120 Visibility::default(),
121 ),
122 );
123 app.editor_bundle(
124 "Mesh",
125 "Sphere",
126 (
127 MeshPrimitivePrefab::Sphere(SpherePrefab::default()),
128 Name::new("UVSphere".to_string()),
129 Transform::default(),
130 Visibility::default(),
131 ),
132 );
133 app.editor_bundle(
134 "Mesh",
135 "Quad",
136 (
137 MeshPrimitivePrefab::Quad(QuadPrefab::default()),
138 Name::new("Quad".to_string()),
139 Transform::default(),
140 Visibility::default(),
141 ),
142 );
143 app.editor_bundle(
144 "Mesh",
145 "Capsule",
146 (
147 MeshPrimitivePrefab::Capsule(CapsulePrefab::default()),
148 Name::new("Capsule"),
149 Transform::default(),
150 Visibility::default(),
151 ),
152 );
153 app.editor_bundle(
154 "Mesh",
155 "Circle",
156 (
157 MeshPrimitivePrefab::Circle(CirclePrefab::default()),
158 Name::new("Circle".to_string()),
159 Transform::default(),
160 Visibility::default(),
161 ),
162 );
163 app.editor_bundle(
164 "Mesh",
165 "Cylinder",
166 (
167 MeshPrimitivePrefab::Cylinder(CylinderPrefab::default()),
168 Name::new("Cylinder".to_string()),
169 Transform::default(),
170 Visibility::default(),
171 ),
172 );
173 app.editor_bundle(
174 "Mesh",
175 "Icosphere",
176 (
177 MeshPrimitivePrefab::Icosphere(IcospherePrefab::default()),
178 Name::new("Icosphere".to_string()),
179 Transform::default(),
180 Visibility::default(),
181 ),
182 );
183 app.editor_bundle(
184 "Mesh",
185 "Plane",
186 (
187 MeshPrimitivePrefab::Plane(PlanePrefab::default()),
188 Name::new("Plane".to_string()),
189 Transform::default(),
190 Visibility::default(),
191 ),
192 );
193 app.editor_bundle(
194 "Mesh",
195 "RegularPolygon",
196 (
197 MeshPrimitivePrefab::RegularPolygon(RegularPolygonPrefab::default()),
198 Name::new("RegularPolygon".to_string()),
199 Transform::default(),
200 Visibility::default(),
201 ),
202 );
203 app.editor_bundle(
204 "Mesh",
205 "Torus",
206 (
207 MeshPrimitivePrefab::Torus(TorusPrefab::default()),
208 Name::new("Torus".to_string()),
209 Transform::default(),
210 Visibility::default(),
211 ),
212 );
213
214 app.editor_bundle(
215 "Camera",
216 "CameraPlay",
217 (
218 Camera3d::default(),
219 Name::new("Camera3d".to_string()),
220 Transform::default(),
221 Visibility::default(),
222 CameraPlay::default(),
223 ),
224 );
225}