1use crate::sys;
8use std::ffi::c_void;
9
10#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
18#[repr(transparent)]
19pub struct TextureId(u64);
20
21impl TextureId {
22 #[inline]
24 pub const fn new(id: u64) -> Self {
25 Self(id)
26 }
27
28 #[inline]
30 pub const fn id(self) -> u64 {
31 self.0
32 }
33
34 #[inline]
36 pub const fn null() -> Self {
37 Self(0)
38 }
39
40 #[inline]
42 pub const fn is_null(self) -> bool {
43 self.0 == 0
44 }
45}
46
47impl From<u64> for TextureId {
48 #[inline]
49 fn from(id: u64) -> Self {
50 TextureId(id)
51 }
52}
53
54impl<T> From<*const T> for TextureId {
55 #[inline]
56 fn from(ptr: *const T) -> Self {
57 TextureId(ptr as usize as u64)
58 }
59}
60
61impl<T> From<*mut T> for TextureId {
62 #[inline]
63 fn from(ptr: *mut T) -> Self {
64 TextureId(ptr as usize as u64)
65 }
66}
67
68impl From<TextureId> for *const c_void {
69 #[inline]
70 fn from(id: TextureId) -> Self {
71 id.0 as usize as *const c_void
72 }
73}
74
75impl From<TextureId> for *mut c_void {
76 #[inline]
77 fn from(id: TextureId) -> Self {
78 id.0 as usize as *mut c_void
79 }
80}
81
82impl From<usize> for TextureId {
84 #[inline]
85 fn from(id: usize) -> Self {
86 TextureId(id as u64)
87 }
88}
89
90impl From<TextureId> for usize {
92 #[inline]
93 fn from(id: TextureId) -> Self {
94 id.0 as usize
95 }
96}
97
98impl Default for TextureId {
99 #[inline]
100 fn default() -> Self {
101 Self::null()
102 }
103}
104
105pub type RawTextureId = *const c_void;
107
108#[derive(Copy, Clone, Debug)]
134#[repr(transparent)]
135pub struct TextureRef(sys::ImTextureRef);
136
137impl TextureRef {
138 #[inline]
140 pub fn from_raw(raw: sys::ImTextureRef) -> Self {
141 Self(raw)
142 }
143
144 #[inline]
146 pub fn raw(self) -> sys::ImTextureRef {
147 self.0
148 }
149}
150
151impl From<TextureId> for TextureRef {
152 #[inline]
153 fn from(id: TextureId) -> Self {
154 TextureRef(sys::ImTextureRef {
155 _TexData: std::ptr::null_mut(),
156 _TexID: id.id() as sys::ImTextureID,
157 })
158 }
159}
160
161impl From<u64> for TextureRef {
162 #[inline]
163 fn from(id: u64) -> Self {
164 TextureRef::from(TextureId::from(id))
165 }
166}
167
168impl From<&TextureData> for TextureRef {
169 #[inline]
170 fn from(td: &TextureData) -> Self {
171 TextureRef(sys::ImTextureRef {
173 _TexData: td.as_raw() as *mut sys::ImTextureData,
174 _TexID: 0,
175 })
176 }
177}
178
179impl From<&mut TextureData> for TextureRef {
180 #[inline]
181 fn from(td: &mut TextureData) -> Self {
182 TextureRef(sys::ImTextureRef {
183 _TexData: td.as_raw_mut(),
184 _TexID: 0,
185 })
186 }
187}
188
189#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
191#[repr(i32)]
192pub enum TextureFormat {
193 RGBA32 = sys::ImTextureFormat_RGBA32 as i32,
195 Alpha8 = sys::ImTextureFormat_Alpha8 as i32,
197}
198
199impl From<sys::ImTextureFormat> for TextureFormat {
200 fn from(format: sys::ImTextureFormat) -> Self {
201 match format {
202 sys::ImTextureFormat_RGBA32 => TextureFormat::RGBA32,
203 sys::ImTextureFormat_Alpha8 => TextureFormat::Alpha8,
204 _ => TextureFormat::RGBA32, }
206 }
207}
208
209impl From<TextureFormat> for sys::ImTextureFormat {
210 fn from(format: TextureFormat) -> Self {
211 format as sys::ImTextureFormat
212 }
213}
214
215#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
217#[repr(i32)]
218pub enum TextureStatus {
219 OK = sys::ImTextureStatus_OK as i32,
221 Destroyed = sys::ImTextureStatus_Destroyed as i32,
223 WantCreate = sys::ImTextureStatus_WantCreate as i32,
225 WantUpdates = sys::ImTextureStatus_WantUpdates as i32,
227 WantDestroy = sys::ImTextureStatus_WantDestroy as i32,
229}
230
231impl From<sys::ImTextureStatus> for TextureStatus {
232 fn from(status: sys::ImTextureStatus) -> Self {
233 match status {
234 sys::ImTextureStatus_OK => TextureStatus::OK,
235 sys::ImTextureStatus_Destroyed => TextureStatus::Destroyed,
236 sys::ImTextureStatus_WantCreate => TextureStatus::WantCreate,
237 sys::ImTextureStatus_WantUpdates => TextureStatus::WantUpdates,
238 sys::ImTextureStatus_WantDestroy => TextureStatus::WantDestroy,
239 _ => TextureStatus::Destroyed, }
241 }
242}
243
244impl From<TextureStatus> for sys::ImTextureStatus {
245 fn from(status: TextureStatus) -> Self {
246 status as sys::ImTextureStatus
247 }
248}
249
250#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
252pub struct TextureRect {
253 pub x: u16,
255 pub y: u16,
257 pub w: u16,
259 pub h: u16,
261}
262
263impl From<sys::ImTextureRect> for TextureRect {
264 fn from(rect: sys::ImTextureRect) -> Self {
265 Self {
266 x: rect.x,
267 y: rect.y,
268 w: rect.w,
269 h: rect.h,
270 }
271 }
272}
273
274impl From<TextureRect> for sys::ImTextureRect {
275 fn from(rect: TextureRect) -> Self {
276 Self {
277 x: rect.x,
278 y: rect.y,
279 w: rect.w,
280 h: rect.h,
281 }
282 }
283}
284
285#[repr(transparent)]
304pub struct TextureData {
305 raw: sys::ImTextureData,
306}
307
308impl TextureData {
309 pub fn new() -> Box<Self> {
314 let raw = unsafe {
316 let p = sys::ImTextureData_ImTextureData();
317 let v = *p;
318 sys::ImTextureData_destroy(p);
319 v
320 };
321 let raw_data = Box::new(raw);
322 unsafe { Box::from_raw(Box::into_raw(raw_data) as *mut Self) }
323 }
324
325 pub(crate) unsafe fn from_raw<'a>(raw: *mut sys::ImTextureData) -> &'a mut Self {
329 unsafe { &mut *(raw as *mut Self) }
330 }
331
332 pub fn as_raw(&self) -> *const sys::ImTextureData {
334 &self.raw as *const _
335 }
336
337 pub fn as_raw_mut(&mut self) -> *mut sys::ImTextureData {
339 &mut self.raw as *mut _
340 }
341
342 pub fn unique_id(&self) -> i32 {
344 self.raw.UniqueID
345 }
346
347 pub fn status(&self) -> TextureStatus {
349 TextureStatus::from(self.raw.Status)
350 }
351
352 pub fn set_status(&mut self, status: TextureStatus) {
356 self.raw.Status = status.into();
357 }
358
359 pub fn backend_user_data(&self) -> *mut c_void {
361 self.raw.BackendUserData
362 }
363
364 pub fn set_backend_user_data(&mut self, data: *mut c_void) {
366 self.raw.BackendUserData = data;
367 }
368
369 pub fn tex_id(&self) -> TextureId {
371 TextureId::from(self.raw.TexID)
372 }
373
374 pub fn set_tex_id(&mut self, tex_id: TextureId) {
378 self.raw.TexID = tex_id.id() as sys::ImTextureID;
379 }
380
381 pub fn format(&self) -> TextureFormat {
383 TextureFormat::from(self.raw.Format)
384 }
385
386 pub fn width(&self) -> i32 {
388 self.raw.Width
389 }
390
391 pub fn height(&self) -> i32 {
393 self.raw.Height
394 }
395
396 pub fn bytes_per_pixel(&self) -> i32 {
398 self.raw.BytesPerPixel
399 }
400
401 pub fn unused_frames(&self) -> i32 {
403 self.raw.UnusedFrames
404 }
405
406 pub fn ref_count(&self) -> u16 {
408 self.raw.RefCount
409 }
410
411 pub fn use_colors(&self) -> bool {
413 self.raw.UseColors
414 }
415
416 pub fn want_destroy_next_frame(&self) -> bool {
418 self.raw.WantDestroyNextFrame
419 }
420
421 pub fn pixels(&self) -> Option<&[u8]> {
425 if self.raw.Pixels.is_null() {
426 None
427 } else {
428 let size = (self.width() * self.height() * self.bytes_per_pixel()) as usize;
429 unsafe {
430 Some(std::slice::from_raw_parts(
431 self.raw.Pixels as *const u8,
432 size,
433 ))
434 }
435 }
436 }
437
438 pub fn used_rect(&self) -> TextureRect {
440 unsafe { TextureRect::from((*self.as_raw()).UsedRect) }
441 }
442
443 pub fn update_rect(&self) -> TextureRect {
445 unsafe { TextureRect::from((*self.as_raw()).UpdateRect) }
446 }
447
448 pub fn updates(&self) -> impl Iterator<Item = TextureRect> + '_ {
450 unsafe {
451 let vec = &(*self.as_raw()).Updates;
452 let count = vec.Size as usize;
453 let data = vec.Data as *const sys::ImTextureRect;
454 (0..count).map(move |i| TextureRect::from(*data.add(i)))
455 }
456 }
457
458 pub fn pixels_at(&self, x: i32, y: i32) -> Option<&[u8]> {
462 if self.raw.Pixels.is_null() || x < 0 || y < 0 || x >= self.width() || y >= self.height() {
463 None
464 } else {
465 let offset = (x + y * self.width()) * self.bytes_per_pixel();
466 let remaining_size = ((self.width() - x) + (self.height() - y - 1) * self.width())
467 * self.bytes_per_pixel();
468 unsafe {
469 let ptr = (self.raw.Pixels as *const u8).add(offset as usize);
470 Some(std::slice::from_raw_parts(ptr, remaining_size as usize))
471 }
472 }
473 }
474
475 pub fn pitch(&self) -> i32 {
477 self.width() * self.bytes_per_pixel()
478 }
479
480 pub fn create(&mut self, format: TextureFormat, width: i32, height: i32) {
484 unsafe {
485 sys::ImTextureData_Create(self.as_raw_mut(), format.into(), width, height);
486 }
487 }
488
489 pub fn destroy_pixels(&mut self) {
493 unsafe {
494 sys::ImTextureData_DestroyPixels(self.as_raw_mut());
495 }
496 }
497
498 pub fn set_data(&mut self, data: &[u8]) {
502 unsafe {
503 let raw = self.as_raw_mut();
504 let needed = (*raw)
505 .Width
506 .saturating_mul((*raw).Height)
507 .saturating_mul((*raw).BytesPerPixel);
508 if needed <= 0 {
509 return;
511 }
512
513 if (*raw).Pixels.is_null() {
515 sys::ImTextureData_Create(
516 self.as_raw_mut(),
517 (*raw).Format,
518 (*raw).Width,
519 (*raw).Height,
520 );
521 }
522
523 let copy_bytes = std::cmp::min(needed as usize, data.len());
524 if copy_bytes == 0 {
525 return;
526 }
527
528 std::ptr::copy_nonoverlapping(data.as_ptr(), (*raw).Pixels as *mut u8, copy_bytes);
529
530 (*raw).UpdateRect = sys::ImTextureRect {
532 x: 0u16,
533 y: 0u16,
534 w: (*raw).Width.clamp(0, u16::MAX as i32) as u16,
535 h: (*raw).Height.clamp(0, u16::MAX as i32) as u16,
536 };
537 (*raw).Status = sys::ImTextureStatus_WantUpdates;
538 }
539 }
540
541 pub fn set_width(&mut self, width: u32) {
543 unsafe {
544 (*self.as_raw_mut()).Width = width as i32;
545 }
546 }
547
548 pub fn set_height(&mut self, height: u32) {
550 unsafe {
551 (*self.as_raw_mut()).Height = height as i32;
552 }
553 }
554
555 pub fn set_format(&mut self, format: TextureFormat) {
557 unsafe {
558 (*self.as_raw_mut()).Format = format.into();
559 }
560 }
561}
562
563pub fn get_format_bytes_per_pixel(format: TextureFormat) -> i32 {
565 unsafe { sys::igImTextureDataGetFormatBytesPerPixel(format.into()) }
566}
567
568pub fn create_texture_ref(texture_id: u64) -> sys::ImTextureRef {
573 sys::ImTextureRef {
574 _TexData: std::ptr::null_mut(),
575 _TexID: texture_id,
576 }
577}
578
579pub fn get_status_name(status: TextureStatus) -> &'static str {
581 unsafe {
582 let ptr = sys::igImTextureDataGetStatusName(status.into());
583 if ptr.is_null() {
584 "Unknown"
585 } else {
586 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
587 }
588 }
589}
590
591pub fn get_format_name(format: TextureFormat) -> &'static str {
593 unsafe {
594 let ptr = sys::igImTextureDataGetFormatName(format.into());
595 if ptr.is_null() {
596 "Unknown"
597 } else {
598 std::ffi::CStr::from_ptr(ptr).to_str().unwrap_or("Invalid")
599 }
600 }
601}