1use std::ptr;
2
3use crate::camera::Camera;
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::light::Light;
8use crate::mesh::Mesh;
9use crate::physically_plausible_light::PhysicallyPlausibleLight;
10use crate::protocols::{Component, Named, ObjectContainerComponent};
11use crate::skeleton::Skeleton;
12use crate::types::{BoundingBox, ObjectInfo, ObjectKind};
13use crate::util::{c_string, parse_json, required_handle, take_string};
14use crate::voxel_array::VoxelArray;
15use crate::PackedJointAnimation;
16
17#[derive(Debug, Clone)]
18pub struct Object {
20 handle: ObjectHandle,
21}
22
23impl Named for Object {
24 fn name(&self) -> Option<String> {
25 self.name()
26 }
27
28 fn set_name(&self, name: &str) -> Result<()> {
29 self.set_name(name)
30 }
31}
32
33impl Object {
34 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
36 Self { handle }
37 }
38
39 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
41 self.handle.as_ptr()
42 }
43
44 pub fn new() -> Result<Self> {
46 let mut out_object = ptr::null_mut();
47 let mut out_error = ptr::null_mut();
48 let status = unsafe { ffi::mdl_object_new(&mut out_object, &mut out_error) };
50 crate::util::status_result(status, out_error)?;
51 Ok(Self::from_handle(required_handle(out_object, "MDLObject")?))
52 }
53
54 pub fn info(&self) -> Result<ObjectInfo> {
56 parse_json(
57 unsafe { ffi::mdl_object_info_json(self.handle.as_ptr()) },
59 "MDLObject",
60 )
61 }
62
63 #[must_use]
64 pub fn kind(&self) -> ObjectKind {
66 ObjectKind::from_raw(unsafe { ffi::mdl_object_kind(self.handle.as_ptr()) })
68 .unwrap_or(ObjectKind::Unknown)
69 }
70
71 #[must_use]
72 pub fn name(&self) -> Option<String> {
74 take_string(unsafe { ffi::mdl_object_name_string(self.handle.as_ptr()) })
76 }
77
78 pub fn set_name(&self, name: &str) -> Result<()> {
80 let name = c_string(name)?;
81 unsafe { ffi::mdl_object_set_name(self.handle.as_ptr(), name.as_ptr()) };
83 Ok(())
84 }
85
86 #[must_use]
87 pub fn path(&self) -> Option<String> {
89 take_string(unsafe { ffi::mdl_object_path_string(self.handle.as_ptr()) })
91 }
92
93 #[must_use]
94 pub fn hidden(&self) -> bool {
96 unsafe { ffi::mdl_object_hidden(self.handle.as_ptr()) != 0 }
98 }
99
100 pub fn set_hidden(&self, hidden: bool) {
102 unsafe { ffi::mdl_object_set_hidden(self.handle.as_ptr(), i32::from(hidden)) };
104 }
105
106 pub fn add_child(&self, child: &Self) {
108 unsafe { ffi::mdl_object_add_child(self.handle.as_ptr(), child.handle.as_ptr()) };
110 }
111
112 #[must_use]
113 pub fn children_container(&self) -> Option<ObjectContainer> {
115 let ptr = unsafe { ffi::mdl_object_children_container(self.handle.as_ptr()) };
117 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(ObjectContainer::from_handle)
119 }
120
121 pub fn set_children_container(&self, container: Option<&ObjectContainer>) {
123 unsafe {
125 ffi::mdl_object_set_children_container(
126 self.handle.as_ptr(),
127 container.map_or(ptr::null_mut(), ObjectContainer::as_ptr),
128 );
129 };
130 }
131
132 #[must_use]
133 pub fn child_count(&self) -> usize {
135 unsafe { ffi::mdl_object_child_count(self.handle.as_ptr()) as usize }
137 }
138
139 #[must_use]
140 pub fn child_at(&self, index: usize) -> Option<Self> {
142 let ptr = unsafe { ffi::mdl_object_child_at(self.handle.as_ptr(), index as u64) };
144 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle)
146 }
147
148 #[must_use]
149 pub fn children(&self) -> Vec<Self> {
151 (0..self.child_count())
152 .filter_map(|index| self.child_at(index))
153 .collect()
154 }
155
156 pub fn at_path(&self, path: &str) -> Result<Option<Self>> {
158 let path = c_string(path)?;
159 let ptr = unsafe { ffi::mdl_object_at_path(self.handle.as_ptr(), path.as_ptr()) };
161 Ok(unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle))
163 }
164
165 #[must_use]
166 pub fn bounding_box_at_time(&self, time: f64) -> BoundingBox {
168 let mut min = [0.0_f32; 3];
169 let mut max = [0.0_f32; 3];
170 unsafe {
172 ffi::mdl_object_bounding_box_at_time(
173 self.handle.as_ptr(),
174 time,
175 &mut min[0],
176 &mut min[1],
177 &mut min[2],
178 &mut max[0],
179 &mut max[1],
180 &mut max[2],
181 );
182 }
183 BoundingBox { min, max }
184 }
185
186 #[must_use]
187 pub fn as_mesh(&self) -> Option<Mesh> {
189 (self.kind() == ObjectKind::Mesh).then(|| Mesh::from_handle(self.handle.clone()))
190 }
191
192 #[must_use]
193 pub fn as_light(&self) -> Option<Light> {
195 matches!(
196 self.kind(),
197 ObjectKind::Light | ObjectKind::PhysicallyPlausibleLight
198 )
199 .then(|| Light::from_handle(self.handle.clone()))
200 }
201
202 #[must_use]
203 pub fn as_physically_plausible_light(&self) -> Option<PhysicallyPlausibleLight> {
205 (self.kind() == ObjectKind::PhysicallyPlausibleLight)
206 .then(|| PhysicallyPlausibleLight::from_handle(self.handle.clone()))
207 }
208
209 #[must_use]
210 pub fn as_camera(&self) -> Option<Camera> {
212 (self.kind() == ObjectKind::Camera).then(|| Camera::from_handle(self.handle.clone()))
213 }
214
215 #[must_use]
216 pub fn as_voxel_array(&self) -> Option<VoxelArray> {
218 (self.kind() == ObjectKind::VoxelArray)
219 .then(|| VoxelArray::from_handle(self.handle.clone()))
220 }
221
222 #[must_use]
223 pub fn as_skeleton(&self) -> Option<Skeleton> {
225 (self.kind() == ObjectKind::Skeleton).then(|| Skeleton::from_handle(self.handle.clone()))
226 }
227
228 #[must_use]
229 pub fn as_packed_joint_animation(&self) -> Option<PackedJointAnimation> {
231 (self.kind() == ObjectKind::PackedJointAnimation)
232 .then(|| PackedJointAnimation::from_handle(self.handle.clone()))
233 }
234}
235
236#[derive(Debug, Clone)]
237pub struct ObjectContainer {
239 handle: ObjectHandle,
240}
241
242impl Component for ObjectContainer {}
243
244impl ObjectContainerComponent for ObjectContainer {
245 fn count(&self) -> usize {
246 self.count()
247 }
248
249 fn object_at(&self, index: usize) -> Option<Object> {
250 self.object_at(index)
251 }
252
253 fn add_object(&self, object: &Object) {
254 self.add_object(object);
255 }
256
257 fn remove_object(&self, object: &Object) {
258 self.remove_object(object);
259 }
260}
261
262impl ObjectContainer {
263 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
265 Self { handle }
266 }
267
268 pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
270 self.handle.as_ptr()
271 }
272
273 pub fn new() -> Result<Self> {
275 let mut out_container = ptr::null_mut();
276 let mut out_error = ptr::null_mut();
277 let status = unsafe { ffi::mdl_object_container_new(&mut out_container, &mut out_error) };
279 crate::util::status_result(status, out_error)?;
280 Ok(Self::from_handle(required_handle(
281 out_container,
282 "MDLObjectContainer",
283 )?))
284 }
285
286 #[must_use]
287 pub fn count(&self) -> usize {
289 unsafe { ffi::mdl_object_container_count(self.handle.as_ptr()) as usize }
291 }
292
293 #[must_use]
294 pub fn object_at(&self, index: usize) -> Option<Object> {
296 let ptr =
297 unsafe { ffi::mdl_object_container_object_at(self.handle.as_ptr(), index as u64) };
299 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Object::from_handle)
301 }
302
303 #[must_use]
304 pub fn objects(&self) -> Vec<Object> {
306 (0..self.count())
307 .filter_map(|index| self.object_at(index))
308 .collect()
309 }
310
311 pub fn add_object(&self, object: &Object) {
313 unsafe { ffi::mdl_object_container_add_object(self.handle.as_ptr(), object.as_ptr()) };
315 }
316
317 pub fn remove_object(&self, object: &Object) {
319 unsafe { ffi::mdl_object_container_remove_object(self.handle.as_ptr(), object.as_ptr()) };
321 }
322}