1use crate::sys;
8use std::cell::UnsafeCell;
9use std::ffi::c_void;
10use std::ptr::NonNull;
11
12#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
20#[repr(transparent)]
21pub struct TextureId(u64);
22
23impl TextureId {
24 #[inline]
26 pub const fn new(id: u64) -> Self {
27 Self(id)
28 }
29
30 #[inline]
32 pub const fn id(self) -> u64 {
33 self.0
34 }
35
36 #[inline]
38 pub const fn null() -> Self {
39 Self(0)
40 }
41
42 #[inline]
44 pub const fn is_null(self) -> bool {
45 self.0 == 0
46 }
47}
48
49impl From<u64> for TextureId {
50 #[inline]
51 fn from(id: u64) -> Self {
52 TextureId(id)
53 }
54}
55
56impl<T> From<*const T> for TextureId {
57 #[inline]
58 fn from(ptr: *const T) -> Self {
59 TextureId(ptr as usize as u64)
60 }
61}
62
63impl<T> From<*mut T> for TextureId {
64 #[inline]
65 fn from(ptr: *mut T) -> Self {
66 TextureId(ptr as usize as u64)
67 }
68}
69
70impl From<TextureId> for *const c_void {
71 #[inline]
72 fn from(id: TextureId) -> Self {
73 debug_assert!(
74 id.0 <= (usize::MAX as u64),
75 "TextureId value {} exceeds pointer width on this target",
76 id.0
77 );
78 id.0 as usize as *const c_void
79 }
80}
81
82impl From<TextureId> for *mut c_void {
83 #[inline]
84 fn from(id: TextureId) -> Self {
85 debug_assert!(
86 id.0 <= (usize::MAX as u64),
87 "TextureId value {} exceeds pointer width on this target",
88 id.0
89 );
90 id.0 as usize as *mut c_void
91 }
92}
93
94impl From<usize> for TextureId {
96 #[inline]
97 fn from(id: usize) -> Self {
98 TextureId(id as u64)
99 }
100}
101
102impl From<TextureId> for usize {
104 #[inline]
105 fn from(id: TextureId) -> Self {
106 debug_assert!(
107 id.0 <= (usize::MAX as u64),
108 "TextureId value {} exceeds usize width on this target",
109 id.0
110 );
111 id.0 as usize
112 }
113}
114
115impl Default for TextureId {
116 #[inline]
117 fn default() -> Self {
118 Self::null()
119 }
120}
121
122pub type RawTextureId = sys::ImTextureID;
124
125impl From<TextureId> for RawTextureId {
126 #[inline]
127 fn from(id: TextureId) -> Self {
128 id.id() as sys::ImTextureID
129 }
130}
131
132#[derive(Copy, Clone, Debug)]
158#[repr(transparent)]
159pub struct TextureRef(sys::ImTextureRef);
160
161const _: [(); std::mem::size_of::<sys::ImTextureRef>()] = [(); std::mem::size_of::<TextureRef>()];
163const _: [(); std::mem::align_of::<sys::ImTextureRef>()] = [(); std::mem::align_of::<TextureRef>()];
164
165impl TextureRef {
166 #[inline]
168 pub fn from_raw(raw: sys::ImTextureRef) -> Self {
169 Self(raw)
170 }
171
172 #[inline]
174 pub fn raw(self) -> sys::ImTextureRef {
175 self.0
176 }
177}
178
179impl From<TextureId> for TextureRef {
180 #[inline]
181 fn from(id: TextureId) -> Self {
182 TextureRef(sys::ImTextureRef {
183 _TexData: std::ptr::null_mut(),
184 _TexID: id.id() as sys::ImTextureID,
185 })
186 }
187}
188
189impl From<u64> for TextureRef {
190 #[inline]
191 fn from(id: u64) -> Self {
192 TextureRef::from(TextureId::from(id))
193 }
194}
195
196impl From<&TextureData> for TextureRef {
197 #[inline]
198 fn from(td: &TextureData) -> Self {
199 TextureRef(sys::ImTextureRef {
206 _TexData: std::ptr::null_mut(),
207 _TexID: td.tex_id().id() as sys::ImTextureID,
208 })
209 }
210}
211
212impl From<&mut TextureData> for TextureRef {
213 #[inline]
214 fn from(td: &mut TextureData) -> Self {
215 TextureRef(sys::ImTextureRef {
216 _TexData: td.as_raw_mut(),
217 _TexID: 0,
218 })
219 }
220}
221
222#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
224#[repr(i32)]
225pub enum TextureFormat {
226 RGBA32 = sys::ImTextureFormat_RGBA32 as i32,
228 Alpha8 = sys::ImTextureFormat_Alpha8 as i32,
230}
231
232impl From<sys::ImTextureFormat> for TextureFormat {
233 fn from(format: sys::ImTextureFormat) -> Self {
234 match format {
235 sys::ImTextureFormat_RGBA32 => TextureFormat::RGBA32,
236 sys::ImTextureFormat_Alpha8 => TextureFormat::Alpha8,
237 _ => TextureFormat::RGBA32, }
239 }
240}
241
242impl From<TextureFormat> for sys::ImTextureFormat {
243 fn from(format: TextureFormat) -> Self {
244 format as sys::ImTextureFormat
245 }
246}
247
248#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
250#[repr(i32)]
251pub enum TextureStatus {
252 OK = sys::ImTextureStatus_OK as i32,
254 Destroyed = sys::ImTextureStatus_Destroyed as i32,
256 WantCreate = sys::ImTextureStatus_WantCreate as i32,
258 WantUpdates = sys::ImTextureStatus_WantUpdates as i32,
260 WantDestroy = sys::ImTextureStatus_WantDestroy as i32,
262}
263
264impl From<sys::ImTextureStatus> for TextureStatus {
265 fn from(status: sys::ImTextureStatus) -> Self {
266 match status {
267 sys::ImTextureStatus_OK => TextureStatus::OK,
268 sys::ImTextureStatus_Destroyed => TextureStatus::Destroyed,
269 sys::ImTextureStatus_WantCreate => TextureStatus::WantCreate,
270 sys::ImTextureStatus_WantUpdates => TextureStatus::WantUpdates,
271 sys::ImTextureStatus_WantDestroy => TextureStatus::WantDestroy,
272 _ => TextureStatus::Destroyed, }
274 }
275}
276
277impl From<TextureStatus> for sys::ImTextureStatus {
278 fn from(status: TextureStatus) -> Self {
279 status as sys::ImTextureStatus
280 }
281}
282
283#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
285pub struct TextureRect {
286 pub x: u16,
288 pub y: u16,
290 pub w: u16,
292 pub h: u16,
294}
295
296impl From<sys::ImTextureRect> for TextureRect {
297 fn from(rect: sys::ImTextureRect) -> Self {
298 Self {
299 x: rect.x,
300 y: rect.y,
301 w: rect.w,
302 h: rect.h,
303 }
304 }
305}
306
307impl From<TextureRect> for sys::ImTextureRect {
308 fn from(rect: TextureRect) -> Self {
309 Self {
310 x: rect.x,
311 y: rect.y,
312 w: rect.w,
313 h: rect.h,
314 }
315 }
316}
317
318pub struct OwnedTextureData {
325 raw: NonNull<sys::ImTextureData>,
326}
327
328impl OwnedTextureData {
329 pub fn new() -> Self {
331 let raw = unsafe { sys::ImTextureData_ImTextureData() };
332 let raw = NonNull::new(raw).expect("ImTextureData_ImTextureData() returned null");
333 Self { raw }
334 }
335
336 pub fn into_raw(self) -> *mut sys::ImTextureData {
338 let raw = self.raw.as_ptr();
339 std::mem::forget(self);
340 raw
341 }
342
343 pub unsafe fn from_raw_owned(raw: *mut sys::ImTextureData) -> Self {
349 let raw = NonNull::new(raw).expect("raw ImTextureData pointer was null");
350 Self { raw }
351 }
352}
353
354impl Drop for OwnedTextureData {
355 fn drop(&mut self) {
356 unsafe { sys::ImTextureData_destroy(self.raw.as_ptr()) }
357 }
358}
359
360impl std::ops::Deref for OwnedTextureData {
361 type Target = TextureData;
362
363 fn deref(&self) -> &Self::Target {
364 unsafe { &*(self.raw.as_ptr() as *const TextureData) }
365 }
366}
367
368impl std::ops::DerefMut for OwnedTextureData {
369 fn deref_mut(&mut self) -> &mut Self::Target {
370 unsafe { &mut *(self.raw.as_ptr() as *mut TextureData) }
371 }
372}
373
374impl AsRef<TextureData> for OwnedTextureData {
375 fn as_ref(&self) -> &TextureData {
376 self
377 }
378}
379
380impl AsMut<TextureData> for OwnedTextureData {
381 fn as_mut(&mut self) -> &mut TextureData {
382 self
383 }
384}
385
386#[repr(transparent)]
408pub struct TextureData {
409 raw: UnsafeCell<sys::ImTextureData>,
410}
411
412const _: [(); std::mem::size_of::<sys::ImTextureData>()] = [(); std::mem::size_of::<TextureData>()];
414const _: [(); std::mem::align_of::<sys::ImTextureData>()] =
415 [(); std::mem::align_of::<TextureData>()];
416
417impl TextureData {
418 #[inline]
419 fn inner(&self) -> &sys::ImTextureData {
420 unsafe { &*self.raw.get() }
425 }
426
427 #[inline]
428 fn inner_mut(&mut self) -> &mut sys::ImTextureData {
429 unsafe { &mut *self.raw.get() }
431 }
432
433 pub fn new() -> OwnedTextureData {
437 OwnedTextureData::new()
438 }
439
440 pub(crate) unsafe fn from_raw<'a>(raw: *mut sys::ImTextureData) -> &'a mut Self {
444 unsafe { &mut *(raw as *mut Self) }
445 }
446
447 pub(crate) unsafe fn from_raw_ref<'a>(raw: *const sys::ImTextureData) -> &'a Self {
451 unsafe { &*(raw as *const Self) }
452 }
453
454 pub fn as_raw(&self) -> *const sys::ImTextureData {
456 self.raw.get() as *const _
457 }
458
459 pub fn as_raw_mut(&mut self) -> *mut sys::ImTextureData {
461 self.raw.get()
462 }
463
464 pub fn unique_id(&self) -> i32 {
466 self.inner().UniqueID
467 }
468
469 pub fn status(&self) -> TextureStatus {
471 TextureStatus::from(self.inner().Status)
472 }
473
474 pub fn set_status(&mut self, status: TextureStatus) {
478 unsafe {
479 if status == TextureStatus::Destroyed {
483 sys::ImTextureData_SetTexID(self.as_raw_mut(), 0 as sys::ImTextureID);
484 (*self.as_raw_mut()).BackendUserData = std::ptr::null_mut();
485 }
486 sys::ImTextureData_SetStatus(self.as_raw_mut(), status.into());
487 }
488 }
489
490 pub fn backend_user_data(&self) -> *mut c_void {
492 self.inner().BackendUserData
493 }
494
495 pub fn set_backend_user_data(&mut self, data: *mut c_void) {
497 self.inner_mut().BackendUserData = data;
498 }
499
500 pub fn tex_id(&self) -> TextureId {
502 TextureId::from(self.inner().TexID)
503 }
504
505 pub fn set_tex_id(&mut self, tex_id: TextureId) {
509 unsafe {
510 sys::ImTextureData_SetTexID(self.as_raw_mut(), tex_id.id() as sys::ImTextureID);
511 }
512 }
513
514 #[inline]
516 pub fn texture_ref(&mut self) -> TextureRef {
517 unsafe { TextureRef::from_raw(sys::ImTextureData_GetTexRef(self.as_raw_mut())) }
518 }
519
520 pub fn format(&self) -> TextureFormat {
522 TextureFormat::from(self.inner().Format)
523 }
524
525 pub fn width(&self) -> i32 {
527 self.inner().Width
528 }
529
530 pub fn height(&self) -> i32 {
532 self.inner().Height
533 }
534
535 pub fn bytes_per_pixel(&self) -> i32 {
537 self.inner().BytesPerPixel
538 }
539
540 pub fn unused_frames(&self) -> i32 {
542 self.inner().UnusedFrames
543 }
544
545 pub fn ref_count(&self) -> u16 {
547 self.inner().RefCount
548 }
549
550 pub fn use_colors(&self) -> bool {
552 self.inner().UseColors
553 }
554
555 pub fn want_destroy_next_frame(&self) -> bool {
557 self.inner().WantDestroyNextFrame
558 }
559
560 pub fn pixels(&self) -> Option<&[u8]> {
564 let raw = self.inner();
565 if raw.Pixels.is_null() {
566 None
567 } else {
568 let width = raw.Width;
569 let height = raw.Height;
570 let bytes_per_pixel = raw.BytesPerPixel;
571 if width <= 0 || height <= 0 || bytes_per_pixel <= 0 {
572 return None;
573 }
574
575 let size = (width as usize)
576 .checked_mul(height as usize)?
577 .checked_mul(bytes_per_pixel as usize)?;
578 unsafe { Some(std::slice::from_raw_parts(raw.Pixels as *const u8, size)) }
579 }
580 }
581
582 pub fn used_rect(&self) -> TextureRect {
584 TextureRect::from(self.inner().UsedRect)
585 }
586
587 pub fn update_rect(&self) -> TextureRect {
589 TextureRect::from(self.inner().UpdateRect)
590 }
591
592 pub fn updates(&self) -> impl Iterator<Item = TextureRect> + '_ {
594 let vec = &self.inner().Updates;
595 let count = if vec.Data.is_null() {
596 0
597 } else {
598 usize::try_from(vec.Size).unwrap_or(0)
599 };
600 let data = vec.Data as *const sys::ImTextureRect;
601 (0..count).map(move |i| unsafe { TextureRect::from(*data.add(i)) })
602 }
603
604 pub fn pixels_at(&self, x: i32, y: i32) -> Option<&[u8]> {
608 let raw = self.inner();
609 let width = raw.Width;
610 let height = raw.Height;
611 let bytes_per_pixel = raw.BytesPerPixel;
612 if raw.Pixels.is_null()
613 || width <= 0
614 || height <= 0
615 || bytes_per_pixel <= 0
616 || x < 0
617 || y < 0
618 || x >= width
619 || y >= height
620 {
621 None
622 } else {
623 let width_usize = width as usize;
624 let x_usize = x as usize;
625 let y_usize = y as usize;
626 let bpp_usize = bytes_per_pixel as usize;
627
628 let total_size = width_usize
629 .checked_mul(height as usize)?
630 .checked_mul(bpp_usize)?;
631
632 let offset_px = y_usize.checked_mul(width_usize)?.checked_add(x_usize)?;
633 let offset_bytes = offset_px.checked_mul(bpp_usize)?;
634 let remaining_size = total_size.checked_sub(offset_bytes)?;
635
636 unsafe {
637 let ptr = (raw.Pixels as *const u8).add(offset_bytes);
638 Some(std::slice::from_raw_parts(ptr, remaining_size))
639 }
640 }
641 }
642
643 pub fn pitch(&self) -> i32 {
645 self.width() * self.bytes_per_pixel()
646 }
647
648 pub fn create(&mut self, format: TextureFormat, width: i32, height: i32) {
652 unsafe {
653 sys::ImTextureData_Create(self.as_raw_mut(), format.into(), width, height);
654 }
655 }
656
657 pub fn destroy_pixels(&mut self) {
661 unsafe {
662 sys::ImTextureData_DestroyPixels(self.as_raw_mut());
663 }
664 }
665
666 pub fn set_data(&mut self, data: &[u8]) {
670 unsafe {
671 let raw = self.as_raw_mut();
672 let needed = (*raw)
673 .Width
674 .saturating_mul((*raw).Height)
675 .saturating_mul((*raw).BytesPerPixel);
676 if needed <= 0 {
677 return;
679 }
680
681 if (*raw).Pixels.is_null() {
683 sys::ImTextureData_Create(
684 self.as_raw_mut(),
685 (*raw).Format,
686 (*raw).Width,
687 (*raw).Height,
688 );
689 }
690
691 let copy_bytes = std::cmp::min(needed as usize, data.len());
692 if copy_bytes == 0 {
693 return;
694 }
695
696 std::ptr::copy_nonoverlapping(data.as_ptr(), (*raw).Pixels as *mut u8, copy_bytes);
697
698 (*raw).UpdateRect = sys::ImTextureRect {
700 x: 0u16,
701 y: 0u16,
702 w: (*raw).Width.clamp(0, u16::MAX as i32) as u16,
703 h: (*raw).Height.clamp(0, u16::MAX as i32) as u16,
704 };
705 sys::ImTextureData_SetStatus(raw, sys::ImTextureStatus_WantUpdates);
706 }
707 }
708
709 pub fn set_width(&mut self, width: u32) {
711 let width = width.min(i32::MAX as u32) as i32;
712 self.inner_mut().Width = width;
713 }
714
715 pub fn set_height(&mut self, height: u32) {
717 let height = height.min(i32::MAX as u32) as i32;
718 self.inner_mut().Height = height;
719 }
720
721 pub fn set_format(&mut self, format: TextureFormat) {
723 self.inner_mut().Format = format.into();
724 }
725}
726
727pub fn get_format_bytes_per_pixel(format: TextureFormat) -> i32 {
729 unsafe { sys::igImTextureDataGetFormatBytesPerPixel(format.into()) }
730}
731
732pub fn create_texture_ref(texture_id: u64) -> sys::ImTextureRef {
737 sys::ImTextureRef {
738 _TexData: std::ptr::null_mut(),
739 _TexID: texture_id,
740 }
741}
742
743pub fn get_status_name(status: TextureStatus) -> &'static str {
745 unsafe {
746 let ptr = sys::igImTextureDataGetStatusName(status.into());
747 if ptr.is_null() {
748 "Unknown"
749 } else {
750 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
751 }
752 }
753}
754
755pub fn get_format_name(format: TextureFormat) -> &'static str {
757 unsafe {
758 let ptr = sys::igImTextureDataGetFormatName(format.into());
759 if ptr.is_null() {
760 "Unknown"
761 } else {
762 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
763 }
764 }
765}