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}