1use crate::internal::{RawCast, RawWrapper};
7use crate::sys;
8use crate::texture::TextureId;
9use std::marker::PhantomData;
10use std::rc::Rc;
11use std::slice;
12
13#[repr(C)]
15pub struct DrawData {
16 valid: bool,
18 cmd_lists_count: i32,
20 pub total_idx_count: i32,
22 pub total_vtx_count: i32,
24 cmd_lists: crate::internal::ImVector<DrawList>,
26 pub display_pos: [f32; 2],
30 pub display_size: [f32; 2],
34 pub framebuffer_scale: [f32; 2],
39
40 owner_viewport: *mut sys::ImGuiViewport,
42 textures: *mut crate::internal::ImVector<*mut sys::ImTextureData>,
44}
45
46unsafe impl RawCast<sys::ImDrawData> for DrawData {}
47
48impl RawWrapper for DrawData {
49 type Raw = sys::ImDrawData;
50
51 unsafe fn raw(&self) -> &Self::Raw {
52 unsafe { std::mem::transmute(self) }
53 }
54
55 unsafe fn raw_mut(&mut self) -> &mut Self::Raw {
56 unsafe { std::mem::transmute(self) }
57 }
58}
59
60impl DrawData {
61 #[inline]
66 pub fn valid(&self) -> bool {
67 self.valid
68 }
69
70 #[inline]
72 pub fn draw_lists(&self) -> DrawListIterator<'_> {
73 unsafe {
74 DrawListIterator {
75 iter: self.cmd_lists().iter(),
76 }
77 }
78 }
79 #[inline]
81 pub fn draw_lists_count(&self) -> usize {
82 self.cmd_lists_count.try_into().unwrap()
83 }
84
85 pub fn textures(&self) -> TextureIterator<'_> {
95 unsafe {
96 if self.textures.is_null() {
97 TextureIterator::new(std::ptr::null(), std::ptr::null())
98 } else {
99 let vector = &*self.textures;
100 TextureIterator::new(vector.data, vector.data.add(vector.size as usize))
101 }
102 }
103 }
104
105 pub fn textures_count(&self) -> usize {
107 unsafe {
108 if self.textures.is_null() {
109 0
110 } else {
111 (*self.textures).size as usize
112 }
113 }
114 }
115
116 pub fn texture(&self, index: usize) -> Option<&crate::texture::TextureData> {
120 unsafe {
121 if self.textures.is_null() {
122 return None;
123 }
124 let vector = &*self.textures;
125 if index >= vector.size as usize {
126 return None;
127 }
128 let texture_ptr = *vector.data.add(index);
129 if texture_ptr.is_null() {
130 return None;
131 }
132 Some(crate::texture::TextureData::from_raw(texture_ptr))
133 }
134 }
135
136 pub fn texture_mut(&mut self, index: usize) -> Option<&mut crate::texture::TextureData> {
140 unsafe {
141 if self.textures.is_null() {
142 return None;
143 }
144 let vector = &*self.textures;
145 if index >= vector.size as usize {
146 return None;
147 }
148 let texture_ptr = *vector.data.add(index);
149 if texture_ptr.is_null() {
150 return None;
151 }
152 Some(crate::texture::TextureData::from_raw(texture_ptr))
153 }
154 }
155 #[inline]
157 pub fn display_pos(&self) -> [f32; 2] {
158 self.display_pos
159 }
160
161 #[inline]
163 pub fn display_size(&self) -> [f32; 2] {
164 self.display_size
165 }
166
167 #[inline]
169 pub fn framebuffer_scale(&self) -> [f32; 2] {
170 self.framebuffer_scale
171 }
172
173 #[inline]
174 pub(crate) unsafe fn cmd_lists(&self) -> &[*const DrawList] {
175 unsafe {
176 if self.cmd_lists_count <= 0 || self.cmd_lists.data.is_null() {
177 return &[];
178 }
179 slice::from_raw_parts(
180 self.cmd_lists.data as *const *const DrawList,
181 self.cmd_lists_count as usize,
182 )
183 }
184 }
185
186 #[doc(alias = "DeIndexAllBuffers")]
190 pub fn deindex_all_buffers(&mut self) {
191 unsafe {
192 sys::ImDrawData_DeIndexAllBuffers(RawWrapper::raw_mut(self));
193 }
194 }
195
196 #[doc(alias = "ScaleClipRects")]
201 pub fn scale_clip_rects(&mut self, fb_scale: [f32; 2]) {
202 unsafe {
203 let scale = sys::ImVec2 {
204 x: fb_scale[0],
205 y: fb_scale[1],
206 };
207 sys::ImDrawData_ScaleClipRects(RawWrapper::raw_mut(self), scale);
208 }
209 }
210}
211
212pub struct DrawListIterator<'a> {
214 iter: std::slice::Iter<'a, *const DrawList>,
215}
216
217impl<'a> Iterator for DrawListIterator<'a> {
218 type Item = &'a DrawList;
219
220 fn next(&mut self) -> Option<Self::Item> {
221 self.iter.next().map(|&ptr| unsafe { &*ptr })
222 }
223}
224
225impl<'a> ExactSizeIterator for DrawListIterator<'a> {
226 fn len(&self) -> usize {
227 self.iter.len()
228 }
229}
230
231#[repr(transparent)]
233pub struct DrawList(sys::ImDrawList);
234
235impl RawWrapper for DrawList {
236 type Raw = sys::ImDrawList;
237 #[inline]
238 unsafe fn raw(&self) -> &sys::ImDrawList {
239 &self.0
240 }
241 #[inline]
242 unsafe fn raw_mut(&mut self) -> &mut sys::ImDrawList {
243 &mut self.0
244 }
245}
246
247impl DrawList {
248 #[inline]
249 pub(crate) unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
250 unsafe {
251 let cmd_buffer = &self.0.CmdBuffer;
252 if cmd_buffer.Size <= 0 || cmd_buffer.Data.is_null() {
253 return &[];
254 }
255 slice::from_raw_parts(cmd_buffer.Data, cmd_buffer.Size as usize)
256 }
257 }
258
259 pub fn commands(&self) -> DrawCmdIterator<'_> {
261 unsafe {
262 DrawCmdIterator {
263 iter: self.cmd_buffer().iter(),
264 }
265 }
266 }
267
268 pub fn vtx_buffer(&self) -> &[DrawVert] {
270 unsafe {
271 let vtx_buffer = &self.0.VtxBuffer;
272 slice::from_raw_parts(vtx_buffer.Data as *const DrawVert, vtx_buffer.Size as usize)
273 }
274 }
275
276 pub fn idx_buffer(&self) -> &[DrawIdx] {
278 unsafe {
279 let idx_buffer = &self.0.IdxBuffer;
280 slice::from_raw_parts(idx_buffer.Data, idx_buffer.Size as usize)
281 }
282 }
283}
284
285pub struct DrawCmdIterator<'a> {
287 iter: slice::Iter<'a, sys::ImDrawCmd>,
288}
289
290impl<'a> Iterator for DrawCmdIterator<'a> {
291 type Item = DrawCmd;
292
293 fn next(&mut self) -> Option<Self::Item> {
294 self.iter.next().map(|cmd| {
295 let cmd_params = DrawCmdParams {
296 clip_rect: [
297 cmd.ClipRect.x,
298 cmd.ClipRect.y,
299 cmd.ClipRect.z,
300 cmd.ClipRect.w,
301 ],
302 texture_id: TextureId::from(cmd.TexRef._TexID),
304 vtx_offset: cmd.VtxOffset as usize,
305 idx_offset: cmd.IdxOffset as usize,
306 };
307
308 match cmd.UserCallback {
310 Some(raw_callback) if raw_callback as usize == (-1isize) as usize => {
311 DrawCmd::ResetRenderState
312 }
313 Some(raw_callback) => DrawCmd::RawCallback {
314 callback: raw_callback,
315 raw_cmd: cmd,
316 },
317 None => DrawCmd::Elements {
318 count: cmd.ElemCount as usize,
319 cmd_params,
320 raw_cmd: cmd as *const sys::ImDrawCmd,
321 },
322 }
323 })
324 }
325}
326
327#[derive(Copy, Clone, Debug, PartialEq)]
329pub struct DrawCmdParams {
330 pub clip_rect: [f32; 4],
332 pub texture_id: TextureId,
340 pub vtx_offset: usize,
342 pub idx_offset: usize,
344}
345
346#[derive(Clone, Debug)]
348pub enum DrawCmd {
349 Elements {
351 count: usize,
353 cmd_params: DrawCmdParams,
354 raw_cmd: *const sys::ImDrawCmd,
361 },
362 ResetRenderState,
364 RawCallback {
366 callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
367 raw_cmd: *const sys::ImDrawCmd,
368 },
369}
370
371#[repr(C)]
373#[derive(Copy, Clone, Debug, PartialEq)]
374pub struct DrawVert {
375 pub pos: [f32; 2],
377 pub uv: [f32; 2],
379 pub col: u32,
381}
382
383impl DrawVert {
384 pub fn new(pos: [f32; 2], uv: [f32; 2], col: u32) -> Self {
386 Self { pos, uv, col }
387 }
388
389 pub fn from_rgba(pos: [f32; 2], uv: [f32; 2], rgba: [u8; 4]) -> Self {
391 let col = ((rgba[3] as u32) << 24)
392 | ((rgba[2] as u32) << 16)
393 | ((rgba[1] as u32) << 8)
394 | (rgba[0] as u32);
395 Self { pos, uv, col }
396 }
397
398 pub fn rgba(&self) -> [u8; 4] {
400 [
401 (self.col & 0xFF) as u8,
402 ((self.col >> 8) & 0xFF) as u8,
403 ((self.col >> 16) & 0xFF) as u8,
404 ((self.col >> 24) & 0xFF) as u8,
405 ]
406 }
407}
408
409pub type DrawIdx = u16;
411
412pub struct OwnedDrawData {
423 draw_data: *mut sys::ImDrawData,
424 _no_send_sync: PhantomData<Rc<()>>,
426}
427
428impl OwnedDrawData {
429 #[inline]
433 pub fn draw_data(&self) -> Option<&DrawData> {
434 if !self.draw_data.is_null() {
435 Some(unsafe { std::mem::transmute::<&sys::ImDrawData, &DrawData>(&*self.draw_data) })
436 } else {
437 None
438 }
439 }
440}
441
442impl Default for OwnedDrawData {
443 #[inline]
445 fn default() -> Self {
446 Self {
447 draw_data: std::ptr::null_mut(),
448 _no_send_sync: PhantomData,
449 }
450 }
451}
452
453impl From<&DrawData> for OwnedDrawData {
454 fn from(value: &DrawData) -> Self {
456 unsafe {
457 let result = sys::ImDrawData_ImDrawData();
459 if result.is_null() {
460 panic!("Failed to allocate ImDrawData for OwnedDrawData");
461 }
462
463 let source_ptr = RawWrapper::raw(value);
465 (*result).Valid = source_ptr.Valid;
466 (*result).TotalIdxCount = source_ptr.TotalIdxCount;
467 (*result).TotalVtxCount = source_ptr.TotalVtxCount;
468 (*result).DisplayPos = source_ptr.DisplayPos;
469 (*result).DisplaySize = source_ptr.DisplaySize;
470 (*result).FramebufferScale = source_ptr.FramebufferScale;
471 (*result).OwnerViewport = source_ptr.OwnerViewport;
472
473 (*result).CmdListsCount = 0;
475 if source_ptr.CmdListsCount > 0 && !source_ptr.CmdLists.Data.is_null() {
476 for i in 0..(source_ptr.CmdListsCount as usize) {
477 let src_list = *source_ptr.CmdLists.Data.add(i);
478 if !src_list.is_null() {
479 let cloned = sys::ImDrawList_CloneOutput(src_list);
481 if !cloned.is_null() {
482 sys::ImDrawData_AddDrawList(result, cloned);
483 }
484 }
485 }
486 }
487
488 (*result).Textures = source_ptr.Textures;
490
491 OwnedDrawData {
492 draw_data: result,
493 _no_send_sync: PhantomData,
494 }
495 }
496 }
497}
498
499impl Drop for OwnedDrawData {
500 fn drop(&mut self) {
502 unsafe {
503 if !self.draw_data.is_null() {
504 if !(*self.draw_data).CmdLists.Data.is_null() {
506 for i in 0..(*self.draw_data).CmdListsCount as usize {
507 let ptr = *(*self.draw_data).CmdLists.Data.add(i);
508 if !ptr.is_null() {
509 sys::ImDrawList_destroy(ptr);
510 }
511 }
512 sys::igMemFree((*self.draw_data).CmdLists.Data as *mut std::ffi::c_void);
514 }
515
516 sys::ImDrawData_destroy(self.draw_data);
518 self.draw_data = std::ptr::null_mut();
519 }
520 }
521 }
522}
523
524pub struct TextureIterator<'a> {
526 ptr: *const *mut sys::ImTextureData,
527 end: *const *mut sys::ImTextureData,
528 _phantom: std::marker::PhantomData<&'a crate::texture::TextureData>,
529}
530
531impl<'a> TextureIterator<'a> {
532 pub(crate) unsafe fn new(
539 ptr: *const *mut sys::ImTextureData,
540 end: *const *mut sys::ImTextureData,
541 ) -> Self {
542 Self {
543 ptr,
544 end,
545 _phantom: std::marker::PhantomData,
546 }
547 }
548}
549
550impl<'a> Iterator for TextureIterator<'a> {
551 type Item = &'a mut crate::texture::TextureData;
552
553 fn next(&mut self) -> Option<Self::Item> {
554 if self.ptr >= self.end {
555 None
556 } else {
557 unsafe {
558 let texture_ptr = *self.ptr;
559 self.ptr = self.ptr.add(1);
560 if texture_ptr.is_null() {
561 self.next() } else {
563 Some(crate::texture::TextureData::from_raw(texture_ptr))
564 }
565 }
566 }
567 }
568}
569
570impl<'a> std::iter::FusedIterator for TextureIterator<'a> {}