hapi_rs/
node.rs

1//! Manipulating Houdini nodes and networks, getting geometry and parameters
2//!
3//! Any Houdini nodes is represented as [`HoudiniNode`] struct and all node-related functions are exposed as
4//! methods on that struct. It has a public `info` filed with [`NodeInfo`] with details about the node.
5//!
6//! Nodes can be created with [`Session::create_node`]
7//!
8//! HoudiniNode is ['Clone'], [`Sync`] and [`Send`]
9use 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
68/// Trait to convert a NodeType to a NodeTypeBits
69pub trait ToNodeTypeBits {
70    fn to_bits(self) -> NodeTypeBits;
71}
72
73/// Trait to convert a NodeFlags to a NodeFlagsBits
74pub 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
122// To allow chaining of bitwise operations
123impl 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/// Types of Houdini manager nodes (contexts).
152#[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
192// Helper function to return all child nodes of specified type
193fn 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
205// Helper function to return all network type nodes.
206fn 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)]
228/// Represents a manager node (OBJ, SOP, etc)
229pub struct ManagerNode {
230    pub session: Session,
231    pub handle: NodeHandle,
232    pub node_type: ManagerType,
233}
234
235impl ManagerNode {
236    /// Find network nodes of given type.
237    pub fn find_network_nodes(&self, types: NodeType) -> Result<Vec<HoudiniNode>> {
238        find_networks_nodes(&self.session, types, self.handle, true)
239    }
240
241    /// Return children nodes of this network.
242    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)]
255/// A lightweight handle to a node. Can not be created manually, use [`HoudiniNode`] instead.
256/// Some APIs return a list of such handles for efficiency, for example [`HoudiniNode::get_children_by_type`].
257/// Once you found the node you're looking for, upgrade it to a "full" node type with [`NodeHandle::to_node`].
258pub 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    /// Retrieve info about the node this handle belongs to
286    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    /// Returns node's internal path.
298    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    /// Returns node's path relative to another node.
304    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    /// Check if the handle is valid (node wasn't deleted)
314    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    /// Upgrade the handle to HoudiniNode, which has more capabilities.
320    pub fn to_node(&self, session: &Session) -> Result<HoudiniNode> {
321        HoudiniNode::new(session.clone(), *self, None)
322    }
323
324    /// Upgrade the handle to Geometry node.
325    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    /// If this is a handle to a TOP node, returns a [`TopNode`] type.
337    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)]
347/// Represents a Houdini node
348pub 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    /// Convert this node instance into [`TopNode`]
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    /// Delete the node in this session.
425    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    /// Checks if the node valid (not deleted).
431    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    /// Returns node's internal path.
440    pub fn path(&self) -> Result<String> {
441        self.handle.path(&self.session)
442    }
443
444    /// Returns node's path relative to another node.
445    pub fn path_relative(&self, to: impl Into<Option<NodeHandle>>) -> Result<String> {
446        self.handle.path_relative(&self.session, to)
447    }
448
449    /// Start cooking the node. This is a non-blocking call if the session is async.
450    #[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    /// Start cooking the node and wait until completed.
458    /// In sync mode (single threaded), the error will be available in Err(..) while
459    /// in threaded cooking mode the status will be in [`CookResult`]
460    #[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    /// Start cooking with options and wait for result if blocking = true.
469    #[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    /// How many times this node has been cooked.
482    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    /// If the node is of Object type, get the information object about it.
493    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    /// Get a new NodeInfo even for this node.
500    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    /// Returns information objects about this node children.
506    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    /// Find all children of this node by type.
520    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    /// Get all children of the node, not recursively.
537    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    /// Get a child node by path.
549    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    /// Get the node ids for the objects being instanced by an Instance OBJ node.
555    pub fn get_instanced_object_ids(&self) -> Result<Vec<NodeHandle>> {
556        crate::ffi::get_instanced_object_ids(self)
557    }
558
559    /// *Search* for child node by name.
560    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    /// Given if Self is an asset or a subnet SOP node, get its output node at index.
583    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    /// Return the node's parent.
589    pub fn parent_node(&self) -> Option<NodeHandle> {
590        let handle = self.info.parent_id();
591        (handle.0 > -1).then_some(handle)
592    }
593
594    /// Find a parameter on the node by name. Err() means parameter not found.
595    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    /// Find a parameter with a specific tag
602    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    /// Return all node parameters.
615    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    /// If node is an HDA, return [`AssetInfo`] about it.
627    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    /// Recursively check all nodes for a specific error.
632    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    /// Compose the cook result (errors and warnings) of all nodes in the network into a string.
638    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    /// Get the cook errors and warnings on this node as a string
645    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    /// Resets the simulation cache of the asset.
651    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    /// Return a node connected to given input.
657    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    /// Give the node a new name.
669    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    /// Saves the node and all its contents to file
676    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    /// Loads and creates a previously saved node and all its contents from given file.
683    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    /// Returns a node preset as bytes.
699    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    /// Set the preset data to the node.
706    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    /// Return Geometry for this node if it's a SOP node,
713    /// otherwise find a child SOP node with display flag and return.
714    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    /// Search this node for TOP networks
733    pub fn find_top_networks(&self) -> Result<Vec<HoudiniNode>> {
734        find_networks_nodes(&self.session, NodeType::Top, self, true)
735    }
736
737    /// How many geometry output nodes there is inside an Object or SOP node.
738    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    /// Get names of each HDA output
744    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    /// Return all output nodes as Geometry.
750    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    /// If node is an Object, return it's transform.
767    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    /// Set transform on the Object
783    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    /// Set keyframes animation on the Object.
789    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    /// Connect output of another node into an input on this node.
801    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    /// Get the nodes currently connected to the given node at the output index.
818    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    /// Disconnect a given input index.
828    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    /// Disconnect a given output index.
834    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    /// Set display flag on this node.
840    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    /// Get the name of a node's input.
846    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    /// Get the ids of the message nodes specified in the HDA Type Properties
852    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}