1use std::mem::size_of;
2use std::slice;
3
4use crate::internal::{RawCast, RawWrapper};
5use crate::math::MintVec2;
6use crate::render::renderer::TextureId;
7use crate::sys;
8
9#[repr(C)]
11pub struct DrawData {
12 valid: bool,
14 cmd_lists_count: i32,
16 pub total_idx_count: i32,
18 pub total_vtx_count: i32,
20 cmd_lists: *mut *mut DrawList,
22 pub display_pos: [f32; 2],
26 pub display_size: [f32; 2],
30 pub framebuffer_scale: [f32; 2],
35
36 #[cfg(feature = "docking")]
37 owner_viewport: *mut sys::ImGuiViewport,
38}
39
40unsafe impl RawCast<sys::ImDrawData> for DrawData {}
41
42impl DrawData {
43 #[inline]
45 pub fn draw_lists(&self) -> DrawListIterator<'_> {
46 unsafe {
47 DrawListIterator {
48 iter: self.cmd_lists().iter(),
49 }
50 }
51 }
52 #[inline]
54 pub fn draw_lists_count(&self) -> usize {
55 self.cmd_lists_count.try_into().unwrap()
56 }
57 #[inline]
58 pub(crate) unsafe fn cmd_lists(&self) -> &[*const DrawList] {
59 slice::from_raw_parts(
60 self.cmd_lists as *const *const DrawList,
61 self.cmd_lists_count as usize,
62 )
63 }
64 #[doc(alias = "DeIndexAllBuffers")]
69 pub fn deindex_all_buffers(&mut self) {
70 unsafe {
71 sys::ImDrawData_DeIndexAllBuffers(self.raw_mut());
72 }
73 }
74 #[doc(alias = "ScaleClipRects")]
79 pub fn scale_clip_rects(&mut self, fb_scale: MintVec2) {
80 unsafe {
81 sys::ImDrawData_ScaleClipRects(self.raw_mut(), fb_scale.into());
82 }
83 }
84}
85
86pub struct DrawListIterator<'a> {
88 iter: std::slice::Iter<'a, *const DrawList>,
89}
90
91impl<'a> Iterator for DrawListIterator<'a> {
92 type Item = &'a DrawList;
93
94 fn next(&mut self) -> Option<Self::Item> {
95 self.iter.next().map(|&ptr| unsafe { &*ptr })
96 }
97}
98
99#[test]
100#[cfg(test)]
101fn test_drawdata_memory_layout() {
102 use std::mem;
103 assert_eq!(
104 mem::size_of::<DrawData>(),
105 mem::size_of::<sys::ImDrawData>()
106 );
107 assert_eq!(
108 mem::align_of::<DrawData>(),
109 mem::align_of::<sys::ImDrawData>()
110 );
111 use sys::ImDrawData;
112 macro_rules! assert_field_offset {
113 ($l:ident, $r:ident) => {
114 assert_eq!(
115 memoffset::offset_of!(DrawData, $l),
116 memoffset::offset_of!(ImDrawData, $r)
117 );
118 };
119 }
120 assert_field_offset!(valid, Valid);
121 assert_field_offset!(cmd_lists, CmdLists);
122 assert_field_offset!(cmd_lists_count, CmdListsCount);
123 assert_field_offset!(total_idx_count, TotalIdxCount);
124 assert_field_offset!(total_vtx_count, TotalVtxCount);
125 assert_field_offset!(display_pos, DisplayPos);
126 assert_field_offset!(display_size, DisplaySize);
127 assert_field_offset!(framebuffer_scale, FramebufferScale);
128}
129
130#[repr(transparent)]
132pub struct DrawList(sys::ImDrawList);
133
134impl RawWrapper for DrawList {
135 type Raw = sys::ImDrawList;
136 #[inline]
137 unsafe fn raw(&self) -> &sys::ImDrawList {
138 &self.0
139 }
140 #[inline]
141 unsafe fn raw_mut(&mut self) -> &mut sys::ImDrawList {
142 &mut self.0
143 }
144}
145
146impl DrawList {
147 #[inline]
148 pub(crate) unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
149 slice::from_raw_parts(
150 self.0.CmdBuffer.Data as *const sys::ImDrawCmd,
151 self.0.CmdBuffer.Size as usize,
152 )
153 }
154 #[inline]
155 pub fn idx_buffer(&self) -> &[DrawIdx] {
156 unsafe {
157 slice::from_raw_parts(
158 self.0.IdxBuffer.Data as *const DrawIdx,
159 self.0.IdxBuffer.Size as usize,
160 )
161 }
162 }
163 #[inline]
164 pub fn vtx_buffer(&self) -> &[DrawVert] {
165 unsafe {
166 slice::from_raw_parts(
167 self.0.VtxBuffer.Data as *const DrawVert,
168 self.0.VtxBuffer.Size as usize,
169 )
170 }
171 }
172
173 pub unsafe fn transmute_vtx_buffer<VTy: Copy>(&self) -> &[VTy] {
178 assert_eq!(
180 core::mem::size_of::<VTy>(),
181 core::mem::size_of::<DrawVert>(),
182 );
183 assert!(core::mem::align_of::<VTy>() <= core::mem::align_of::<DrawVert>());
184 slice::from_raw_parts(self.0.VtxBuffer.Data.cast(), self.0.VtxBuffer.Size as usize)
185 }
186
187 #[inline]
188 pub fn commands(&self) -> DrawCmdIterator<'_> {
189 unsafe {
190 DrawCmdIterator {
191 iter: self.cmd_buffer().iter(),
192 }
193 }
194 }
195}
196
197pub struct DrawCmdIterator<'a> {
198 iter: std::slice::Iter<'a, sys::ImDrawCmd>,
199}
200
201impl<'a> Iterator for DrawCmdIterator<'a> {
202 type Item = DrawCmd;
203
204 #[inline]
205 fn next(&mut self) -> Option<Self::Item> {
206 self.iter.next().map(|cmd| {
207 let cmd_params = DrawCmdParams {
208 clip_rect: cmd.ClipRect.into(),
209 texture_id: TextureId::from(cmd.TextureId),
210 vtx_offset: cmd.VtxOffset as usize,
211 idx_offset: cmd.IdxOffset as usize,
212 };
213 match cmd.UserCallback {
214 Some(raw_callback) if raw_callback as usize == -1isize as usize => {
215 DrawCmd::ResetRenderState
216 }
217 Some(raw_callback) => DrawCmd::RawCallback {
218 callback: raw_callback,
219 raw_cmd: cmd,
220 },
221 None => DrawCmd::Elements {
222 count: cmd.ElemCount as usize,
223 cmd_params,
224 },
225 }
226 })
227 }
228}
229
230pub type DrawIdx = sys::ImDrawIdx;
232
233#[derive(Copy, Clone, Debug, PartialEq)]
234pub struct DrawCmdParams {
235 pub clip_rect: [f32; 4],
237 pub texture_id: TextureId,
238 pub vtx_offset: usize,
239 pub idx_offset: usize,
240}
241
242pub enum DrawCmd {
244 Elements {
245 count: usize,
247 cmd_params: DrawCmdParams,
248 },
249 ResetRenderState,
250 RawCallback {
251 callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
252 raw_cmd: *const sys::ImDrawCmd,
253 },
254}
255
256#[repr(C)]
258#[derive(Copy, Clone, Debug, PartialEq)]
259pub struct DrawVert {
260 pub pos: [f32; 2],
261 pub uv: [f32; 2],
262 pub col: [u8; 4],
263}
264
265#[test]
266#[cfg(test)]
267fn test_drawvert_memory_layout() {
268 use std::mem;
269 assert_eq!(
270 mem::size_of::<DrawVert>(),
271 mem::size_of::<sys::ImDrawVert>()
272 );
273 assert_eq!(
274 mem::align_of::<DrawVert>(),
275 mem::align_of::<sys::ImDrawVert>()
276 );
277 use sys::ImDrawVert;
278 macro_rules! assert_field_offset {
279 ($l:ident, $r:ident) => {
280 assert_eq!(
281 memoffset::offset_of!(DrawVert, $l),
282 memoffset::offset_of!(ImDrawVert, $r)
283 );
284 };
285 }
286 assert_field_offset!(pos, pos);
287 assert_field_offset!(uv, uv);
288 assert_field_offset!(col, col);
289}
290
291pub struct OwnedDrawData {
296 draw_data: *mut sys::ImDrawData,
297}
298
299impl OwnedDrawData {
300 #[inline]
304 pub fn draw_data(&self) -> Option<&DrawData> {
305 if !self.draw_data.is_null() {
306 Some(unsafe { DrawData::from_raw(&*self.draw_data) })
307 } else {
308 None
309 }
310 }
311
312 #[cfg(feature = "docking")]
313 unsafe fn copy_docking_properties(source: &sys::ImDrawData, dest: *mut sys::ImDrawData) {
314 (*dest).OwnerViewport = source.OwnerViewport;
315 }
316 #[cfg(not(feature = "docking"))]
317 unsafe fn copy_docking_properties(_source: &sys::ImDrawData, _dest: *mut sys::ImDrawData) {}
318}
319
320impl Default for OwnedDrawData {
321 #[inline]
323 fn default() -> Self {
324 Self {
325 draw_data: std::ptr::null_mut(),
326 }
327 }
328}
329
330impl From<&DrawData> for OwnedDrawData {
331 fn from(value: &DrawData) -> Self {
333 OwnedDrawData {
334 draw_data: unsafe {
335 let other_ptr = value.raw();
336 let result = sys::ImDrawData_ImDrawData();
337 (*result).Valid = other_ptr.Valid;
338 (*result).TotalIdxCount = other_ptr.TotalIdxCount;
339 (*result).TotalVtxCount = other_ptr.TotalVtxCount;
340 (*result).DisplayPos = other_ptr.DisplayPos;
341 (*result).DisplaySize = other_ptr.DisplaySize;
342 (*result).FramebufferScale = other_ptr.FramebufferScale;
343 (*result).CmdListsCount = other_ptr.CmdListsCount;
344 (*result).CmdLists = sys::igMemAlloc(
345 size_of::<*mut sys::ImDrawList>() * other_ptr.CmdListsCount as usize,
346 ) as *mut *mut sys::ImDrawList;
347 OwnedDrawData::copy_docking_properties(other_ptr, result);
348
349 let mut current_draw_list = (*result).CmdLists;
350 for i in 0..other_ptr.CmdListsCount as usize {
351 *current_draw_list = sys::ImDrawList_CloneOutput(*other_ptr.CmdLists.add(i));
352 current_draw_list = current_draw_list.add(1);
353 }
354 result
355 },
356 }
357 }
358}
359
360impl Drop for OwnedDrawData {
361 fn drop(&mut self) {
363 unsafe {
364 if !self.draw_data.is_null() {
365 if !(*self.draw_data).CmdLists.is_null() {
366 for i in 0..(*self.draw_data).CmdListsCount as usize {
367 let ptr = *(*self.draw_data).CmdLists.add(i);
368 if !ptr.is_null() {
369 sys::ImDrawList_destroy(ptr);
370 }
371 }
372 sys::igMemFree((*self.draw_data).CmdLists as *mut std::ffi::c_void);
373 }
374 sys::ImDrawData_destroy(self.draw_data);
375 self.draw_data = std::ptr::null_mut();
376 }
377 }
378 }
379}
380
381#[test]
382#[cfg(test)]
383fn test_owneddrawdata_default() {
384 let default = OwnedDrawData::default();
385 assert!(default.draw_data().is_none());
386}
387
388#[test]
389#[cfg(test)]
390fn test_owneddrawdata_from_drawdata() {
391 let (_guard, _ctx) = crate::test::test_ctx();
392
393 let mut draw_list = sys::ImDrawList::default();
395 let mut draw_lists_raw = [std::ptr::addr_of_mut!(draw_list)];
396 let draw_data_raw = sys::ImDrawData {
397 Valid: true,
398 CmdListsCount: 1,
399 CmdLists: draw_lists_raw.as_mut_ptr(),
400 TotalIdxCount: 123,
401 TotalVtxCount: 456,
402 DisplayPos: sys::ImVec2 { x: 123.0, y: 456.0 },
403 DisplaySize: sys::ImVec2 { x: 789.0, y: 012.0 },
404 FramebufferScale: sys::ImVec2 { x: 3.0, y: 7.0 },
405 #[cfg(feature = "docking")]
406 OwnerViewport: unsafe { std::ptr::null_mut::<sys::ImGuiViewport>().offset(123) },
407 };
408 let draw_data = unsafe { DrawData::from_raw(&draw_data_raw) };
409
410 let owned_draw_data: OwnedDrawData = draw_data.into();
412 let inner_draw_data = owned_draw_data.draw_data();
413 assert!(inner_draw_data.is_some());
414 let owned_draw_data_raw = unsafe { inner_draw_data.unwrap().raw() };
415 assert_eq!(draw_data_raw.Valid, owned_draw_data_raw.Valid);
416 assert_eq!(
417 draw_data_raw.CmdListsCount,
418 owned_draw_data_raw.CmdListsCount
419 );
420 assert!(!draw_data_raw.CmdLists.is_null());
421 assert_eq!(
422 draw_data_raw.TotalIdxCount,
423 owned_draw_data_raw.TotalIdxCount
424 );
425 assert_eq!(
426 draw_data_raw.TotalVtxCount,
427 owned_draw_data_raw.TotalVtxCount
428 );
429 assert_eq!(draw_data_raw.DisplayPos, owned_draw_data_raw.DisplayPos);
430 assert_eq!(draw_data_raw.DisplaySize, owned_draw_data_raw.DisplaySize);
431 assert_eq!(
432 draw_data_raw.FramebufferScale,
433 owned_draw_data_raw.FramebufferScale
434 );
435
436 #[cfg(feature = "docking")]
437 assert_eq!(
438 draw_data_raw.OwnerViewport,
439 owned_draw_data_raw.OwnerViewport
440 );
441}
442
443#[test]
444#[cfg(test)]
445fn test_owneddrawdata_drop() {
446 let (_guard, _ctx) = crate::test::test_ctx();
447 let initial_allocation_count = unsafe { (*sys::igGetIO()).MetricsActiveAllocations };
448
449 let mut draw_list = sys::ImDrawList::default();
451 let mut draw_lists_raw = [std::ptr::addr_of_mut!(draw_list)];
452 let draw_data_raw = sys::ImDrawData {
453 Valid: true,
454 CmdListsCount: 1,
455 CmdLists: draw_lists_raw.as_mut_ptr(),
456 TotalIdxCount: 0,
457 TotalVtxCount: 0,
458 DisplayPos: sys::ImVec2 { x: 0.0, y: 0.0 },
459 DisplaySize: sys::ImVec2 { x: 800.0, y: 600.0 },
460 FramebufferScale: sys::ImVec2 { x: 1.0, y: 1.0 },
461 #[cfg(feature = "docking")]
462 OwnerViewport: std::ptr::null_mut(),
463 };
464 let draw_data = unsafe { DrawData::from_raw(&draw_data_raw) };
465
466 {
468 let _owned_draw_data: OwnedDrawData = draw_data.into();
469 let cloned_allocation_count = unsafe { (*sys::igGetIO()).MetricsActiveAllocations };
470 assert!(cloned_allocation_count > initial_allocation_count);
471 }
473 let final_allocation_count = unsafe { (*sys::igGetIO()).MetricsActiveAllocations };
474 assert_eq!(initial_allocation_count, final_allocation_count);
475}