1use crate::{
4 util::{path_to_c, str_to_c},
5 AddonApi, TextureApi,
6};
7use std::{
8 ffi::{c_char, c_void},
9 mem,
10 path::Path,
11 ptr::NonNull,
12};
13use windows::Win32::{Foundation::HMODULE, Graphics::Direct3D11::ID3D11ShaderResourceView};
14
15#[derive(Debug, Clone)]
17#[cfg_attr(feature = "serde", derive(serde::Serialize))]
18#[repr(C)]
19pub struct Texture {
20 pub width: u32,
22
23 pub height: u32,
25
26 #[cfg_attr(feature = "serde", serde(skip))]
28 pub resource: ID3D11ShaderResourceView,
29}
30
31impl Texture {
32 #[inline]
34 pub fn resource_ptr(&self) -> *const c_void {
35 unsafe { mem::transmute::<&ID3D11ShaderResourceView, &NonNull<c_void>>(&self.resource) }
37 .as_ptr()
38 }
39
40 #[inline]
42 pub fn id(&self) -> imgui::TextureId {
43 self.resource_ptr().into()
44 }
45
46 #[inline]
48 pub fn size(&self) -> [f32; 2] {
49 [self.width as f32, self.height as f32]
50 }
51
52 #[inline]
54 pub fn size_resized(&self, factor: f32) -> [f32; 2] {
55 let [x, y] = self.size();
56 [factor * x, factor * y]
57 }
58}
59
60pub type RawTextureReceiveCallback =
61 extern "C-unwind" fn(identifier: *const c_char, texture: *const Texture);
62
63pub type RawTextureGet = unsafe extern "C-unwind" fn(identifier: *const c_char) -> *const Texture;
64
65pub type RawTextureGetOrCreateFromFile = unsafe extern "C-unwind" fn(
66 identifier: *const c_char,
67 filename: *const c_char,
68) -> *const Texture;
69
70pub type RawTextureGetOrCreateFromResource = unsafe extern "C-unwind" fn(
71 identifier: *const c_char,
72 resource_id: u32,
73 module: HMODULE,
74) -> *const Texture;
75
76pub type RawTextureGetOrCreateFromUrl = unsafe extern "C-unwind" fn(
77 identifier: *const c_char,
78 remote: *const c_char,
79 endpoint: *const c_char,
80) -> *const Texture;
81
82pub type RawTextureGetOrCreateFromMemory = unsafe extern "C-unwind" fn(
83 identifier: *const c_char,
84 data: *const c_void,
85 size: usize,
86) -> *const Texture;
87
88pub type RawTextureLoadFromFile = unsafe extern "C-unwind" fn(
89 identifier: *const c_char,
90 filename: *const c_char,
91 callback: RawTextureReceiveCallback,
92);
93
94pub type RawTextureLoadFromResource = unsafe extern "C-unwind" fn(
95 identifier: *const c_char,
96 resource_id: u32,
97 module: HMODULE,
98 callback: RawTextureReceiveCallback,
99);
100
101pub type RawTextureLoadFromUrl = unsafe extern "C-unwind" fn(
102 identifier: *const c_char,
103 remote: *const c_char,
104 endpoint: *const c_char,
105 callback: RawTextureReceiveCallback,
106);
107
108pub type RawTextureLoadFromMemory = unsafe extern "C-unwind" fn(
109 identifier: *const c_char,
110 data: *const c_void,
111 size: usize,
112 callback: RawTextureReceiveCallback,
113);
114
115pub fn get_texture(identifier: impl AsRef<str>) -> Option<Texture> {
117 let TextureApi { get, .. } = AddonApi::get().texture;
118 let identifier = str_to_c(identifier, "failed to convert texture identifier");
119 unsafe { get(identifier.as_ptr()).as_ref().cloned() }
120}
121
122pub fn get_texture_or_create_from_file(
124 identifier: impl AsRef<str>,
125 file: impl AsRef<Path>,
126) -> Option<Texture> {
127 let TextureApi {
128 get_or_create_from_file,
129 ..
130 } = AddonApi::get().texture;
131 let identifier = str_to_c(identifier, "failed to convert texture identifier");
132 let file = path_to_c(file, "failed to convert texture file");
133 unsafe {
134 get_or_create_from_file(identifier.as_ptr(), file.as_ptr())
135 .as_ref()
136 .cloned()
137 }
138}
139
140pub fn get_texture_or_create_from_resource(
142 identifier: impl AsRef<str>,
143 resource_id: u32,
144 module: HMODULE,
145) -> Option<Texture> {
146 let TextureApi {
147 get_or_create_from_resource,
148 ..
149 } = AddonApi::get().texture;
150 let identifier = str_to_c(identifier, "failed to convert texture identifier");
151 unsafe {
152 get_or_create_from_resource(identifier.as_ptr(), resource_id, module)
153 .as_ref()
154 .cloned()
155 }
156}
157
158pub fn get_texture_or_create_from_url(
160 identifier: impl AsRef<str>,
161 remote: impl AsRef<str>,
162 endpoint: impl AsRef<str>,
163) -> Option<Texture> {
164 let TextureApi {
165 get_or_create_from_url,
166 ..
167 } = AddonApi::get().texture;
168 let identifier = str_to_c(identifier, "failed to convert texture identifier");
169 let remote = str_to_c(remote, "failed to convert texture url remote");
170 let endpoint = str_to_c(endpoint, "failed to convert texture url endpoint");
171 unsafe {
172 get_or_create_from_url(identifier.as_ptr(), remote.as_ptr(), endpoint.as_ptr())
173 .as_ref()
174 .cloned()
175 }
176}
177
178pub fn get_texture_or_create_from_memory(
180 identifier: impl AsRef<str>,
181 memory: impl AsRef<[u8]>,
182) -> Option<Texture> {
183 let TextureApi {
184 get_or_create_from_memory,
185 ..
186 } = AddonApi::get().texture;
187 let identifier = str_to_c(identifier, "failed to convert texture identifier");
188 let memory = memory.as_ref();
189 unsafe {
190 get_or_create_from_memory(identifier.as_ptr(), memory.as_ptr().cast(), memory.len())
191 .as_ref()
192 .cloned()
193 }
194}
195
196pub fn load_texture_from_file(
200 identifier: impl AsRef<str>,
201 file: impl AsRef<Path>,
202 callback: Option<RawTextureReceiveCallback>,
203) {
204 let TextureApi { load_from_file, .. } = AddonApi::get().texture;
205 let identifier = str_to_c(identifier, "failed to convert texture identifier");
206 let file = path_to_c(file, "foo");
207 unsafe {
208 load_from_file(
209 identifier.as_ptr(),
210 file.as_ptr(),
211 callback.unwrap_or(dummy_receive_texture),
212 )
213 }
214}
215
216pub fn load_texture_from_resource(
220 identifier: impl AsRef<str>,
221 resource_id: u32,
222 module: HMODULE,
223 callback: Option<RawTextureReceiveCallback>,
224) {
225 let TextureApi {
226 load_from_resource, ..
227 } = AddonApi::get().texture;
228 let identifier = str_to_c(identifier, "failed to convert texture identifier");
229 unsafe {
230 load_from_resource(
231 identifier.as_ptr(),
232 resource_id,
233 module,
234 callback.unwrap_or(dummy_receive_texture),
235 )
236 }
237}
238
239pub fn load_texture_from_url(
255 identifier: impl AsRef<str>,
256 remote: impl AsRef<str>,
257 endpoint: impl AsRef<str>,
258 callback: Option<RawTextureReceiveCallback>,
259) {
260 let TextureApi { load_from_url, .. } = AddonApi::get().texture;
261 let identifier = str_to_c(identifier, "failed to convert texture identifier");
262 let remote = str_to_c(remote, "failed to convert texture url remote");
263 let endpoint = str_to_c(endpoint, "failed to convert texture url endpoint");
264 unsafe {
265 load_from_url(
266 identifier.as_ptr(),
267 remote.as_ptr(),
268 endpoint.as_ptr(),
269 callback.unwrap_or(dummy_receive_texture),
270 )
271 }
272}
273
274pub fn load_texture_from_memory(
278 identifier: impl AsRef<str>,
279 data: impl AsRef<[u8]>,
280 callback: Option<RawTextureReceiveCallback>,
281) {
282 let TextureApi {
283 load_from_memory, ..
284 } = AddonApi::get().texture;
285 let identifier = str_to_c(identifier, "failed to convert texture identifier");
286 let data = data.as_ref();
287 unsafe {
288 load_from_memory(
289 identifier.as_ptr(),
290 data.as_ptr().cast(),
291 data.len(),
292 callback.unwrap_or(dummy_receive_texture),
293 )
294 }
295}
296
297extern "C-unwind" fn dummy_receive_texture(_identifier: *const c_char, _texture: *const Texture) {}
298
299#[macro_export]
313macro_rules! texture_receive {
314 ( $callback:expr $(,)? ) => {{
315 const __CALLBACK: fn(&::std::primitive::str, Option<&$crate::texture::Texture>) = $callback;
316
317 extern "C-unwind" fn __keybind_callback_wrapper(
318 identifier: *const ::std::ffi::c_char,
319 texture: *const $crate::texture::Texture,
320 ) {
321 let identifier = unsafe { $crate::__macro::str_from_c(identifier) }
322 .expect("invalid identifier in texture callback");
323 let texture = unsafe { texture.as_ref() };
324 __CALLBACK(identifier, texture)
325 }
326
327 __keybind_callback_wrapper
328 }};
329}
330
331pub use texture_receive;