Skip to main content

hapi_rs/
material.rs

1//! Rendering material textures to memory or disk
2//!
3use crate::Result;
4use crate::ffi::{ImageInfo, raw::HAPI_MaterialInfo};
5use crate::node::{HoudiniNode, NodeHandle};
6use crate::parameter::ParmHandle;
7use crate::session::Session;
8use std::ffi::CString;
9use std::path::Path;
10
11#[derive(Debug, Clone)]
12/// Represents a material node (SHOP) with methods for texture baking
13pub struct Material {
14    pub(crate) session: Session,
15    pub(crate) info: HAPI_MaterialInfo,
16}
17
18impl Material {
19    #[inline]
20    pub fn node(&self) -> Result<HoudiniNode> {
21        HoudiniNode::new(self.session.clone(), self.node_handle(), None)
22    }
23
24    #[inline]
25    fn node_handle(&self) -> NodeHandle {
26        NodeHandle(self.info.nodeId)
27    }
28
29    #[inline]
30    #[must_use]
31    pub fn has_changed(&self) -> bool {
32        self.info.hasChanged > 0
33    }
34
35    pub fn render_texture(&self, parm_name: &str) -> Result<()> {
36        debug_assert!(self.session.is_valid());
37        let name = CString::new(parm_name)?;
38        let id = crate::ffi::get_parm_id_from_name(&name, self.node_handle(), &self.session)?;
39        crate::ffi::render_texture_to_image(&self.session, self.node_handle(), ParmHandle(id))
40    }
41
42    pub fn extract_image_to_file(
43        &self,
44        image_planes: impl AsRef<str>,
45        path: impl AsRef<Path>,
46    ) -> Result<String> {
47        debug_assert!(self.session.is_valid());
48        extract_image_to_file(&self.session, self.node_handle(), image_planes, path)
49    }
50
51    pub fn extract_image_to_memory(
52        &self,
53        buffer: &mut Vec<u8>,
54        image_planes: impl AsRef<str>,
55        format: impl AsRef<str>,
56    ) -> Result<()> {
57        debug_assert!(self.session.is_valid());
58        extract_image_to_memory(
59            &self.session,
60            self.node_handle(),
61            buffer,
62            image_planes,
63            format,
64        )
65    }
66
67    pub fn set_image_info(&self, info: &ImageInfo) -> Result<()> {
68        debug_assert!(self.session.is_valid());
69        crate::ffi::set_image_info(&self.session, self.node_handle(), info)
70    }
71
72    pub fn get_image_info(&self) -> Result<ImageInfo> {
73        debug_assert!(self.session.is_valid());
74        crate::ffi::get_image_info(&self.session, self.node_handle()).map(ImageInfo)
75    }
76
77    pub fn get_image_planes(&self) -> Result<Vec<String>> {
78        debug_assert!(self.session.is_valid());
79        crate::ffi::get_image_planes(&self.session, self.node_handle())
80            .map(|a| a.into_iter().collect())
81    }
82}
83
84pub(crate) fn extract_image_to_file(
85    session: &Session,
86    node: NodeHandle,
87    image_planes: impl AsRef<str>,
88    path: impl AsRef<Path>,
89) -> Result<String> {
90    debug_assert!(session.is_valid());
91    let path = path.as_ref();
92    let format = CString::new(
93        path.extension()
94            .expect("extension")
95            .to_string_lossy()
96            .to_string()
97            .to_uppercase(),
98    )?;
99    let image_planes = CString::new(image_planes.as_ref())?;
100    let dest_folder = crate::utils::path_to_cstring(path.parent().expect("parent"))?;
101    let dest_file = CString::new(
102        path.file_stem()
103            .expect("extension")
104            .to_string_lossy()
105            .to_string(),
106    )?;
107    crate::ffi::extract_image_to_file(
108        session,
109        node,
110        &format,
111        &image_planes,
112        &dest_folder,
113        &dest_file,
114    )
115}
116
117pub(crate) fn extract_image_to_memory(
118    session: &Session,
119    node: NodeHandle,
120    buffer: &mut Vec<u8>,
121    image_planes: impl AsRef<str>,
122    format: impl AsRef<str>,
123) -> Result<()> {
124    let format = CString::new(format.as_ref())?;
125    let image_planes = CString::new(image_planes.as_ref())?;
126    crate::ffi::extract_image_to_memory(session, node, buffer, &format, &image_planes)
127}