1use std::borrow::Cow;
10use std::path::Path;
11use std::str::FromStr;
12use std::sync::Arc;
13use std::{ffi::CString, ffi::OsStr, fmt::Formatter};
14
15use log::debug;
16
17use crate::pdg::TopNode;
18pub use crate::{
19 errors::Result,
20 ffi::{AssetInfo, GeoInfo, KeyFrame, NodeInfo, ObjectInfo, ParmInfo},
21 geometry::Geometry,
22 parameter::*,
23 session::{CookResult, Session},
24};
25pub use crate::{
26 ffi::raw::{
27 ErrorCode, NodeFlags, NodeType, PresetType, RSTOrder, State, StatusType, StatusVerbosity,
28 TransformComponent,
29 },
30 ffi::{CookOptions, Transform, TransformEuler},
31};
32
33impl std::fmt::Display for NodeType {
34 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
35 f.write_str(match *self {
36 NodeType::Sop => "Sop",
37 NodeType::Obj => "Obj",
38 NodeType::Rop => "Rop",
39 NodeType::Dop => "Dop",
40 NodeType::Cop => "Cop",
41 NodeType::Shop => "Shop",
42 NodeType::Vop => "Vop",
43 NodeType::Chop => "Chop",
44 _ => "Unknown",
45 })
46 }
47}
48
49#[repr(transparent)]
50#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
51pub struct NodeTypeBits(crate::ffi::raw::HAPI_NodeTypeBits);
52#[repr(transparent)]
53#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
54pub struct NodeFlagsBits(crate::ffi::raw::HAPI_NodeFlagsBits);
55
56impl From<NodeTypeBits> for crate::ffi::raw::HAPI_NodeTypeBits {
57 fn from(value: NodeTypeBits) -> Self {
58 value.0
59 }
60}
61
62impl From<NodeFlagsBits> for crate::ffi::raw::HAPI_NodeFlagsBits {
63 fn from(value: NodeFlagsBits) -> Self {
64 value.0
65 }
66}
67
68pub trait ToNodeTypeBits {
70 fn to_bits(self) -> NodeTypeBits;
71}
72
73pub trait ToNodeFlagsBits {
75 fn to_bits(self) -> NodeFlagsBits;
76}
77
78impl ToNodeTypeBits for NodeType {
79 fn to_bits(self) -> NodeTypeBits {
80 NodeTypeBits(self as crate::ffi::raw::HAPI_NodeTypeBits)
81 }
82}
83
84impl ToNodeFlagsBits for NodeFlags {
85 fn to_bits(self) -> NodeFlagsBits {
86 NodeFlagsBits(self as crate::ffi::raw::HAPI_NodeFlagsBits)
87 }
88}
89
90impl ToNodeTypeBits for NodeTypeBits {
91 fn to_bits(self) -> NodeTypeBits {
92 NodeTypeBits(self.0)
93 }
94}
95
96impl ToNodeFlagsBits for NodeFlagsBits {
97 fn to_bits(self) -> NodeFlagsBits {
98 NodeFlagsBits(self.0)
99 }
100}
101
102impl std::ops::BitOr for NodeFlags {
103 type Output = NodeFlagsBits;
104 fn bitor(self, rhs: Self) -> Self::Output {
105 NodeFlagsBits(
106 (self as crate::ffi::raw::HAPI_NodeFlagsBits)
107 | (rhs as crate::ffi::raw::HAPI_NodeFlagsBits),
108 )
109 }
110}
111
112impl std::ops::BitOr for NodeType {
113 type Output = NodeTypeBits;
114 fn bitor(self, rhs: Self) -> Self::Output {
115 NodeTypeBits(
116 (self as crate::ffi::raw::HAPI_NodeTypeBits)
117 | (rhs as crate::ffi::raw::HAPI_NodeTypeBits),
118 )
119 }
120}
121
122impl std::ops::BitOr for NodeTypeBits {
124 type Output = NodeTypeBits;
125 fn bitor(self, rhs: Self) -> Self::Output {
126 NodeTypeBits(self.0 | rhs.0)
127 }
128}
129
130impl std::ops::BitOr for NodeFlagsBits {
131 type Output = NodeFlagsBits;
132 fn bitor(self, rhs: Self) -> Self::Output {
133 NodeFlagsBits(self.0 | rhs.0)
134 }
135}
136
137impl std::ops::BitOr<NodeFlags> for NodeFlagsBits {
138 type Output = NodeFlagsBits;
139 fn bitor(self, rhs: NodeFlags) -> Self::Output {
140 NodeFlagsBits(self.0 | (rhs as crate::ffi::raw::HAPI_NodeFlagsBits))
141 }
142}
143
144impl std::ops::BitOr<NodeType> for NodeTypeBits {
145 type Output = NodeTypeBits;
146 fn bitor(self, rhs: NodeType) -> Self::Output {
147 NodeTypeBits(self.0 | (rhs as crate::ffi::raw::HAPI_NodeTypeBits))
148 }
149}
150
151#[derive(Debug, Copy, Clone)]
153#[non_exhaustive]
154pub enum ManagerType {
155 Obj,
156 Chop,
157 Cop,
158 Rop,
159 Top,
160}
161
162impl FromStr for ManagerType {
163 type Err = crate::HapiError;
164
165 fn from_str(val: &str) -> Result<Self> {
166 match val {
167 "Cop2" => Ok(Self::Cop),
168 "Chop" => Ok(Self::Chop),
169 "Top" => Ok(Self::Top),
170 "Object" => Ok(Self::Obj),
171 "Driver" => Ok(Self::Rop),
172 v => Err(crate::HapiError::Internal(format!(
173 "Unknown ManagerType::{v}"
174 ))),
175 }
176 }
177}
178
179impl From<ManagerType> for NodeType {
180 fn from(value: ManagerType) -> Self {
181 use ManagerType::*;
182 match value {
183 Obj => NodeType::Obj,
184 Chop => NodeType::Chop,
185 Cop => NodeType::Cop,
186 Rop => NodeType::Rop,
187 Top => NodeType::Top,
188 }
189 }
190}
191
192fn get_child_node_list(
194 session: &Session,
195 parent: impl Into<NodeHandle>,
196 types: NodeTypeBits,
197 flags: NodeFlagsBits,
198 recursive: bool,
199) -> Result<Vec<NodeHandle>> {
200 let ids =
201 crate::ffi::get_compose_child_node_list(session, parent.into(), types, flags, recursive)?;
202 Ok(ids.into_iter().map(NodeHandle).collect())
203}
204
205fn find_networks_nodes(
207 session: &Session,
208 types: NodeType,
209 parent: impl Into<NodeHandle>,
210 recursive: bool,
211) -> Result<Vec<HoudiniNode>> {
212 debug_assert!(session.is_valid());
213 get_child_node_list(
214 session,
215 parent,
216 types.to_bits(),
217 NodeFlags::Network.to_bits(),
218 recursive,
219 )
220 .map(|vec| {
221 vec.into_iter()
222 .map(|handle| handle.to_node(session))
223 .collect::<Result<Vec<_>>>()
224 })?
225}
226
227#[derive(Debug, Clone)]
228pub struct ManagerNode {
230 pub session: Session,
231 pub handle: NodeHandle,
232 pub node_type: ManagerType,
233}
234
235impl ManagerNode {
236 pub fn find_network_nodes(&self, types: NodeType) -> Result<Vec<HoudiniNode>> {
238 find_networks_nodes(&self.session, types, self.handle, true)
239 }
240
241 pub fn get_children(&self) -> Result<Vec<NodeHandle>> {
243 get_child_node_list(
244 &self.session,
245 self.handle,
246 NodeType::from(self.node_type).to_bits(),
247 NodeFlags::Any.to_bits(),
248 false,
249 )
250 }
251}
252
253#[repr(transparent)]
254#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
255pub struct NodeHandle(pub(crate) crate::ffi::raw::HAPI_NodeId);
259
260impl From<NodeHandle> for crate::ffi::raw::HAPI_NodeId {
261 fn from(h: NodeHandle) -> Self {
262 h.0
263 }
264}
265
266impl AsRef<NodeHandle> for HoudiniNode {
267 fn as_ref(&self) -> &NodeHandle {
268 &self.handle
269 }
270}
271
272impl AsRef<NodeHandle> for NodeHandle {
273 fn as_ref(&self) -> &NodeHandle {
274 self
275 }
276}
277
278impl Default for NodeHandle {
279 fn default() -> Self {
280 NodeHandle(-1)
281 }
282}
283
284impl NodeHandle {
285 pub fn info(&self, session: &Session) -> Result<NodeInfo> {
287 NodeInfo::new(session, *self)
288 }
289
290 pub fn asset_info(&self, session: &Session) -> Result<AssetInfo> {
291 Ok(AssetInfo(
292 crate::ffi::get_asset_info(session, *self)?,
293 session.clone().into(),
294 ))
295 }
296
297 pub fn path(&self, session: &Session) -> Result<String> {
299 debug_assert!(self.is_valid(session)?, "Invalid {:?}", self);
300 crate::ffi::get_node_path(session, *self, None)
301 }
302
303 pub fn path_relative(
305 &self,
306 session: &Session,
307 to: impl Into<Option<NodeHandle>>,
308 ) -> Result<String> {
309 debug_assert!(self.is_valid(session)?, "Invalid {:?}", self);
310 crate::ffi::get_node_path(session, *self, to.into())
311 }
312
313 pub fn is_valid(&self, session: &Session) -> Result<bool> {
315 let info = self.info(session)?;
316 crate::ffi::is_node_valid(session, &info.0)
317 }
318
319 pub fn to_node(&self, session: &Session) -> Result<HoudiniNode> {
321 HoudiniNode::new(session.clone(), *self, None)
322 }
323
324 pub fn as_geometry_node(&self, session: &Session) -> Result<Option<Geometry>> {
326 let info = self.info(session)?;
327 match info.node_type() {
328 NodeType::Sop => Ok(Some(Geometry {
329 node: HoudiniNode::new(session.clone(), *self, Some(info))?,
330 info: GeoInfo::from_handle(*self, session)?,
331 })),
332 _ => Ok(None),
333 }
334 }
335
336 pub fn as_top_node(&self, session: &Session) -> Result<Option<TopNode>> {
338 let node = self.to_node(session)?;
339 match node.info.node_type() {
340 NodeType::Top => Ok(Some(TopNode { node })),
341 _ => Ok(None),
342 }
343 }
344}
345
346#[derive(Clone)]
347pub struct HoudiniNode {
349 pub handle: NodeHandle,
350 pub session: Session,
351 pub info: Arc<NodeInfo>,
352}
353
354impl PartialEq for HoudiniNode {
355 fn eq(&self, other: &Self) -> bool {
356 self.handle == other.handle && self.session == other.session
357 }
358}
359
360impl std::fmt::Debug for HoudiniNode {
361 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
362 f.debug_struct("HoudiniNode")
363 .field("id", &self.handle.0)
364 .field("type", &self.info.node_type())
365 .field(
366 "path",
367 &self
368 .path()
369 .map(Cow::Owned)
370 .unwrap_or_else(|_| Cow::Borrowed("Node path not available")),
371 )
372 .finish()
373 }
374}
375
376impl From<HoudiniNode> for NodeHandle {
377 fn from(n: HoudiniNode) -> Self {
378 n.handle
379 }
380}
381
382impl From<HoudiniNode> for Option<NodeHandle> {
383 fn from(n: HoudiniNode) -> Self {
384 Some(n.handle)
385 }
386}
387
388impl From<&HoudiniNode> for Option<NodeHandle> {
389 fn from(n: &HoudiniNode) -> Self {
390 Some(n.handle)
391 }
392}
393
394impl From<&HoudiniNode> for NodeHandle {
395 fn from(n: &HoudiniNode) -> Self {
396 n.handle
397 }
398}
399
400impl HoudiniNode {
401 pub(crate) fn new(
402 session: Session,
403 handle: NodeHandle,
404 info: Option<NodeInfo>,
405 ) -> Result<Self> {
406 let info = Arc::new(match info {
407 None => NodeInfo::new(&session, handle)?,
408 Some(i) => i,
409 });
410 Ok(HoudiniNode {
411 handle,
412 session,
413 info,
414 })
415 }
416
417 pub fn to_top_node(self) -> Option<TopNode> {
419 match self.info.node_type() {
420 NodeType::Top => Some(TopNode { node: self }),
421 _ => None,
422 }
423 }
424 pub fn delete(self) -> Result<()> {
426 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
427 crate::ffi::delete_node(self.handle, &self.session)
428 }
429
430 pub fn is_valid(&self) -> Result<bool> {
432 self.handle.is_valid(&self.session)
433 }
434
435 pub fn name(&self) -> Result<String> {
436 self.info.name()
437 }
438
439 pub fn path(&self) -> Result<String> {
441 self.handle.path(&self.session)
442 }
443
444 pub fn path_relative(&self, to: impl Into<Option<NodeHandle>>) -> Result<String> {
446 self.handle.path_relative(&self.session, to)
447 }
448
449 #[must_use = "cook may fail or return errors, check the result"]
451 pub fn cook(&self) -> Result<()> {
452 debug!("Start cooking node: {}", self.path()?);
453 debug_assert!(self.is_valid()?);
454 crate::ffi::cook_node(self, None)
455 }
456
457 #[must_use = "cook may fail or return errors, check the result"]
461 pub fn cook_blocking(&self) -> Result<CookResult> {
462 debug!("Start cooking node: {}", self.path()?);
463 debug_assert!(self.is_valid()?);
464 crate::ffi::cook_node(self, None)?;
465 self.session.cook()
466 }
467
468 #[must_use = "cook may fail or return errors, check the result"]
470 pub fn cook_with_options(&self, options: &CookOptions, blocking: bool) -> Result<CookResult> {
471 debug!("Start cooking node: {}", self.path()?);
472 debug_assert!(self.is_valid()?);
473 crate::ffi::cook_node(self, Some(options))?;
474 if blocking {
475 self.session.cook()
476 } else {
477 Ok(CookResult::Succeeded)
478 }
479 }
480
481 pub fn cook_count(
483 &self,
484 node_types: impl ToNodeTypeBits,
485 node_flags: impl ToNodeFlagsBits,
486 recurse: bool,
487 ) -> Result<i32> {
488 debug_assert!(self.is_valid()?);
489 crate::ffi::get_total_cook_count(self, node_types.to_bits(), node_flags.to_bits(), recurse)
490 }
491
492 pub fn get_object_info(&self) -> Result<ObjectInfo<'_>> {
494 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
495 crate::ffi::get_object_info(&self.session, self.handle)
496 .map(|info| ObjectInfo(info, (&self.session).into()))
497 }
498
499 pub fn get_info(&self) -> Result<NodeInfo> {
501 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
502 self.handle.info(&self.session)
503 }
504
505 pub fn get_objects_info(&self) -> Result<Vec<ObjectInfo<'_>>> {
507 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
508 let parent = match self.info.node_type() {
509 NodeType::Obj => self.info.parent_id(),
510 _ => self.handle,
511 };
512 let infos = crate::ffi::get_composed_object_list(&self.session, parent)?;
513 Ok(infos
514 .into_iter()
515 .map(|inner| ObjectInfo(inner, (&self.session).into()))
516 .collect())
517 }
518
519 pub fn get_children_by_type(
521 &self,
522 types: impl ToNodeTypeBits,
523 flags: impl ToNodeFlagsBits,
524 recursive: bool,
525 ) -> Result<Vec<NodeHandle>> {
526 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
527 get_child_node_list(
528 &self.session,
529 self,
530 types.to_bits(),
531 flags.to_bits(),
532 recursive,
533 )
534 }
535
536 pub fn get_children(&self) -> Result<Vec<NodeHandle>> {
538 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
539 get_child_node_list(
540 &self.session,
541 self,
542 NodeType::Any.to_bits(),
543 NodeFlags::Any.to_bits(),
544 false,
545 )
546 }
547
548 pub fn get_child_by_path(&self, relative_path: &str) -> Result<Option<HoudiniNode>> {
550 self.session
551 .get_node_from_path(relative_path, Some(self.handle))
552 }
553
554 pub fn get_instanced_object_ids(&self) -> Result<Vec<NodeHandle>> {
556 crate::ffi::get_instanced_object_ids(self)
557 }
558
559 pub fn find_child_node(
561 &self,
562 name: impl AsRef<str>,
563 recursive: bool,
564 ) -> Result<Option<HoudiniNode>> {
565 debug_assert!(self.is_valid()?);
566 if !recursive {
567 return self.get_child_by_path(name.as_ref());
568 }
569 for handle in self.get_children_by_type(NodeType::Any, NodeFlags::Any, recursive)? {
570 let info = handle.info(&self.session)?;
571 if info.name()? == name.as_ref() {
572 return Ok(Some(HoudiniNode::new(
573 self.session.clone(),
574 handle,
575 Some(info),
576 )?));
577 }
578 }
579 Ok(None)
580 }
581
582 pub fn get_sop_output_node(&self, index: i32) -> Result<NodeHandle> {
584 debug_assert!(self.is_valid()?);
585 crate::ffi::get_sop_output_node(&self.session, self.handle, index)
586 }
587
588 pub fn parent_node(&self) -> Option<NodeHandle> {
590 let handle = self.info.parent_id();
591 (handle.0 > -1).then_some(handle)
592 }
593
594 pub fn parameter(&self, name: &str) -> Result<Parameter> {
596 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
597 let parm_info = ParmInfo::from_parm_name(name, self)?;
598 Ok(Parameter::new(self.handle, parm_info))
599 }
600
601 pub fn parameter_with_tag(&self, tag: &str) -> Result<Option<Parameter>> {
603 let tag = CString::new(tag)?;
604 match crate::ffi::get_parm_with_tag(self, &tag)? {
605 -1 => Ok(None),
606 h => {
607 let parm_info =
608 ParmInfo::from_parm_handle(ParmHandle(h), self.handle, &self.session)?;
609 Ok(Some(Parameter::new(self.handle, parm_info)))
610 }
611 }
612 }
613
614 pub fn parameters(&self) -> Result<Vec<Parameter>> {
616 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
617 let infos = crate::ffi::get_parameters(self)?;
618 Ok(infos
619 .into_iter()
620 .map(|info| {
621 Parameter::new(self.handle, ParmInfo::new(info, self.session.clone(), None))
622 })
623 .collect())
624 }
625
626 pub fn asset_info(&self) -> Result<AssetInfo> {
628 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
629 self.handle.asset_info(&self.session)
630 }
631 pub fn check_for_specific_error(&self, error_bits: i32) -> Result<ErrorCode> {
633 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
634 crate::ffi::check_for_specific_errors(self, error_bits)
635 }
636
637 pub fn get_composed_cook_result_string(&self, verbosity: StatusVerbosity) -> Result<String> {
639 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
640 let bytes = crate::ffi::get_composed_cook_result(self, verbosity)?;
641 String::from_utf8(bytes).map_err(crate::errors::HapiError::from)
642 }
643
644 pub fn get_cook_result_string(&self, verbosity: StatusVerbosity) -> Result<String> {
646 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
647 let bytes = crate::ffi::get_node_cook_result(self, verbosity)?;
648 Ok(String::from_utf8_lossy(&bytes).to_string())
649 }
650 pub fn reset_simulation(&self) -> Result<()> {
652 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
653 crate::ffi::reset_simulation(self)
654 }
655
656 pub fn input_node(&self, idx: i32) -> Result<Option<HoudiniNode>> {
658 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
659 crate::ffi::query_node_input(self, idx).map(|idx| {
660 if idx == -1 {
661 None
662 } else {
663 HoudiniNode::new(self.session.clone(), NodeHandle(idx), None).ok()
664 }
665 })
666 }
667
668 pub fn rename(&self, new_name: impl AsRef<str>) -> Result<()> {
670 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
671 let name = CString::new(new_name.as_ref())?;
672 crate::ffi::rename_node(self, &name)
673 }
674
675 pub fn save_to_file(&self, file: impl AsRef<Path>) -> Result<()> {
677 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
678 let filename = CString::new(file.as_ref().to_string_lossy().to_string())?;
679 crate::ffi::save_node_to_file(self.handle, &self.session, &filename)
680 }
681
682 pub fn load_from_file(
684 session: &Session,
685 parent: impl Into<Option<NodeHandle>>,
686 label: &str,
687 cook: bool,
688 file: impl AsRef<OsStr>,
689 ) -> Result<HoudiniNode> {
690 debug_assert!(session.is_valid());
691 debug!("Loading node from file {:?}", file.as_ref());
692 let filename = CString::new(file.as_ref().to_string_lossy().to_string())?;
693 let label = CString::new(label)?;
694 let id = crate::ffi::load_node_from_file(parent.into(), session, &label, &filename, cook)?;
695 NodeHandle(id).to_node(session)
696 }
697
698 pub fn get_preset(&self, name: &str, preset_type: PresetType) -> Result<Vec<i8>> {
700 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
701 let name = CString::new(name)?;
702 crate::ffi::get_preset(&self.session, self.handle, &name, preset_type)
703 }
704
705 pub fn set_preset(&self, name: &str, preset_type: PresetType, data: &[i8]) -> Result<()> {
707 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
708 let name = CString::new(name)?;
709 crate::ffi::set_preset(&self.session, self.handle, &name, preset_type, data)
710 }
711
712 pub fn geometry(&self) -> Result<Option<Geometry>> {
715 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
716 match self.info.node_type() {
717 NodeType::Sop => Ok(Some(Geometry {
718 node: self.clone(),
719 info: GeoInfo::from_node(self)?,
720 })),
721 NodeType::Obj => {
722 let info = crate::ffi::get_geo_display_info(self).map(GeoInfo)?;
723 Ok(Some(Geometry {
724 node: info.node_id().to_node(&self.session)?,
725 info,
726 }))
727 }
728 _ => Ok(None),
729 }
730 }
731
732 pub fn find_top_networks(&self) -> Result<Vec<HoudiniNode>> {
734 find_networks_nodes(&self.session, NodeType::Top, self, true)
735 }
736
737 pub fn number_of_geo_outputs(&self) -> Result<i32> {
739 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
740 crate::ffi::get_output_geo_count(self)
741 }
742
743 pub fn get_output_names(&self) -> Result<Vec<String>> {
745 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
746 crate::ffi::get_output_names(self)
747 }
748
749 pub fn geometry_output_nodes(&self) -> Result<Vec<Geometry>> {
751 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
752 crate::ffi::get_output_geos(self).map(|vec| {
753 vec.into_iter()
754 .map(|inner| {
755 NodeHandle(inner.nodeId)
756 .to_node(&self.session)
757 .map(|node| Geometry {
758 node,
759 info: GeoInfo(inner),
760 })
761 })
762 .collect::<Result<Vec<_>>>()
763 })?
764 }
765
766 pub fn get_transform(
768 &self,
769 rst_order: Option<RSTOrder>,
770 relative_to: impl Into<Option<NodeHandle>>,
771 ) -> Result<Transform> {
772 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
773 crate::ffi::get_object_transform(
774 &self.session,
775 self.handle,
776 relative_to.into(),
777 rst_order.unwrap_or(RSTOrder::Default),
778 )
779 .map(Transform)
780 }
781
782 pub fn set_transform(&self, transform: &TransformEuler) -> Result<()> {
784 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
785 crate::ffi::set_object_transform(&self.session, self.handle, &transform.0)
786 }
787
788 pub fn set_transform_anim_curve(
790 &self,
791 component: TransformComponent,
792 keys: &[KeyFrame],
793 ) -> Result<()> {
794 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
795 let keys =
796 unsafe { std::mem::transmute::<&[KeyFrame], &[crate::ffi::raw::HAPI_Keyframe]>(keys) };
797 crate::ffi::set_transform_anim_curve(&self.session, self.handle, component, keys)
798 }
799
800 pub fn connect_input<H: Into<NodeHandle>>(
802 &self,
803 input_num: i32,
804 source: H,
805 output_num: i32,
806 ) -> Result<()> {
807 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
808 crate::ffi::connect_node_input(
809 &self.session,
810 self.handle,
811 input_num,
812 source.into(),
813 output_num,
814 )
815 }
816
817 pub fn output_connected_nodes(
819 &self,
820 output_index: i32,
821 search_subnets: bool,
822 ) -> Result<Vec<NodeHandle>> {
823 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
824 crate::ffi::query_node_output_connected_nodes(self, output_index, search_subnets)
825 }
826
827 pub fn disconnect_input(&self, input_index: i32) -> Result<()> {
829 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
830 crate::ffi::disconnect_node_input(self, input_index)
831 }
832
833 pub fn disconnect_outputs(&self, output_index: i32) -> Result<()> {
835 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
836 crate::ffi::disconnect_node_outputs(self, output_index)
837 }
838
839 pub fn set_display_flag(&self, on: bool) -> Result<()> {
841 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
842 crate::ffi::set_node_display(&self.session, self.handle, on)
843 }
844
845 pub fn get_input_name(&self, input_index: i32) -> Result<String> {
847 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
848 crate::ffi::get_node_input_name(self, input_index)
849 }
850
851 pub fn get_message_nodes(&self) -> Result<Vec<NodeHandle>> {
853 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
854 crate::ffi::get_message_node_ids(self)
855 }
856}