Skip to main content

modelio/
texture.rs

1use std::path::Path;
2use std::ptr;
3
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::types::{TextureChannelEncoding, TextureInfo};
8use crate::util::{c_string, parse_json, path_to_c_string, required_handle};
9
10#[derive(Debug, Clone)]
11pub struct Texture {
12    handle: ObjectHandle,
13}
14
15impl Texture {
16    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
17        Self { handle }
18    }
19
20    pub fn from_url(path: impl AsRef<Path>, name: Option<&str>) -> Result<Self> {
21        let path = path_to_c_string(path.as_ref())?;
22        let name = name.map(c_string).transpose()?;
23        let mut out_texture = ptr::null_mut();
24        let mut out_error = ptr::null_mut();
25        let status = unsafe {
26            ffi::mdl_url_texture_new(
27                path.as_ptr(),
28                name.as_ref().map_or(ptr::null(), |name| name.as_ptr()),
29                &mut out_texture,
30                &mut out_error,
31            )
32        };
33        crate::util::status_result(status, out_error)?;
34        Ok(Self::from_handle(required_handle(
35            out_texture,
36            "MDLURLTexture",
37        )?))
38    }
39
40    pub fn new_checkerboard(
41        divisions: f32,
42        name: Option<&str>,
43        dimensions: [i32; 2],
44        channel_count: usize,
45        channel_encoding: TextureChannelEncoding,
46        color1: [f32; 4],
47        color2: [f32; 4],
48    ) -> Result<Self> {
49        let name = name.map(c_string).transpose()?;
50        let mut out_texture = ptr::null_mut();
51        let mut out_error = ptr::null_mut();
52        let status = unsafe {
53            ffi::mdl_checkerboard_texture_new(
54                divisions,
55                name.as_ref().map_or(ptr::null(), |name| name.as_ptr()),
56                dimensions[0],
57                dimensions[1],
58                channel_count as u64,
59                channel_encoding as i32,
60                color1[0],
61                color1[1],
62                color1[2],
63                color1[3],
64                color2[0],
65                color2[1],
66                color2[2],
67                color2[3],
68                &mut out_texture,
69                &mut out_error,
70            )
71        };
72        crate::util::status_result(status, out_error)?;
73        Ok(Self::from_handle(required_handle(
74            out_texture,
75            "MDLCheckerboardTexture",
76        )?))
77    }
78
79    pub fn info(&self) -> Result<TextureInfo> {
80        parse_json(
81            unsafe { ffi::mdl_texture_info_json(self.handle.as_ptr()) },
82            "MDLTexture",
83        )
84    }
85
86    pub fn write_to_url(&self, path: impl AsRef<Path>) -> Result<()> {
87        let path = path_to_c_string(path.as_ref())?;
88        let mut out_error = ptr::null_mut();
89        let status = unsafe {
90            ffi::mdl_texture_write_to_url(self.handle.as_ptr(), path.as_ptr(), &mut out_error)
91        };
92        crate::util::status_result(status, out_error)
93    }
94
95    fn texel_data(&self, top_left_origin: bool) -> Vec<u8> {
96        let length = unsafe {
97            ffi::mdl_texture_texel_data_length(self.handle.as_ptr(), i32::from(top_left_origin))
98        } as usize;
99        let mut bytes = vec![0_u8; length];
100        if length == 0 {
101            return bytes;
102        }
103        let written = unsafe {
104            ffi::mdl_texture_copy_texel_data(
105                self.handle.as_ptr(),
106                i32::from(top_left_origin),
107                bytes.as_mut_ptr(),
108                bytes.len() as u64,
109            )
110        } as usize;
111        bytes.truncate(written);
112        bytes
113    }
114
115    #[must_use]
116    pub fn texel_data_top_left(&self) -> Vec<u8> {
117        self.texel_data(true)
118    }
119
120    #[must_use]
121    pub fn texel_data_bottom_left(&self) -> Vec<u8> {
122        self.texel_data(false)
123    }
124}