arcdps_imgui\render/
draw_data.rs

1use std::slice;
2
3use crate::internal::{RawCast, RawWrapper};
4use crate::render::renderer::TextureId;
5use crate::sys;
6
7/// All draw data to render a Dear ImGui frame.
8#[repr(C)]
9pub struct DrawData {
10    /// Only valid after render() is called and before the next new frame() is called.
11    valid: bool,
12    // Array of DrawList.
13    cmd_lists: *mut *mut DrawList,
14    /// Number of DrawList to render.
15    cmd_lists_count: i32,
16    /// For convenience, sum of all draw list index buffer sizes.
17    pub total_idx_count: i32,
18    /// For convenience, sum of all draw list vertex buffer sizes.
19    pub total_vtx_count: i32,
20    /// Upper-left position of the viewport to render.
21    ///
22    /// (= upper-left corner of the orthogonal projection matrix to use)
23    pub display_pos: [f32; 2],
24    /// Size of the viewport to render.
25    ///
26    /// (= display_pos + display_size == lower-right corner of the orthogonal matrix to use)
27    pub display_size: [f32; 2],
28    /// Amount of pixels for each unit of display_size.
29    ///
30    /// Based on io.display_frame_buffer_scale. Typically [1.0, 1.0] on normal displays, and
31    /// [2.0, 2.0] on Retina displays, but fractional values are also possible.
32    pub framebuffer_scale: [f32; 2],
33}
34
35unsafe impl RawCast<sys::ImDrawData> for DrawData {}
36
37impl DrawData {
38    /// Returns an iterator over the draw lists included in the draw data.
39    #[inline]
40    pub fn draw_lists(&self) -> DrawListIterator<'_> {
41        unsafe {
42            DrawListIterator {
43                iter: self.cmd_lists().iter(),
44            }
45        }
46    }
47    /// Returns the number of draw lists included in the draw data.
48    #[inline]
49    pub fn draw_lists_count(&self) -> usize {
50        use std::convert::TryInto;
51        self.cmd_lists_count.try_into().unwrap()
52    }
53    #[inline]
54    pub(crate) unsafe fn cmd_lists(&self) -> &[*const DrawList] {
55        slice::from_raw_parts(
56            self.cmd_lists as *const *const DrawList,
57            self.cmd_lists_count as usize,
58        )
59    }
60    /// Converts all buffers from indexed to non-indexed, in case you cannot render indexed
61    /// buffers.
62    ///
63    /// **This is slow and most likely a waste of resources. Always prefer indexed rendering!**
64    #[doc(alias = "DeIndexAllBuffers")]
65    pub fn deindex_all_buffers(&mut self) {
66        unsafe {
67            sys::ImDrawData_DeIndexAllBuffers(self.raw_mut());
68        }
69    }
70    /// Scales the clip rect of each draw command.
71    ///
72    /// Can be used if your final output buffer is at a different scale than imgui-rs expects, or
73    /// if there is a difference between your window resolution and framebuffer resolution.
74    #[doc(alias = "ScaleClipRects")]
75    pub fn scale_clip_rects(&mut self, fb_scale: [f32; 2]) {
76        unsafe {
77            sys::ImDrawData_ScaleClipRects(self.raw_mut(), fb_scale.into());
78        }
79    }
80}
81
82/// Iterator over draw lists
83pub struct DrawListIterator<'a> {
84    iter: std::slice::Iter<'a, *const DrawList>,
85}
86
87impl<'a> Iterator for DrawListIterator<'a> {
88    type Item = &'a DrawList;
89
90    fn next(&mut self) -> Option<Self::Item> {
91        self.iter.next().map(|&ptr| unsafe { &*ptr })
92    }
93}
94
95#[test]
96#[cfg(test)]
97fn test_drawdata_memory_layout() {
98    use std::mem;
99    assert_eq!(
100        mem::size_of::<DrawData>(),
101        mem::size_of::<sys::ImDrawData>()
102    );
103    assert_eq!(
104        mem::align_of::<DrawData>(),
105        mem::align_of::<sys::ImDrawData>()
106    );
107    use sys::ImDrawData;
108    macro_rules! assert_field_offset {
109        ($l:ident, $r:ident) => {
110            assert_eq!(
111                memoffset::offset_of!(DrawData, $l),
112                memoffset::offset_of!(ImDrawData, $r)
113            );
114        };
115    }
116    assert_field_offset!(valid, Valid);
117    assert_field_offset!(cmd_lists, CmdLists);
118    assert_field_offset!(cmd_lists_count, CmdListsCount);
119    assert_field_offset!(total_idx_count, TotalIdxCount);
120    assert_field_offset!(total_vtx_count, TotalVtxCount);
121    assert_field_offset!(display_pos, DisplayPos);
122    assert_field_offset!(display_size, DisplaySize);
123    assert_field_offset!(framebuffer_scale, FramebufferScale);
124}
125
126/// Draw command list
127#[repr(transparent)]
128pub struct DrawList(sys::ImDrawList);
129
130impl RawWrapper for DrawList {
131    type Raw = sys::ImDrawList;
132    #[inline]
133    unsafe fn raw(&self) -> &sys::ImDrawList {
134        &self.0
135    }
136    #[inline]
137    unsafe fn raw_mut(&mut self) -> &mut sys::ImDrawList {
138        &mut self.0
139    }
140}
141
142impl DrawList {
143    #[inline]
144    pub(crate) unsafe fn cmd_buffer(&self) -> &[sys::ImDrawCmd] {
145        slice::from_raw_parts(
146            self.0.CmdBuffer.Data as *const sys::ImDrawCmd,
147            self.0.CmdBuffer.Size as usize,
148        )
149    }
150    #[inline]
151    pub fn idx_buffer(&self) -> &[DrawIdx] {
152        unsafe {
153            slice::from_raw_parts(
154                self.0.IdxBuffer.Data as *const DrawIdx,
155                self.0.IdxBuffer.Size as usize,
156            )
157        }
158    }
159    #[inline]
160    pub fn vtx_buffer(&self) -> &[DrawVert] {
161        unsafe {
162            slice::from_raw_parts(
163                self.0.VtxBuffer.Data as *const DrawVert,
164                self.0.VtxBuffer.Size as usize,
165            )
166        }
167    }
168
169    /// # Safety
170    /// This is equivalent to `transmute(self.vtx_buffer())` with a little more
171    /// checking, and thus inherits the safety considerations of `transmute`ing
172    /// slices.
173    pub unsafe fn transmute_vtx_buffer<VTy: Copy>(&self) -> &[VTy] {
174        // these checks are constant and thus are removed from release builds
175        assert_eq!(
176            core::mem::size_of::<VTy>(),
177            core::mem::size_of::<DrawVert>(),
178        );
179        assert!(core::mem::align_of::<VTy>() <= core::mem::align_of::<DrawVert>());
180        slice::from_raw_parts(self.0.VtxBuffer.Data.cast(), self.0.VtxBuffer.Size as usize)
181    }
182
183    #[inline]
184    pub fn commands(&self) -> DrawCmdIterator<'_> {
185        unsafe {
186            DrawCmdIterator {
187                iter: self.cmd_buffer().iter(),
188            }
189        }
190    }
191}
192
193pub struct DrawCmdIterator<'a> {
194    iter: std::slice::Iter<'a, sys::ImDrawCmd>,
195}
196
197impl<'a> Iterator for DrawCmdIterator<'a> {
198    type Item = DrawCmd;
199
200    #[inline]
201    fn next(&mut self) -> Option<Self::Item> {
202        self.iter.next().map(|cmd| {
203            let cmd_params = DrawCmdParams {
204                clip_rect: cmd.ClipRect.into(),
205                texture_id: TextureId::from(cmd.TextureId),
206                vtx_offset: cmd.VtxOffset as usize,
207                idx_offset: cmd.IdxOffset as usize,
208            };
209            match cmd.UserCallback {
210                Some(raw_callback) if raw_callback as usize == -1isize as usize => {
211                    DrawCmd::ResetRenderState
212                }
213                Some(raw_callback) => DrawCmd::RawCallback {
214                    callback: raw_callback,
215                    raw_cmd: cmd,
216                },
217                None => DrawCmd::Elements {
218                    count: cmd.ElemCount as usize,
219                    cmd_params,
220                },
221            }
222        })
223    }
224}
225
226/// A vertex index
227pub type DrawIdx = sys::ImDrawIdx;
228
229#[derive(Copy, Clone, Debug, PartialEq)]
230pub struct DrawCmdParams {
231    /// left, up, right, down
232    pub clip_rect: [f32; 4],
233    pub texture_id: TextureId,
234    pub vtx_offset: usize,
235    pub idx_offset: usize,
236}
237
238/// A draw command
239pub enum DrawCmd {
240    Elements {
241        /// The number of indices used for this draw command
242        count: usize,
243        cmd_params: DrawCmdParams,
244    },
245    ResetRenderState,
246    RawCallback {
247        callback: unsafe extern "C" fn(*const sys::ImDrawList, cmd: *const sys::ImDrawCmd),
248        raw_cmd: *const sys::ImDrawCmd,
249    },
250}
251
252/// A single vertex
253#[repr(C)]
254#[derive(Copy, Clone, Debug, PartialEq)]
255pub struct DrawVert {
256    pub pos: [f32; 2],
257    pub uv: [f32; 2],
258    pub col: [u8; 4],
259}
260
261#[test]
262#[cfg(test)]
263fn test_drawvert_memory_layout() {
264    use std::mem;
265    assert_eq!(
266        mem::size_of::<DrawVert>(),
267        mem::size_of::<sys::ImDrawVert>()
268    );
269    assert_eq!(
270        mem::align_of::<DrawVert>(),
271        mem::align_of::<sys::ImDrawVert>()
272    );
273    use sys::ImDrawVert;
274    macro_rules! assert_field_offset {
275        ($l:ident, $r:ident) => {
276            assert_eq!(
277                memoffset::offset_of!(DrawVert, $l),
278                memoffset::offset_of!(ImDrawVert, $r)
279            );
280        };
281    }
282    assert_field_offset!(pos, pos);
283    assert_field_offset!(uv, uv);
284    assert_field_offset!(col, col);
285}