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)]
407pub struct TextureData {
408 raw: UnsafeCell<sys::ImTextureData>,
409}
410
411const _: [(); std::mem::size_of::<sys::ImTextureData>()] = [(); std::mem::size_of::<TextureData>()];
413const _: [(); std::mem::align_of::<sys::ImTextureData>()] =
414 [(); std::mem::align_of::<TextureData>()];
415
416impl TextureData {
417 #[inline]
418 fn inner(&self) -> &sys::ImTextureData {
419 unsafe { &*self.raw.get() }
424 }
425
426 #[inline]
427 fn inner_mut(&mut self) -> &mut sys::ImTextureData {
428 unsafe { &mut *self.raw.get() }
430 }
431
432 pub fn new() -> OwnedTextureData {
436 OwnedTextureData::new()
437 }
438
439 pub(crate) unsafe fn from_raw<'a>(raw: *mut sys::ImTextureData) -> &'a mut Self {
443 unsafe { &mut *(raw as *mut Self) }
444 }
445
446 pub(crate) unsafe fn from_raw_ref<'a>(raw: *const sys::ImTextureData) -> &'a Self {
450 unsafe { &*(raw as *const Self) }
451 }
452
453 pub fn as_raw(&self) -> *const sys::ImTextureData {
455 self.raw.get() as *const _
456 }
457
458 pub fn as_raw_mut(&mut self) -> *mut sys::ImTextureData {
460 self.raw.get()
461 }
462
463 pub fn unique_id(&self) -> i32 {
465 self.inner().UniqueID
466 }
467
468 pub fn status(&self) -> TextureStatus {
470 TextureStatus::from(self.inner().Status)
471 }
472
473 pub fn set_status(&mut self, status: TextureStatus) {
477 unsafe {
478 if status == TextureStatus::Destroyed {
482 sys::ImTextureData_SetTexID(self.as_raw_mut(), 0 as sys::ImTextureID);
483 (*self.as_raw_mut()).BackendUserData = std::ptr::null_mut();
484 }
485 sys::ImTextureData_SetStatus(self.as_raw_mut(), status.into());
486 }
487 }
488
489 pub fn backend_user_data(&self) -> *mut c_void {
491 self.inner().BackendUserData
492 }
493
494 pub fn set_backend_user_data(&mut self, data: *mut c_void) {
496 self.inner_mut().BackendUserData = data;
497 }
498
499 pub fn tex_id(&self) -> TextureId {
501 TextureId::from(self.inner().TexID)
502 }
503
504 pub fn set_tex_id(&mut self, tex_id: TextureId) {
508 unsafe {
509 sys::ImTextureData_SetTexID(self.as_raw_mut(), tex_id.id() as sys::ImTextureID);
510 }
511 }
512
513 pub fn format(&self) -> TextureFormat {
515 TextureFormat::from(self.inner().Format)
516 }
517
518 pub fn width(&self) -> i32 {
520 self.inner().Width
521 }
522
523 pub fn height(&self) -> i32 {
525 self.inner().Height
526 }
527
528 pub fn bytes_per_pixel(&self) -> i32 {
530 self.inner().BytesPerPixel
531 }
532
533 pub fn unused_frames(&self) -> i32 {
535 self.inner().UnusedFrames
536 }
537
538 pub fn ref_count(&self) -> u16 {
540 self.inner().RefCount
541 }
542
543 pub fn use_colors(&self) -> bool {
545 self.inner().UseColors
546 }
547
548 pub fn want_destroy_next_frame(&self) -> bool {
550 self.inner().WantDestroyNextFrame
551 }
552
553 pub fn pixels(&self) -> Option<&[u8]> {
557 let raw = self.inner();
558 if raw.Pixels.is_null() {
559 None
560 } else {
561 let width = raw.Width;
562 let height = raw.Height;
563 let bytes_per_pixel = raw.BytesPerPixel;
564 if width <= 0 || height <= 0 || bytes_per_pixel <= 0 {
565 return None;
566 }
567
568 let size = (width as usize)
569 .checked_mul(height as usize)?
570 .checked_mul(bytes_per_pixel as usize)?;
571 unsafe { Some(std::slice::from_raw_parts(raw.Pixels as *const u8, size)) }
572 }
573 }
574
575 pub fn used_rect(&self) -> TextureRect {
577 TextureRect::from(self.inner().UsedRect)
578 }
579
580 pub fn update_rect(&self) -> TextureRect {
582 TextureRect::from(self.inner().UpdateRect)
583 }
584
585 pub fn updates(&self) -> impl Iterator<Item = TextureRect> + '_ {
587 let vec = &self.inner().Updates;
588 let count = if vec.Data.is_null() {
589 0
590 } else {
591 usize::try_from(vec.Size).unwrap_or(0)
592 };
593 let data = vec.Data as *const sys::ImTextureRect;
594 (0..count).map(move |i| unsafe { TextureRect::from(*data.add(i)) })
595 }
596
597 pub fn pixels_at(&self, x: i32, y: i32) -> Option<&[u8]> {
601 let raw = self.inner();
602 let width = raw.Width;
603 let height = raw.Height;
604 let bytes_per_pixel = raw.BytesPerPixel;
605 if raw.Pixels.is_null()
606 || width <= 0
607 || height <= 0
608 || bytes_per_pixel <= 0
609 || x < 0
610 || y < 0
611 || x >= width
612 || y >= height
613 {
614 None
615 } else {
616 let width_usize = width as usize;
617 let x_usize = x as usize;
618 let y_usize = y as usize;
619 let bpp_usize = bytes_per_pixel as usize;
620
621 let total_size = width_usize
622 .checked_mul(height as usize)?
623 .checked_mul(bpp_usize)?;
624
625 let offset_px = y_usize.checked_mul(width_usize)?.checked_add(x_usize)?;
626 let offset_bytes = offset_px.checked_mul(bpp_usize)?;
627 let remaining_size = total_size.checked_sub(offset_bytes)?;
628
629 unsafe {
630 let ptr = (raw.Pixels as *const u8).add(offset_bytes);
631 Some(std::slice::from_raw_parts(ptr, remaining_size))
632 }
633 }
634 }
635
636 pub fn pitch(&self) -> i32 {
638 self.width() * self.bytes_per_pixel()
639 }
640
641 pub fn create(&mut self, format: TextureFormat, width: i32, height: i32) {
645 unsafe {
646 sys::ImTextureData_Create(self.as_raw_mut(), format.into(), width, height);
647 }
648 }
649
650 pub fn destroy_pixels(&mut self) {
654 unsafe {
655 sys::ImTextureData_DestroyPixels(self.as_raw_mut());
656 }
657 }
658
659 pub fn set_data(&mut self, data: &[u8]) {
663 unsafe {
664 let raw = self.as_raw_mut();
665 let needed = (*raw)
666 .Width
667 .saturating_mul((*raw).Height)
668 .saturating_mul((*raw).BytesPerPixel);
669 if needed <= 0 {
670 return;
672 }
673
674 if (*raw).Pixels.is_null() {
676 sys::ImTextureData_Create(
677 self.as_raw_mut(),
678 (*raw).Format,
679 (*raw).Width,
680 (*raw).Height,
681 );
682 }
683
684 let copy_bytes = std::cmp::min(needed as usize, data.len());
685 if copy_bytes == 0 {
686 return;
687 }
688
689 std::ptr::copy_nonoverlapping(data.as_ptr(), (*raw).Pixels as *mut u8, copy_bytes);
690
691 (*raw).UpdateRect = sys::ImTextureRect {
693 x: 0u16,
694 y: 0u16,
695 w: (*raw).Width.clamp(0, u16::MAX as i32) as u16,
696 h: (*raw).Height.clamp(0, u16::MAX as i32) as u16,
697 };
698 sys::ImTextureData_SetStatus(raw, sys::ImTextureStatus_WantUpdates);
699 }
700 }
701
702 pub fn set_width(&mut self, width: u32) {
704 let width = width.min(i32::MAX as u32) as i32;
705 self.inner_mut().Width = width;
706 }
707
708 pub fn set_height(&mut self, height: u32) {
710 let height = height.min(i32::MAX as u32) as i32;
711 self.inner_mut().Height = height;
712 }
713
714 pub fn set_format(&mut self, format: TextureFormat) {
716 self.inner_mut().Format = format.into();
717 }
718}
719
720pub fn get_format_bytes_per_pixel(format: TextureFormat) -> i32 {
722 unsafe { sys::igImTextureDataGetFormatBytesPerPixel(format.into()) }
723}
724
725pub fn create_texture_ref(texture_id: u64) -> sys::ImTextureRef {
730 sys::ImTextureRef {
731 _TexData: std::ptr::null_mut(),
732 _TexID: texture_id,
733 }
734}
735
736pub fn get_status_name(status: TextureStatus) -> &'static str {
738 unsafe {
739 let ptr = sys::igImTextureDataGetStatusName(status.into());
740 if ptr.is_null() {
741 "Unknown"
742 } else {
743 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
744 }
745 }
746}
747
748pub fn get_format_name(format: TextureFormat) -> &'static str {
750 unsafe {
751 let ptr = sys::igImTextureDataGetFormatName(format.into());
752 if ptr.is_null() {
753 "Unknown"
754 } else {
755 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
756 }
757 }
758}