1use crate::{
4 AddonApi, TextureApi,
5 ffi::{path_to_ansi, str_to_c},
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).expect("failed to convert texture identifier");
119 unsafe { get(identifier.as_ptr()).as_ref().cloned() }
120}
121
122pub fn get_texture_or_create_from_file(
127 identifier: impl AsRef<str>,
128 file: impl AsRef<Path>,
129) -> Option<Texture> {
130 let TextureApi {
131 get_or_create_from_file,
132 ..
133 } = AddonApi::get().texture;
134 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
135 let file = path_to_ansi(file).expect("failed to convert texture file");
136 unsafe {
137 get_or_create_from_file(identifier.as_ptr(), file.as_ptr())
138 .as_ref()
139 .cloned()
140 }
141}
142
143pub unsafe fn get_texture_or_create_from_file_ascii(
148 identifier: impl AsRef<str>,
149 file: impl AsRef<str>,
150) -> Option<Texture> {
151 let file = file.as_ref();
152 debug_assert!(file.is_ascii());
153
154 let TextureApi {
155 get_or_create_from_file,
156 ..
157 } = AddonApi::get().texture;
158 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
159 let file = str_to_c(file).expect("failed to convert texture file");
160 unsafe {
161 get_or_create_from_file(identifier.as_ptr(), file.as_ptr())
162 .as_ref()
163 .cloned()
164 }
165}
166
167pub fn get_texture_or_create_from_resource(
169 identifier: impl AsRef<str>,
170 resource_id: u32,
171 module: HMODULE,
172) -> Option<Texture> {
173 let TextureApi {
174 get_or_create_from_resource,
175 ..
176 } = AddonApi::get().texture;
177 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
178 unsafe {
179 get_or_create_from_resource(identifier.as_ptr(), resource_id, module)
180 .as_ref()
181 .cloned()
182 }
183}
184
185pub fn get_texture_or_create_from_url(
187 identifier: impl AsRef<str>,
188 remote: impl AsRef<str>,
189 endpoint: impl AsRef<str>,
190) -> Option<Texture> {
191 let TextureApi {
192 get_or_create_from_url,
193 ..
194 } = AddonApi::get().texture;
195 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
196 let remote = str_to_c(remote).expect("failed to convert texture url remote");
197 let endpoint = str_to_c(endpoint).expect("failed to convert texture url endpoint");
198 unsafe {
199 get_or_create_from_url(identifier.as_ptr(), remote.as_ptr(), endpoint.as_ptr())
200 .as_ref()
201 .cloned()
202 }
203}
204
205pub fn get_texture_or_create_from_memory(
207 identifier: impl AsRef<str>,
208 memory: impl AsRef<[u8]>,
209) -> Option<Texture> {
210 let TextureApi {
211 get_or_create_from_memory,
212 ..
213 } = AddonApi::get().texture;
214 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
215 let memory = memory.as_ref();
216 unsafe {
217 get_or_create_from_memory(identifier.as_ptr(), memory.as_ptr().cast(), memory.len())
218 .as_ref()
219 .cloned()
220 }
221}
222
223pub fn load_texture_from_file(
230 identifier: impl AsRef<str>,
231 file: impl AsRef<Path>,
232 callback: Option<RawTextureReceiveCallback>,
233) {
234 let TextureApi { load_from_file, .. } = AddonApi::get().texture;
235 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
236 let file = path_to_ansi(file).expect("failed to convert texture file");
237 unsafe {
238 load_from_file(
239 identifier.as_ptr(),
240 file.as_ptr(),
241 callback.unwrap_or(dummy_receive_texture),
242 )
243 }
244}
245
246pub unsafe fn load_texture_from_file_ascii(
253 identifier: impl AsRef<str>,
254 file: impl AsRef<str>,
255 callback: Option<RawTextureReceiveCallback>,
256) {
257 let file = file.as_ref();
258 debug_assert!(file.is_ascii());
259
260 let TextureApi { load_from_file, .. } = AddonApi::get().texture;
261 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
262 let file = str_to_c(file).expect("failed to convert texture file");
263 unsafe {
264 load_from_file(
265 identifier.as_ptr(),
266 file.as_ptr(),
267 callback.unwrap_or(dummy_receive_texture),
268 )
269 }
270}
271
272pub fn load_texture_from_resource(
276 identifier: impl AsRef<str>,
277 resource_id: u32,
278 module: HMODULE,
279 callback: Option<RawTextureReceiveCallback>,
280) {
281 let TextureApi {
282 load_from_resource, ..
283 } = AddonApi::get().texture;
284 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
285 unsafe {
286 load_from_resource(
287 identifier.as_ptr(),
288 resource_id,
289 module,
290 callback.unwrap_or(dummy_receive_texture),
291 )
292 }
293}
294
295pub fn load_texture_from_url(
311 identifier: impl AsRef<str>,
312 remote: impl AsRef<str>,
313 endpoint: impl AsRef<str>,
314 callback: Option<RawTextureReceiveCallback>,
315) {
316 let TextureApi { load_from_url, .. } = AddonApi::get().texture;
317 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
318 let remote = str_to_c(remote).expect("failed to convert texture url remote");
319 let endpoint = str_to_c(endpoint).expect("failed to convert texture url endpoint");
320 unsafe {
321 load_from_url(
322 identifier.as_ptr(),
323 remote.as_ptr(),
324 endpoint.as_ptr(),
325 callback.unwrap_or(dummy_receive_texture),
326 )
327 }
328}
329
330pub fn load_texture_from_memory(
334 identifier: impl AsRef<str>,
335 data: impl AsRef<[u8]>,
336 callback: Option<RawTextureReceiveCallback>,
337) {
338 let TextureApi {
339 load_from_memory, ..
340 } = AddonApi::get().texture;
341 let identifier = str_to_c(identifier).expect("failed to convert texture identifier");
342 let data = data.as_ref();
343 unsafe {
344 load_from_memory(
345 identifier.as_ptr(),
346 data.as_ptr().cast(),
347 data.len(),
348 callback.unwrap_or(dummy_receive_texture),
349 )
350 }
351}
352
353extern "C-unwind" fn dummy_receive_texture(_identifier: *const c_char, _texture: *const Texture) {}
354
355#[macro_export]
369macro_rules! texture_receive {
370 ( $callback:expr $(,)? ) => {{
371 const __CALLBACK: fn(&::std::primitive::str, Option<&$crate::texture::Texture>) = $callback;
372
373 extern "C-unwind" fn __keybind_callback_wrapper(
374 identifier: *const ::std::ffi::c_char,
375 texture: *const $crate::texture::Texture,
376 ) {
377 let identifier = unsafe { $crate::__macro::str_from_c(identifier) }
378 .expect("invalid identifier in texture callback");
379 let texture = unsafe { texture.as_ref() };
380 __CALLBACK(identifier, texture)
381 }
382
383 __keybind_callback_wrapper
384 }};
385}
386
387pub use texture_receive;