hapi_rs/
material.rs

1//! Rendering material textures to memory or disk
2//!
3use crate::ffi::{raw::HAPI_MaterialInfo, ImageInfo};
4use crate::node::{HoudiniNode, NodeHandle};
5use crate::parameter::ParmHandle;
6use crate::session::Session;
7use crate::Result;
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    pub fn has_changed(&self) -> bool {
31        self.info.hasChanged > 0
32    }
33
34    pub fn render_texture(&self, parm_name: &str) -> Result<()> {
35        debug_assert!(self.session.is_valid());
36        let name = CString::new(parm_name)?;
37        let id = crate::ffi::get_parm_id_from_name(&name, self.node_handle(), &self.session)?;
38        crate::ffi::render_texture_to_image(&self.session, self.node_handle(), ParmHandle(id))
39    }
40
41    pub fn extract_image_to_file(
42        &self,
43        image_planes: impl AsRef<str>,
44        path: impl AsRef<Path>,
45    ) -> Result<String> {
46        debug_assert!(self.session.is_valid());
47        extract_image_to_file(&self.session, self.node_handle(), image_planes, path)
48    }
49
50    pub fn extract_image_to_memory(
51        &self,
52        buffer: &mut Vec<u8>,
53        image_planes: impl AsRef<str>,
54        format: impl AsRef<str>,
55    ) -> Result<()> {
56        debug_assert!(self.session.is_valid());
57        extract_image_to_memory(
58            &self.session,
59            self.node_handle(),
60            buffer,
61            image_planes,
62            format,
63        )
64    }
65
66    pub fn set_image_info(&self, info: &ImageInfo) -> Result<()> {
67        debug_assert!(self.session.is_valid());
68        crate::ffi::set_image_info(&self.session, self.node_handle(), info)
69    }
70
71    pub fn get_image_info(&self) -> Result<ImageInfo> {
72        debug_assert!(self.session.is_valid());
73        crate::ffi::get_image_info(&self.session, self.node_handle()).map(ImageInfo)
74    }
75
76    pub fn get_image_planes(&self) -> Result<Vec<String>> {
77        debug_assert!(self.session.is_valid());
78        crate::ffi::get_image_planes(&self.session, self.node_handle())
79            .map(|a| a.into_iter().collect())
80    }
81}
82
83pub(crate) fn extract_image_to_file(
84    session: &Session,
85    node: NodeHandle,
86    image_planes: impl AsRef<str>,
87    path: impl AsRef<Path>,
88) -> Result<String> {
89    debug_assert!(session.is_valid());
90    let path = path.as_ref();
91    let format = CString::new(
92        path.extension()
93            .expect("extension")
94            .to_string_lossy()
95            .to_string()
96            .to_uppercase(),
97    )?;
98    let image_planes = CString::new(image_planes.as_ref())?;
99    let dest_folder = CString::new(path.parent().expect("parent").to_string_lossy().to_string())?;
100    let dest_file = CString::new(
101        path.file_stem()
102            .expect("extension")
103            .to_string_lossy()
104            .to_string(),
105    )?;
106    crate::ffi::extract_image_to_file(
107        session,
108        node,
109        &format,
110        &image_planes,
111        &dest_folder,
112        &dest_file,
113    )
114}
115
116pub(crate) fn extract_image_to_memory(
117    session: &Session,
118    node: NodeHandle,
119    buffer: &mut Vec<u8>,
120    image_planes: impl AsRef<str>,
121    format: impl AsRef<str>,
122) -> Result<()> {
123    let format = CString::new(format.as_ref())?;
124    let image_planes = CString::new(image_planes.as_ref())?;
125    crate::ffi::extract_image_to_memory(session, node, buffer, &format, &image_planes)
126}