1use crate::internal::{RawCast, RawWrapper};
7use crate::sys;
8use crate::texture::TextureId;
9use std::marker::PhantomData;
10use std::rc::Rc;
11use std::slice;
12use std::sync::atomic::{AtomicBool, Ordering};
13
14static TEXTURE_DATA_BORROWED: AtomicBool = AtomicBool::new(false);
15
16pub(crate) fn assert_texture_data_not_borrowed() {
17 if TEXTURE_DATA_BORROWED.load(Ordering::Acquire) {
18 panic!(
19 "TextureData is already mutably borrowed; \
20 do not mix DrawData::textures()/PlatformIo::textures() with DrawData::texture()/PlatformIo::texture() calls"
21 );
22 }
23}
24
25#[repr(C)]
27pub struct DrawData {
28 valid: bool,
30 cmd_lists_count: i32,
32 pub total_idx_count: i32,
34 pub total_vtx_count: i32,
36 cmd_lists: crate::internal::ImVector<*mut sys::ImDrawList>,
38 pub display_pos: [f32; 2],
42 pub display_size: [f32; 2],
46 pub framebuffer_scale: [f32; 2],
51
52 owner_viewport: *mut sys::ImGuiViewport,
54 textures: *mut crate::internal::ImVector<*mut sys::ImTextureData>,
56}
57
58const _: [(); std::mem::size_of::<sys::ImDrawData>()] = [(); std::mem::size_of::<DrawData>()];
60const _: [(); std::mem::align_of::<sys::ImDrawData>()] = [(); std::mem::align_of::<DrawData>()];
61
62unsafe impl RawCast<sys::ImDrawData> for DrawData {}
63
64impl RawWrapper for DrawData {
65 type Raw = sys::ImDrawData;
66
67 unsafe fn raw(&self) -> &Self::Raw {
68 unsafe { <Self as RawCast<Self::Raw>>::raw(self) }
69 }
70
71 unsafe fn raw_mut(&mut self) -> &mut Self::Raw {
72 unsafe { <Self as RawCast<Self::Raw>>::raw_mut(self) }
73 }
74}
75
76impl DrawData {
77 #[inline]
82 pub fn valid(&self) -> bool {
83 self.valid
84 }
85
86 #[inline]
88 pub fn draw_lists(&self) -> DrawListIterator<'_> {
89 unsafe {
90 DrawListIterator {
91 iter: self.cmd_lists().iter(),
92 }
93 }
94 }
95 #[inline]
97 pub fn draw_lists_count(&self) -> usize {
98 unsafe { self.cmd_lists().len() }
99 }
100
101 pub fn textures(&self) -> TextureIterator<'_> {
114 unsafe {
115 if self.textures.is_null() {
116 TextureIterator::new(std::ptr::null(), std::ptr::null())
117 } else {
118 let vector = &*self.textures;
119 if vector.size <= 0 || vector.data.is_null() {
120 TextureIterator::new(std::ptr::null(), std::ptr::null())
121 } else {
122 TextureIterator::new(vector.data, vector.data.add(vector.size as usize))
123 }
124 }
125 }
126 }
127
128 pub fn textures_count(&self) -> usize {
130 unsafe {
131 if self.textures.is_null() {
132 0
133 } else {
134 let vector = &*self.textures;
135 if vector.size <= 0 || vector.data.is_null() {
136 0
137 } else {
138 vector.size as usize
139 }
140 }
141 }
142 }
143
144 pub fn texture(&self, index: usize) -> Option<&crate::texture::TextureData> {
148 unsafe {
149 assert_texture_data_not_borrowed();
150 if self.textures.is_null() {
151 return None;
152 }
153 let vector = &*self.textures;
154 let size = usize::try_from(vector.size).ok()?;
155 if size == 0 || vector.data.is_null() {
156 return None;
157 }
158 if index >= size {
159 return None;
160 }
161 let texture_ptr = *vector.data.add(index);
162 if texture_ptr.is_null() {
163 return None;
164 }
165 Some(crate::texture::TextureData::from_raw_ref(
166 texture_ptr as *const _,
167 ))
168 }
169 }
170
171 pub fn texture_mut(&mut self, index: usize) -> Option<&mut crate::texture::TextureData> {
175 unsafe {
176 if self.textures.is_null() {
177 return None;
178 }
179 let vector = &*self.textures;
180 let size = usize::try_from(vector.size).ok()?;
181 if size == 0 || vector.data.is_null() {
182 return None;
183 }
184 if index >= size {
185 return None;
186 }
187 let texture_ptr = *vector.data.add(index);
188 if texture_ptr.is_null() {
189 return None;
190 }
191 Some(crate::texture::TextureData::from_raw(texture_ptr))
192 }
193 }
194 #[inline]
196 pub fn display_pos(&self) -> [f32; 2] {
197 self.display_pos
198 }
199
200 #[inline]
202 pub fn display_size(&self) -> [f32; 2] {
203 self.display_size
204 }
205
206 #[inline]
208 pub fn framebuffer_scale(&self) -> [f32; 2] {
209 self.framebuffer_scale
210 }
211
212 #[inline]
213 pub(crate) unsafe fn cmd_lists(&self) -> &[*mut sys::ImDrawList] {
214 unsafe {
215 if self.cmd_lists_count <= 0 || self.cmd_lists.data.is_null() {
216 return &[];
217 }
218 let len = match usize::try_from(self.cmd_lists_count) {
219 Ok(len) => len,
220 Err(_) => return &[],
221 };
222 slice::from_raw_parts(self.cmd_lists.data, len)
223 }
224 }
225
226 #[doc(alias = "DeIndexAllBuffers")]
230 pub fn deindex_all_buffers(&mut self) {
231 unsafe {
232 sys::ImDrawData_DeIndexAllBuffers(RawWrapper::raw_mut(self));
233 }
234 }
235
236 #[doc(alias = "ScaleClipRects")]
241 pub fn scale_clip_rects(&mut self, fb_scale: [f32; 2]) {
242 unsafe {
243 let scale = sys::ImVec2 {
244 x: fb_scale[0],
245 y: fb_scale[1],
246 };
247 sys::ImDrawData_ScaleClipRects(RawWrapper::raw_mut(self), scale);
248 }
249 }
250}
251
252pub struct DrawListIterator<'a> {
254 iter: std::slice::Iter<'a, *mut sys::ImDrawList>,
255}
256
257impl<'a> Iterator for DrawListIterator<'a> {
258 type Item = &'a DrawList;
259
260 fn next(&mut self) -> Option<Self::Item> {
261 self.iter.next().and_then(|&ptr| {
262 if ptr.is_null() {
263 None
264 } else {
265 Some(unsafe { DrawList::from_raw(ptr.cast_const()) })
266 }
267 })
268 }
269}
270
271impl<'a> ExactSizeIterator for DrawListIterator<'a> {
272 fn len(&self) -> usize {
273 self.iter.len()
274 }
275}
276
277#[repr(transparent)]
279pub struct DrawList(sys::ImDrawList);
280
281const _: [(); std::mem::size_of::<sys::ImDrawList>()] = [(); std::mem::size_of::<DrawList>()];
283const _: [(); std::mem::align_of::<sys::ImDrawList>()] = [(); std::mem::align_of::<DrawList>()];
284
285impl RawWrapper for DrawList {
286 type Raw = sys::ImDrawList;
287 #[inline]
288 unsafe fn raw(&self) -> &sys::ImDrawList {
289 &self.0
290 }
291 #[inline]
292 unsafe fn raw_mut(&mut self) -> &mut sys::ImDrawList {
293 &mut self.0
294 }
295}
296
297impl DrawList {
298 #[inline]
299 pub(crate) unsafe fn from_raw<'a>(raw: *const sys::ImDrawList) -> &'a Self {
300 unsafe { &*(raw as *const Self) }
301 }
302
303 #[inline]
304 pub(crate) unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
305 unsafe {
306 let cmd_buffer = &self.0.CmdBuffer;
307 if cmd_buffer.Size <= 0 || cmd_buffer.Data.is_null() {
308 return &[];
309 }
310 let len = match usize::try_from(cmd_buffer.Size) {
311 Ok(len) => len,
312 Err(_) => return &[],
313 };
314 slice::from_raw_parts(cmd_buffer.Data, len)
315 }
316 }
317
318 pub fn commands(&self) -> DrawCmdIterator<'_> {
320 unsafe {
321 DrawCmdIterator {
322 iter: self.cmd_buffer().iter(),
323 }
324 }
325 }
326
327 pub fn vtx_buffer(&self) -> &[DrawVert] {
329 unsafe {
330 let vtx_buffer = &self.0.VtxBuffer;
331 if vtx_buffer.Size <= 0 || vtx_buffer.Data.is_null() {
332 return &[];
333 }
334 let len = match usize::try_from(vtx_buffer.Size) {
335 Ok(len) => len,
336 Err(_) => return &[],
337 };
338 slice::from_raw_parts(vtx_buffer.Data as *const DrawVert, len)
339 }
340 }
341
342 pub fn idx_buffer(&self) -> &[DrawIdx] {
344 unsafe {
345 let idx_buffer = &self.0.IdxBuffer;
346 if idx_buffer.Size <= 0 || idx_buffer.Data.is_null() {
347 return &[];
348 }
349 let len = match usize::try_from(idx_buffer.Size) {
350 Ok(len) => len,
351 Err(_) => return &[],
352 };
353 slice::from_raw_parts(idx_buffer.Data, len)
354 }
355 }
356}
357
358pub struct DrawCmdIterator<'a> {
360 iter: slice::Iter<'a, sys::ImDrawCmd>,
361}
362
363impl<'a> Iterator for DrawCmdIterator<'a> {
364 type Item = DrawCmd;
365
366 fn next(&mut self) -> Option<Self::Item> {
367 self.iter.next().map(|cmd| {
368 let cmd_params = DrawCmdParams {
369 clip_rect: [
370 cmd.ClipRect.x,
371 cmd.ClipRect.y,
372 cmd.ClipRect.z,
373 cmd.ClipRect.w,
374 ],
375 texture_id: TextureId::from(cmd.TexRef._TexID),
377 vtx_offset: cmd.VtxOffset as usize,
378 idx_offset: cmd.IdxOffset as usize,
379 };
380
381 match cmd.UserCallback {
383 Some(raw_callback) if raw_callback as usize == (-1isize) as usize => {
384 DrawCmd::ResetRenderState
385 }
386 Some(raw_callback) => DrawCmd::RawCallback {
387 callback: raw_callback,
388 raw_cmd: cmd,
389 },
390 None => DrawCmd::Elements {
391 count: cmd.ElemCount as usize,
392 cmd_params,
393 raw_cmd: cmd as *const sys::ImDrawCmd,
394 },
395 }
396 })
397 }
398}
399
400#[derive(Copy, Clone, Debug, PartialEq)]
402pub struct DrawCmdParams {
403 pub clip_rect: [f32; 4],
405 pub texture_id: TextureId,
413 pub vtx_offset: usize,
415 pub idx_offset: usize,
417}
418
419#[derive(Clone, Debug)]
421pub enum DrawCmd {
422 Elements {
424 count: usize,
426 cmd_params: DrawCmdParams,
427 raw_cmd: *const sys::ImDrawCmd,
434 },
435 ResetRenderState,
437 RawCallback {
439 callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
440 raw_cmd: *const sys::ImDrawCmd,
441 },
442}
443
444#[repr(C)]
446#[derive(Copy, Clone, Debug, PartialEq)]
447pub struct DrawVert {
448 pub pos: [f32; 2],
450 pub uv: [f32; 2],
452 pub col: u32,
454}
455
456const _: [(); std::mem::size_of::<sys::ImDrawVert>()] = [(); std::mem::size_of::<DrawVert>()];
458const _: [(); std::mem::align_of::<sys::ImDrawVert>()] = [(); std::mem::align_of::<DrawVert>()];
459
460impl DrawVert {
461 pub fn new(pos: [f32; 2], uv: [f32; 2], col: u32) -> Self {
463 Self { pos, uv, col }
464 }
465
466 pub fn from_rgba(pos: [f32; 2], uv: [f32; 2], rgba: [u8; 4]) -> Self {
468 let col = ((rgba[3] as u32) << 24)
469 | ((rgba[2] as u32) << 16)
470 | ((rgba[1] as u32) << 8)
471 | (rgba[0] as u32);
472 Self { pos, uv, col }
473 }
474
475 pub fn rgba(&self) -> [u8; 4] {
477 [
478 (self.col & 0xFF) as u8,
479 ((self.col >> 8) & 0xFF) as u8,
480 ((self.col >> 16) & 0xFF) as u8,
481 ((self.col >> 24) & 0xFF) as u8,
482 ]
483 }
484}
485
486pub type DrawIdx = u16;
488
489const _: [(); std::mem::size_of::<sys::ImDrawIdx>()] = [(); std::mem::size_of::<DrawIdx>()];
490const _: [(); std::mem::align_of::<sys::ImDrawIdx>()] = [(); std::mem::align_of::<DrawIdx>()];
491
492pub struct OwnedDrawData {
503 draw_data: *mut sys::ImDrawData,
504 _no_send_sync: PhantomData<Rc<()>>,
506}
507
508impl OwnedDrawData {
509 #[inline]
513 pub fn draw_data(&self) -> Option<&DrawData> {
514 if !self.draw_data.is_null() {
515 Some(unsafe { &*(self.draw_data as *const DrawData) })
516 } else {
517 None
518 }
519 }
520}
521
522impl Default for OwnedDrawData {
523 #[inline]
525 fn default() -> Self {
526 Self {
527 draw_data: std::ptr::null_mut(),
528 _no_send_sync: PhantomData,
529 }
530 }
531}
532
533impl From<&DrawData> for OwnedDrawData {
534 fn from(value: &DrawData) -> Self {
536 unsafe {
537 let result = sys::ImDrawData_ImDrawData();
539 if result.is_null() {
540 panic!("Failed to allocate ImDrawData for OwnedDrawData");
541 }
542
543 let source_ptr = RawWrapper::raw(value);
545 (*result).Valid = source_ptr.Valid;
546 (*result).TotalIdxCount = source_ptr.TotalIdxCount;
547 (*result).TotalVtxCount = source_ptr.TotalVtxCount;
548 (*result).DisplayPos = source_ptr.DisplayPos;
549 (*result).DisplaySize = source_ptr.DisplaySize;
550 (*result).FramebufferScale = source_ptr.FramebufferScale;
551 (*result).OwnerViewport = source_ptr.OwnerViewport;
552
553 (*result).CmdListsCount = 0;
555 if source_ptr.CmdListsCount > 0 && !source_ptr.CmdLists.Data.is_null() {
556 for i in 0..(source_ptr.CmdListsCount as usize) {
557 let src_list = *source_ptr.CmdLists.Data.add(i);
558 if !src_list.is_null() {
559 let cloned = sys::ImDrawList_CloneOutput(src_list);
561 if !cloned.is_null() {
562 sys::ImDrawData_AddDrawList(result, cloned);
563 }
564 }
565 }
566 }
567
568 (*result).Textures = source_ptr.Textures;
570
571 OwnedDrawData {
572 draw_data: result,
573 _no_send_sync: PhantomData,
574 }
575 }
576 }
577}
578
579impl Drop for OwnedDrawData {
580 fn drop(&mut self) {
582 unsafe {
583 if !self.draw_data.is_null() {
584 if !(*self.draw_data).CmdLists.Data.is_null() {
586 for i in 0..(*self.draw_data).CmdListsCount as usize {
587 let ptr = *(*self.draw_data).CmdLists.Data.add(i);
588 if !ptr.is_null() {
589 sys::ImDrawList_destroy(ptr);
590 }
591 }
592 }
593
594 sys::ImDrawData_destroy(self.draw_data);
596 self.draw_data = std::ptr::null_mut();
597 }
598 }
599 }
600}
601
602pub struct TextureIterator<'a> {
604 ptr: *const *mut sys::ImTextureData,
605 end: *const *mut sys::ImTextureData,
606 _phantom: std::marker::PhantomData<&'a crate::texture::TextureData>,
607}
608
609impl<'a> TextureIterator<'a> {
610 pub(crate) unsafe fn new(
617 ptr: *const *mut sys::ImTextureData,
618 end: *const *mut sys::ImTextureData,
619 ) -> Self {
620 Self {
621 ptr,
622 end,
623 _phantom: std::marker::PhantomData,
624 }
625 }
626}
627
628impl<'a> Iterator for TextureIterator<'a> {
629 type Item = TextureDataMut<'a>;
630
631 fn next(&mut self) -> Option<Self::Item> {
632 while self.ptr < self.end {
633 let texture_ptr = unsafe { *self.ptr };
634 self.ptr = unsafe { self.ptr.add(1) };
635 if texture_ptr.is_null() {
636 continue;
637 }
638
639 if TEXTURE_DATA_BORROWED
640 .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
641 .is_err()
642 {
643 panic!(
644 "TextureData is already mutably borrowed; \
645 do not hold items from DrawData::textures()/PlatformIo::textures() across iterations"
646 );
647 }
648
649 return Some(TextureDataMut {
650 raw: texture_ptr,
651 _phantom: PhantomData,
652 });
653 }
654
655 None
656 }
657}
658
659impl<'a> std::iter::FusedIterator for TextureIterator<'a> {}
660
661pub struct TextureDataMut<'a> {
667 raw: *mut sys::ImTextureData,
668 _phantom: PhantomData<&'a mut crate::texture::TextureData>,
669}
670
671impl Drop for TextureDataMut<'_> {
672 fn drop(&mut self) {
673 TEXTURE_DATA_BORROWED.store(false, Ordering::Release);
674 }
675}
676
677impl std::ops::Deref for TextureDataMut<'_> {
678 type Target = crate::texture::TextureData;
679
680 fn deref(&self) -> &Self::Target {
681 unsafe { &*(self.raw as *const crate::texture::TextureData) }
682 }
683}
684
685impl std::ops::DerefMut for TextureDataMut<'_> {
686 fn deref_mut(&mut self) -> &mut Self::Target {
687 unsafe { &mut *(self.raw as *mut crate::texture::TextureData) }
688 }
689}
690
691#[cfg(test)]
692mod tests {
693 use super::*;
694
695 #[test]
696 fn draw_data_textures_empty_is_safe() {
697 let mut textures_vec: crate::internal::ImVector<*mut sys::ImTextureData> =
698 crate::internal::ImVector::default();
699
700 let draw_data = DrawData {
701 valid: false,
702 cmd_lists_count: 0,
703 total_idx_count: 0,
704 total_vtx_count: 0,
705 cmd_lists: crate::internal::ImVector::default(),
706 display_pos: [0.0, 0.0],
707 display_size: [0.0, 0.0],
708 framebuffer_scale: [1.0, 1.0],
709 owner_viewport: std::ptr::null_mut(),
710 textures: &mut textures_vec,
711 };
712
713 assert_eq!(draw_data.textures().count(), 0);
714 assert_eq!(draw_data.textures_count(), 0);
715
716 let mut textures_vec: crate::internal::ImVector<*mut sys::ImTextureData> =
717 crate::internal::ImVector::default();
718 textures_vec.size = 1;
719 textures_vec.data = std::ptr::null_mut();
720 let draw_data = DrawData {
721 valid: false,
722 cmd_lists_count: 0,
723 total_idx_count: 0,
724 total_vtx_count: 0,
725 cmd_lists: crate::internal::ImVector::default(),
726 display_pos: [0.0, 0.0],
727 display_size: [0.0, 0.0],
728 framebuffer_scale: [1.0, 1.0],
729 owner_viewport: std::ptr::null_mut(),
730 textures: &mut textures_vec,
731 };
732 assert_eq!(draw_data.textures().count(), 0);
733 assert_eq!(draw_data.textures_count(), 0);
734 assert!(draw_data.texture(0).is_none());
735 }
736}