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::{Chop, Cop, Obj, Rop, Top};
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_or_else(|_| Cow::Borrowed("Node path not available"), Cow::Owned),
370 )
371 .finish_non_exhaustive()
372 }
373}
374
375impl From<HoudiniNode> for NodeHandle {
376 fn from(n: HoudiniNode) -> Self {
377 n.handle
378 }
379}
380
381impl From<HoudiniNode> for Option<NodeHandle> {
382 fn from(n: HoudiniNode) -> Self {
383 Some(n.handle)
384 }
385}
386
387impl From<&HoudiniNode> for Option<NodeHandle> {
388 fn from(n: &HoudiniNode) -> Self {
389 Some(n.handle)
390 }
391}
392
393impl From<&HoudiniNode> for NodeHandle {
394 fn from(n: &HoudiniNode) -> Self {
395 n.handle
396 }
397}
398
399impl HoudiniNode {
400 pub(crate) fn new(
401 session: Session,
402 handle: NodeHandle,
403 info: Option<NodeInfo>,
404 ) -> Result<Self> {
405 let info = Arc::new(match info {
406 None => NodeInfo::new(&session, handle)?,
407 Some(i) => i,
408 });
409 Ok(HoudiniNode {
410 handle,
411 session,
412 info,
413 })
414 }
415
416 #[must_use]
418 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 #[allow(unused)]
585 pub(crate) fn get_sop_output_node(&self, index: i32) -> Result<NodeHandle> {
586 debug_assert!(self.is_valid()?);
587 crate::ffi::get_sop_output_node(&self.session, self.handle, index)
588 }
589
590 #[must_use]
592 pub fn parent_node(&self) -> Option<NodeHandle> {
593 let handle = self.info.parent_id();
594 (handle.0 > -1).then_some(handle)
595 }
596
597 pub fn parameter(&self, name: &str) -> Result<Parameter> {
599 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
600 let parm_info = ParmInfo::from_parm_name(name, self)?;
601 Ok(Parameter::new(self.handle, parm_info))
602 }
603
604 pub fn parameter_with_tag(&self, tag: &str) -> Result<Option<Parameter>> {
606 let tag = CString::new(tag)?;
607 match crate::ffi::get_parm_with_tag(self, &tag)? {
608 -1 => Ok(None),
609 h => {
610 let parm_info =
611 ParmInfo::from_parm_handle(ParmHandle(h), self.handle, &self.session)?;
612 Ok(Some(Parameter::new(self.handle, parm_info)))
613 }
614 }
615 }
616
617 pub fn parameters(&self) -> Result<Vec<Parameter>> {
619 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
620 let infos = crate::ffi::get_parameters(self)?;
621 Ok(infos
622 .into_iter()
623 .map(|info| {
624 Parameter::new(self.handle, ParmInfo::new(info, self.session.clone(), None))
625 })
626 .collect())
627 }
628
629 pub fn asset_info(&self) -> Result<AssetInfo> {
631 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
632 self.handle.asset_info(&self.session)
633 }
634 pub fn check_for_specific_error(&self, error_bits: i32) -> Result<i32> {
636 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
637 crate::ffi::check_for_specific_errors(self, error_bits)
638 }
639
640 pub fn get_composed_cook_result_string(&self, verbosity: StatusVerbosity) -> Result<String> {
642 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
643 let bytes = crate::ffi::get_composed_cook_result(self, verbosity)?;
644 String::from_utf8(bytes).map_err(crate::errors::HapiError::from)
645 }
646
647 pub fn get_cook_result_string(&self, verbosity: StatusVerbosity) -> Result<String> {
649 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
650 let bytes = crate::ffi::get_node_cook_result(self, verbosity)?;
651 Ok(String::from_utf8_lossy(&bytes).to_string())
652 }
653 pub fn reset_simulation(&self) -> Result<()> {
655 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
656 crate::ffi::reset_simulation(self)
657 }
658
659 pub fn input_node(&self, idx: i32) -> Result<Option<HoudiniNode>> {
661 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
662 crate::ffi::query_node_input(self, idx).map(|idx| {
663 if idx == -1 {
664 None
665 } else {
666 HoudiniNode::new(self.session.clone(), NodeHandle(idx), None).ok()
667 }
668 })
669 }
670
671 pub fn rename(&self, new_name: impl AsRef<str>) -> Result<()> {
673 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
674 let name = CString::new(new_name.as_ref())?;
675 crate::ffi::rename_node(self, &name)
676 }
677
678 pub fn save_to_file(&self, file: impl AsRef<Path>) -> Result<()> {
680 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
681 let filename = CString::new(file.as_ref().to_string_lossy().to_string())?;
682 crate::ffi::save_node_to_file(self.handle, &self.session, &filename)
683 }
684
685 pub fn load_from_file(
687 session: &Session,
688 parent: impl Into<Option<NodeHandle>>,
689 label: &str,
690 cook: bool,
691 file: impl AsRef<OsStr>,
692 ) -> Result<HoudiniNode> {
693 debug_assert!(session.is_valid());
694 debug!("Loading node from file {}", file.as_ref().display());
695 let filename = CString::new(file.as_ref().to_string_lossy().to_string())?;
696 let label = CString::new(label)?;
697 let id = crate::ffi::load_node_from_file(parent.into(), session, &label, &filename, cook)?;
698 NodeHandle(id).to_node(session)
699 }
700
701 pub fn get_preset(&self, name: &str, preset_type: PresetType) -> Result<Vec<i8>> {
703 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
704 let name = CString::new(name)?;
705 crate::ffi::get_preset(&self.session, self.handle, &name, preset_type)
706 }
707
708 pub fn set_preset(&self, name: &str, preset_type: PresetType, data: &[i8]) -> Result<()> {
710 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
711 let name = CString::new(name)?;
712 crate::ffi::set_preset(&self.session, self.handle, &name, preset_type, data)
713 }
714
715 pub fn geometry(&self) -> Result<Option<Geometry>> {
718 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
719 match self.info.node_type() {
720 NodeType::Sop => Ok(Some(Geometry {
721 node: self.clone(),
722 info: GeoInfo::from_node(self)?,
723 })),
724 NodeType::Obj => {
725 let info = crate::ffi::get_geo_display_info(self).map(GeoInfo)?;
726 Ok(Some(Geometry {
727 node: info.node_id().to_node(&self.session)?,
728 info,
729 }))
730 }
731 _ => Ok(None),
732 }
733 }
734
735 pub fn find_top_networks(&self) -> Result<Vec<HoudiniNode>> {
737 find_networks_nodes(&self.session, NodeType::Top, self, true)
738 }
739
740 pub fn number_of_geo_outputs(&self) -> Result<i32> {
742 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
743 crate::ffi::get_output_geo_count(self)
744 }
745
746 pub fn get_output_names(&self) -> Result<Vec<String>> {
748 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
749 crate::ffi::get_output_names(self)
750 }
751
752 pub fn geometry_output_nodes(&self) -> Result<Vec<Geometry>> {
754 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
755 crate::ffi::get_output_geos(self).map(|vec| {
756 vec.into_iter()
757 .map(|inner| {
758 NodeHandle(inner.nodeId)
759 .to_node(&self.session)
760 .map(|node| Geometry {
761 node,
762 info: GeoInfo(inner),
763 })
764 })
765 .collect::<Result<Vec<_>>>()
766 })?
767 }
768
769 pub fn get_transform(
771 &self,
772 rst_order: Option<RSTOrder>,
773 relative_to: impl Into<Option<NodeHandle>>,
774 ) -> Result<Transform> {
775 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
776 crate::ffi::get_object_transform(
777 &self.session,
778 self.handle,
779 relative_to.into(),
780 rst_order.unwrap_or(RSTOrder::Default),
781 )
782 .map(Transform)
783 }
784
785 pub fn set_transform(&self, transform: &TransformEuler) -> Result<()> {
787 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
788 crate::ffi::set_object_transform(&self.session, self.handle, &transform.0)
789 }
790
791 pub fn set_transform_anim_curve(
793 &self,
794 component: TransformComponent,
795 keys: &[KeyFrame],
796 ) -> Result<()> {
797 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
798 let keys = unsafe {
800 &*(std::ptr::from_ref::<[crate::ffi::structs::KeyFrame]>(keys)
801 as *const [crate::ffi::raw::HAPI_Keyframe])
802 };
803 crate::ffi::set_transform_anim_curve(&self.session, self.handle, component, keys)
804 }
805
806 pub fn connect_input<H: Into<NodeHandle>>(
808 &self,
809 input_num: i32,
810 source: H,
811 output_num: i32,
812 ) -> Result<()> {
813 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
814 crate::ffi::connect_node_input(
815 &self.session,
816 self.handle,
817 input_num,
818 source.into(),
819 output_num,
820 )
821 }
822
823 pub fn output_connected_nodes(
825 &self,
826 output_index: i32,
827 search_subnets: bool,
828 ) -> Result<Vec<NodeHandle>> {
829 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
830 crate::ffi::query_node_output_connected_nodes(self, output_index, search_subnets)
831 }
832
833 pub fn disconnect_input(&self, input_index: i32) -> Result<()> {
835 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
836 crate::ffi::disconnect_node_input(self, input_index)
837 }
838
839 pub fn disconnect_outputs(&self, output_index: i32) -> Result<()> {
841 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
842 crate::ffi::disconnect_node_outputs(self, output_index)
843 }
844
845 pub fn set_display_flag(&self, on: bool) -> Result<()> {
847 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
848 crate::ffi::set_node_display(&self.session, self.handle, on)
849 }
850
851 pub fn get_input_name(&self, input_index: i32) -> Result<String> {
853 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
854 crate::ffi::get_node_input_name(self, input_index)
855 }
856
857 pub fn get_message_nodes(&self) -> Result<Vec<NodeHandle>> {
859 debug_assert!(self.is_valid()?, "Invalid node: {}", self.path()?);
860 crate::ffi::get_message_node_ids(self)
861 }
862}