1use dear_imgui_rs::sys as imgui_sys;
42use dear_imgui_rs::texture::TextureRef;
43pub use dear_imgui_rs::{Context, Ui};
44use dear_implot3d_sys as sys;
45
46mod flags;
47mod style;
48mod ui_ext;
49
50pub use flags::*;
51pub use style::*;
52pub use ui_ext::*;
53pub mod meshes;
54pub mod plots;
55
56use std::borrow::Cow;
57use std::cell::RefCell;
58
59fn len_i32(len: usize) -> Option<i32> {
60 i32::try_from(len).ok()
61}
62
63const IMPLOT3D_AUTO: i32 = -1;
64
65thread_local! {
66 static NEXT_PLOT3D_SPEC: RefCell<Option<sys::ImPlot3DSpec_c>> = RefCell::new(None);
67}
68
69pub(crate) fn update_next_plot3d_spec(f: impl FnOnce(&mut sys::ImPlot3DSpec_c)) {
70 NEXT_PLOT3D_SPEC.with(|cell| {
71 let mut guard = cell.borrow_mut();
72 let mut spec = guard.take().unwrap_or_else(default_plot3d_spec);
73 f(&mut spec);
74 *guard = Some(spec);
75 })
76}
77
78fn take_next_plot3d_spec() -> Option<sys::ImPlot3DSpec_c> {
79 NEXT_PLOT3D_SPEC.with(|cell| cell.borrow_mut().take())
80}
81
82fn default_plot3d_spec() -> sys::ImPlot3DSpec_c {
83 let auto_col = sys::ImVec4_c {
84 x: 0.0,
85 y: 0.0,
86 z: 0.0,
87 w: -1.0,
88 };
89
90 sys::ImPlot3DSpec_c {
91 LineColor: auto_col,
92 LineWeight: 1.0,
93 FillColor: auto_col,
94 FillAlpha: -1.0,
95 Marker: sys::ImPlot3DMarker_Auto as _,
96 MarkerSize: -1.0,
97 MarkerLineColor: auto_col,
98 MarkerFillColor: auto_col,
99 Offset: 0,
100 Stride: IMPLOT3D_AUTO,
101 Flags: sys::ImPlot3DItemFlags_None as _,
102 }
103}
104
105fn plot3d_spec_from(flags: u32, offset: i32, stride: i32) -> sys::ImPlot3DSpec_c {
106 let mut spec = take_next_plot3d_spec().unwrap_or_else(default_plot3d_spec);
107 spec.Flags = flags as sys::ImPlot3DItemFlags;
108 spec.Offset = offset;
109 spec.Stride = stride;
110 spec
111}
112
113trait ImVec2Ctor {
114 fn from_xy(x: f32, y: f32) -> Self;
115}
116
117impl ImVec2Ctor for sys::ImVec2_c {
118 fn from_xy(x: f32, y: f32) -> Self {
119 Self { x, y }
120 }
121}
122
123impl ImVec2Ctor for imgui_sys::ImVec2_c {
124 fn from_xy(x: f32, y: f32) -> Self {
125 Self { x, y }
126 }
127}
128
129#[inline]
130fn imvec2<T: ImVec2Ctor>(x: f32, y: f32) -> T {
131 T::from_xy(x, y)
132}
133
134trait ImVec4Ctor {
135 fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self;
136}
137
138impl ImVec4Ctor for sys::ImVec4_c {
139 fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
140 Self { x, y, z, w }
141 }
142}
143
144impl ImVec4Ctor for imgui_sys::ImVec4_c {
145 fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
146 Self { x, y, z, w }
147 }
148}
149
150#[inline]
151fn imvec4<T: ImVec4Ctor>(x: f32, y: f32, z: f32, w: f32) -> T {
152 T::from_xyzw(x, y, z, w)
153}
154
155#[allow(non_snake_case)]
156mod compat_ffi {
157 use super::{imgui_sys, sys};
158
159 unsafe extern "C" {
160 pub fn ImPlot3D_PlotToPixels_double(x: f64, y: f64, z: f64) -> imgui_sys::ImVec2_c;
161 pub fn ImPlot3D_GetPlotRectPos() -> imgui_sys::ImVec2_c;
162 pub fn ImPlot3D_GetPlotRectSize() -> imgui_sys::ImVec2_c;
163 pub fn ImPlot3D_NextColormapColor() -> imgui_sys::ImVec4_c;
164 pub fn ImPlot3D_GetColormapColor(
165 idx: ::std::os::raw::c_int,
166 cmap: sys::ImPlot3DColormap,
167 ) -> imgui_sys::ImVec4_c;
168 }
169}
170
171#[cfg(debug_assertions)]
173thread_local! {
174 static DEBUG_PLOT_STATE: PlotDebugState = PlotDebugState { in_plot: std::cell::Cell::new(false), setup_locked: std::cell::Cell::new(false) };
175}
176
177#[cfg(debug_assertions)]
178struct PlotDebugState {
179 in_plot: std::cell::Cell<bool>,
180 setup_locked: std::cell::Cell<bool>,
181}
182
183#[cfg(debug_assertions)]
184#[inline]
185fn debug_begin_plot() {
186 DEBUG_PLOT_STATE.with(|s| {
187 s.in_plot.set(true);
188 s.setup_locked.set(false);
189 });
190}
191
192#[cfg(debug_assertions)]
193#[inline]
194fn debug_end_plot() {
195 DEBUG_PLOT_STATE.with(|s| {
196 s.in_plot.set(false);
197 s.setup_locked.set(false);
198 });
199}
200
201#[cfg(debug_assertions)]
202#[inline]
203fn debug_before_setup() {
204 DEBUG_PLOT_STATE.with(|s| {
205 debug_assert!(
206 s.in_plot.get(),
207 "Setup* called outside of BeginPlot/EndPlot"
208 );
209 debug_assert!(
210 !s.setup_locked.get(),
211 "Setup* must be called before any plotting (PlotX) or locking operations"
212 );
213 });
214}
215
216#[cfg(debug_assertions)]
217#[inline]
218fn debug_before_plot() {
219 DEBUG_PLOT_STATE.with(|s| {
220 debug_assert!(s.in_plot.get(), "Plot* called outside of BeginPlot/EndPlot");
221 s.setup_locked.set(true);
222 });
223}
224
225#[cfg(not(debug_assertions))]
226#[inline]
227fn debug_begin_plot() {}
228#[cfg(not(debug_assertions))]
229#[inline]
230fn debug_end_plot() {}
231#[cfg(not(debug_assertions))]
232#[inline]
233fn debug_before_setup() {}
234#[cfg(not(debug_assertions))]
235#[inline]
236fn debug_before_plot() {}
237
238pub fn show_all_demos() {
243 unsafe { sys::ImPlot3D_ShowAllDemos() }
244}
245
246pub fn show_demo_window() {
260 unsafe { sys::ImPlot3D_ShowDemoWindow(std::ptr::null_mut()) }
261}
262
263pub fn show_demo_window_with_flag(p_open: &mut bool) {
265 unsafe { sys::ImPlot3D_ShowDemoWindow(p_open as *mut bool) }
266}
267
268pub fn show_style_editor() {
273 unsafe { sys::ImPlot3D_ShowStyleEditor(std::ptr::null_mut()) }
274}
275
276pub fn show_metrics_window() {
281 unsafe { sys::ImPlot3D_ShowMetricsWindow(std::ptr::null_mut()) }
282}
283
284pub fn show_metrics_window_with_flag(p_open: &mut bool) {
286 unsafe { sys::ImPlot3D_ShowMetricsWindow(p_open as *mut bool) }
287}
288
289pub struct Plot3DContext {
308 raw: *mut sys::ImPlot3DContext,
309}
310
311impl Plot3DContext {
312 pub fn try_create(_imgui: &Context) -> dear_imgui_rs::ImGuiResult<Self> {
316 unsafe {
317 let ctx = sys::ImPlot3D_CreateContext();
318 if ctx.is_null() {
319 return Err(dear_imgui_rs::ImGuiError::context_creation(
320 "ImPlot3D_CreateContext returned null",
321 ));
322 }
323
324 sys::ImPlot3D_SetCurrentContext(ctx);
326 Ok(Self { raw: ctx })
327 }
328 }
329
330 pub fn create(imgui: &Context) -> Self {
332 Self::try_create(imgui).expect("Failed to create ImPlot3D context")
333 }
334
335 pub fn set_as_current(&self) {
337 unsafe {
338 sys::ImPlot3D_SetCurrentContext(self.raw);
339 }
340 }
341
342 pub fn raw_style_mut() -> *mut sys::ImPlot3DStyle {
347 unsafe { sys::ImPlot3D_GetStyle() }
348 }
349
350 pub fn get_plot_ui<'ui>(&self, ui: &'ui Ui) -> Plot3DUi<'ui> {
355 Plot3DUi { _ui: ui }
356 }
357}
358
359impl Drop for Plot3DContext {
360 fn drop(&mut self) {
361 if self.raw.is_null() {
362 return;
363 }
364
365 unsafe {
366 if sys::ImPlot3D_GetCurrentContext() == self.raw {
367 sys::ImPlot3D_SetCurrentContext(std::ptr::null_mut());
368 }
369 sys::ImPlot3D_DestroyContext(self.raw);
370 }
371 }
372}
373
374pub struct Plot3DUi<'ui> {
395 _ui: &'ui Ui,
396}
397
398pub struct Plot3DToken;
403
404impl<'ui> Plot3DUi<'ui> {
405 pub fn begin_plot<S: AsRef<str>>(&self, title: S) -> Plot3DBuilder {
425 Plot3DBuilder {
426 title: title.as_ref().into(),
427 size: None,
428 flags: Plot3DFlags::empty(),
429 }
430 }
431
432 pub fn plot_line_f32<S: AsRef<str>>(
457 &self,
458 label: S,
459 xs: &[f32],
460 ys: &[f32],
461 zs: &[f32],
462 flags: Line3DFlags,
463 ) {
464 if xs.len() != ys.len() || ys.len() != zs.len() {
465 return;
466 }
467 let Some(count) = len_i32(xs.len()) else {
468 return;
469 };
470 let label = label.as_ref();
471 if label.contains('\0') {
472 return;
473 }
474 let stride_bytes = std::mem::size_of::<f32>() as i32;
475 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
476 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
477 sys::ImPlot3D_PlotLine_FloatPtr(
478 label_ptr,
479 xs.as_ptr(),
480 ys.as_ptr(),
481 zs.as_ptr(),
482 count,
483 spec,
484 );
485 })
486 }
487
488 pub fn plot_line_f32_raw<S: AsRef<str>>(
490 &self,
491 label: S,
492 xs: &[f32],
493 ys: &[f32],
494 zs: &[f32],
495 flags: Line3DFlags,
496 offset: i32,
497 stride: i32,
498 ) {
499 if xs.len() != ys.len() || ys.len() != zs.len() {
500 return;
501 }
502 let Some(count) = len_i32(xs.len()) else {
503 return;
504 };
505 let label = label.as_ref();
506 if label.contains('\0') {
507 return;
508 }
509 let stride_bytes = if stride == 0 {
510 std::mem::size_of::<f32>() as i32
511 } else {
512 stride
513 };
514 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
515 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
516 sys::ImPlot3D_PlotLine_FloatPtr(
517 label_ptr,
518 xs.as_ptr(),
519 ys.as_ptr(),
520 zs.as_ptr(),
521 count,
522 spec,
523 );
524 })
525 }
526
527 pub fn plot_line_f64<S: AsRef<str>>(
529 &self,
530 label: S,
531 xs: &[f64],
532 ys: &[f64],
533 zs: &[f64],
534 flags: Line3DFlags,
535 ) {
536 if xs.len() != ys.len() || ys.len() != zs.len() {
537 return;
538 }
539 let Some(count) = len_i32(xs.len()) else {
540 return;
541 };
542 let label = label.as_ref();
543 if label.contains('\0') {
544 return;
545 }
546 let stride_bytes = std::mem::size_of::<f64>() as i32;
547 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
548 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
549 sys::ImPlot3D_PlotLine_doublePtr(
550 label_ptr,
551 xs.as_ptr(),
552 ys.as_ptr(),
553 zs.as_ptr(),
554 count,
555 spec,
556 );
557 })
558 }
559
560 pub fn plot_line_f64_raw<S: AsRef<str>>(
562 &self,
563 label: S,
564 xs: &[f64],
565 ys: &[f64],
566 zs: &[f64],
567 flags: Line3DFlags,
568 offset: i32,
569 stride: i32,
570 ) {
571 if xs.len() != ys.len() || ys.len() != zs.len() {
572 return;
573 }
574 let Some(count) = len_i32(xs.len()) else {
575 return;
576 };
577 let label = label.as_ref();
578 if label.contains('\0') {
579 return;
580 }
581 let stride_bytes = if stride == 0 {
582 std::mem::size_of::<f64>() as i32
583 } else {
584 stride
585 };
586 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
587 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
588 sys::ImPlot3D_PlotLine_doublePtr(
589 label_ptr,
590 xs.as_ptr(),
591 ys.as_ptr(),
592 zs.as_ptr(),
593 count,
594 spec,
595 );
596 })
597 }
598
599 pub fn plot_scatter_f32<S: AsRef<str>>(
601 &self,
602 label: S,
603 xs: &[f32],
604 ys: &[f32],
605 zs: &[f32],
606 flags: Scatter3DFlags,
607 ) {
608 if xs.len() != ys.len() || ys.len() != zs.len() {
609 return;
610 }
611 let Some(count) = len_i32(xs.len()) else {
612 return;
613 };
614 let label = label.as_ref();
615 if label.contains('\0') {
616 return;
617 }
618 let stride_bytes = std::mem::size_of::<f32>() as i32;
619 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
620 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
621 sys::ImPlot3D_PlotScatter_FloatPtr(
622 label_ptr,
623 xs.as_ptr(),
624 ys.as_ptr(),
625 zs.as_ptr(),
626 count,
627 spec,
628 );
629 })
630 }
631
632 pub fn plot_scatter_f32_raw<S: AsRef<str>>(
634 &self,
635 label: S,
636 xs: &[f32],
637 ys: &[f32],
638 zs: &[f32],
639 flags: Scatter3DFlags,
640 offset: i32,
641 stride: i32,
642 ) {
643 if xs.len() != ys.len() || ys.len() != zs.len() {
644 return;
645 }
646 let Some(count) = len_i32(xs.len()) else {
647 return;
648 };
649 let label = label.as_ref();
650 if label.contains('\0') {
651 return;
652 }
653 let stride_bytes = if stride == 0 {
654 std::mem::size_of::<f32>() as i32
655 } else {
656 stride
657 };
658 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
659 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
660 sys::ImPlot3D_PlotScatter_FloatPtr(
661 label_ptr,
662 xs.as_ptr(),
663 ys.as_ptr(),
664 zs.as_ptr(),
665 count,
666 spec,
667 );
668 })
669 }
670
671 pub fn plot_scatter_f64<S: AsRef<str>>(
673 &self,
674 label: S,
675 xs: &[f64],
676 ys: &[f64],
677 zs: &[f64],
678 flags: Scatter3DFlags,
679 ) {
680 if xs.len() != ys.len() || ys.len() != zs.len() {
681 return;
682 }
683 let Some(count) = len_i32(xs.len()) else {
684 return;
685 };
686 let label = label.as_ref();
687 if label.contains('\0') {
688 return;
689 }
690 let stride_bytes = std::mem::size_of::<f64>() as i32;
691 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
692 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
693 sys::ImPlot3D_PlotScatter_doublePtr(
694 label_ptr,
695 xs.as_ptr(),
696 ys.as_ptr(),
697 zs.as_ptr(),
698 count,
699 spec,
700 );
701 })
702 }
703
704 pub fn plot_scatter_f64_raw<S: AsRef<str>>(
706 &self,
707 label: S,
708 xs: &[f64],
709 ys: &[f64],
710 zs: &[f64],
711 flags: Scatter3DFlags,
712 offset: i32,
713 stride: i32,
714 ) {
715 if xs.len() != ys.len() || ys.len() != zs.len() {
716 return;
717 }
718 let Some(count) = len_i32(xs.len()) else {
719 return;
720 };
721 let label = label.as_ref();
722 if label.contains('\0') {
723 return;
724 }
725 let stride_bytes = if stride == 0 {
726 std::mem::size_of::<f64>() as i32
727 } else {
728 stride
729 };
730 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
731 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
732 sys::ImPlot3D_PlotScatter_doublePtr(
733 label_ptr,
734 xs.as_ptr(),
735 ys.as_ptr(),
736 zs.as_ptr(),
737 count,
738 spec,
739 );
740 })
741 }
742
743 pub fn plot_triangles_f32<S: AsRef<str>>(
745 &self,
746 label: S,
747 xs: &[f32],
748 ys: &[f32],
749 zs: &[f32],
750 flags: Triangle3DFlags,
751 ) {
752 if xs.len() != ys.len() || ys.len() != zs.len() {
753 return;
754 }
755 let Some(count) = len_i32(xs.len()) else {
756 return;
757 };
758 let label = label.as_ref();
759 if label.contains('\0') {
760 return;
761 }
762 let stride_bytes = std::mem::size_of::<f32>() as i32;
763 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
764 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
765 sys::ImPlot3D_PlotTriangle_FloatPtr(
766 label_ptr,
767 xs.as_ptr(),
768 ys.as_ptr(),
769 zs.as_ptr(),
770 count,
771 spec,
772 );
773 })
774 }
775
776 pub fn plot_triangles_f32_raw<S: AsRef<str>>(
777 &self,
778 label: S,
779 xs: &[f32],
780 ys: &[f32],
781 zs: &[f32],
782 flags: Triangle3DFlags,
783 offset: i32,
784 stride: i32,
785 ) {
786 if xs.len() != ys.len() || ys.len() != zs.len() {
787 return;
788 }
789 let Some(count) = len_i32(xs.len()) else {
790 return;
791 };
792 let label = label.as_ref();
793 if label.contains('\0') {
794 return;
795 }
796 let stride_bytes = if stride == 0 {
797 std::mem::size_of::<f32>() as i32
798 } else {
799 stride
800 };
801 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
802 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
803 sys::ImPlot3D_PlotTriangle_FloatPtr(
804 label_ptr,
805 xs.as_ptr(),
806 ys.as_ptr(),
807 zs.as_ptr(),
808 count,
809 spec,
810 );
811 })
812 }
813
814 pub fn plot_quads_f32<S: AsRef<str>>(
816 &self,
817 label: S,
818 xs: &[f32],
819 ys: &[f32],
820 zs: &[f32],
821 flags: Quad3DFlags,
822 ) {
823 if xs.len() != ys.len() || ys.len() != zs.len() {
824 return;
825 }
826 let Some(count) = len_i32(xs.len()) else {
827 return;
828 };
829 let label = label.as_ref();
830 if label.contains('\0') {
831 return;
832 }
833 let stride_bytes = std::mem::size_of::<f32>() as i32;
834 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
835 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
836 sys::ImPlot3D_PlotQuad_FloatPtr(
837 label_ptr,
838 xs.as_ptr(),
839 ys.as_ptr(),
840 zs.as_ptr(),
841 count,
842 spec,
843 );
844 })
845 }
846
847 pub fn plot_quads_f32_raw<S: AsRef<str>>(
848 &self,
849 label: S,
850 xs: &[f32],
851 ys: &[f32],
852 zs: &[f32],
853 flags: Quad3DFlags,
854 offset: i32,
855 stride: i32,
856 ) {
857 if xs.len() != ys.len() || ys.len() != zs.len() {
858 return;
859 }
860 let Some(count) = len_i32(xs.len()) else {
861 return;
862 };
863 let label = label.as_ref();
864 if label.contains('\0') {
865 return;
866 }
867 let stride_bytes = if stride == 0 {
868 std::mem::size_of::<f32>() as i32
869 } else {
870 stride
871 };
872 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
873 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
874 sys::ImPlot3D_PlotQuad_FloatPtr(
875 label_ptr,
876 xs.as_ptr(),
877 ys.as_ptr(),
878 zs.as_ptr(),
879 count,
880 spec,
881 );
882 })
883 }
884
885 pub fn plot_triangles_f64<S: AsRef<str>>(
887 &self,
888 label: S,
889 xs: &[f64],
890 ys: &[f64],
891 zs: &[f64],
892 flags: Triangle3DFlags,
893 ) {
894 if xs.len() != ys.len() || ys.len() != zs.len() {
895 return;
896 }
897 let Some(count) = len_i32(xs.len()) else {
898 return;
899 };
900 let label = label.as_ref();
901 if label.contains('\0') {
902 return;
903 }
904 let stride_bytes = std::mem::size_of::<f64>() as i32;
905 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
906 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
907 sys::ImPlot3D_PlotTriangle_doublePtr(
908 label_ptr,
909 xs.as_ptr(),
910 ys.as_ptr(),
911 zs.as_ptr(),
912 count,
913 spec,
914 );
915 })
916 }
917
918 pub fn plot_triangles_f64_raw<S: AsRef<str>>(
919 &self,
920 label: S,
921 xs: &[f64],
922 ys: &[f64],
923 zs: &[f64],
924 flags: Triangle3DFlags,
925 offset: i32,
926 stride: i32,
927 ) {
928 if xs.len() != ys.len() || ys.len() != zs.len() {
929 return;
930 }
931 let Some(count) = len_i32(xs.len()) else {
932 return;
933 };
934 let label = label.as_ref();
935 if label.contains('\0') {
936 return;
937 }
938 let stride_bytes = if stride == 0 {
939 std::mem::size_of::<f64>() as i32
940 } else {
941 stride
942 };
943 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
944 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
945 sys::ImPlot3D_PlotTriangle_doublePtr(
946 label_ptr,
947 xs.as_ptr(),
948 ys.as_ptr(),
949 zs.as_ptr(),
950 count,
951 spec,
952 );
953 })
954 }
955
956 pub fn plot_quads_f64<S: AsRef<str>>(
958 &self,
959 label: S,
960 xs: &[f64],
961 ys: &[f64],
962 zs: &[f64],
963 flags: Quad3DFlags,
964 ) {
965 if xs.len() != ys.len() || ys.len() != zs.len() {
966 return;
967 }
968 let Some(count) = len_i32(xs.len()) else {
969 return;
970 };
971 let label = label.as_ref();
972 if label.contains('\0') {
973 return;
974 }
975 let stride_bytes = std::mem::size_of::<f64>() as i32;
976 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
977 let spec = plot3d_spec_from(flags.bits(), 0, stride_bytes);
978 sys::ImPlot3D_PlotQuad_doublePtr(
979 label_ptr,
980 xs.as_ptr(),
981 ys.as_ptr(),
982 zs.as_ptr(),
983 count,
984 spec,
985 );
986 })
987 }
988
989 pub fn plot_quads_f64_raw<S: AsRef<str>>(
990 &self,
991 label: S,
992 xs: &[f64],
993 ys: &[f64],
994 zs: &[f64],
995 flags: Quad3DFlags,
996 offset: i32,
997 stride: i32,
998 ) {
999 if xs.len() != ys.len() || ys.len() != zs.len() {
1000 return;
1001 }
1002 let Some(count) = len_i32(xs.len()) else {
1003 return;
1004 };
1005 let label = label.as_ref();
1006 if label.contains('\0') {
1007 return;
1008 }
1009 let stride_bytes = if stride == 0 {
1010 std::mem::size_of::<f64>() as i32
1011 } else {
1012 stride
1013 };
1014 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1015 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
1016 sys::ImPlot3D_PlotQuad_doublePtr(
1017 label_ptr,
1018 xs.as_ptr(),
1019 ys.as_ptr(),
1020 zs.as_ptr(),
1021 count,
1022 spec,
1023 );
1024 })
1025 }
1026}
1027
1028impl Drop for Plot3DToken {
1029 fn drop(&mut self) {
1030 unsafe {
1031 debug_end_plot();
1032 sys::ImPlot3D_EndPlot();
1033 }
1034 }
1035}
1036
1037pub struct Plot3DBuilder {
1039 title: String,
1040 size: Option<[f32; 2]>,
1041 flags: Plot3DFlags,
1042}
1043
1044impl Plot3DBuilder {
1045 pub fn size(mut self, size: [f32; 2]) -> Self {
1046 self.size = Some(size);
1047 self
1048 }
1049 pub fn flags(mut self, flags: Plot3DFlags) -> Self {
1050 self.flags = flags;
1051 self
1052 }
1053 pub fn build(self) -> Option<Plot3DToken> {
1054 if self.title.contains('\0') {
1055 return None;
1056 }
1057 let title = self.title;
1058 let size = self.size.unwrap_or([0.0, 0.0]);
1059 let ok = dear_imgui_rs::with_scratch_txt(&title, |title_ptr| unsafe {
1060 let style = sys::ImPlot3D_GetStyle();
1062 if !style.is_null() {
1063 let count = sys::ImPlot3D_GetColormapCount();
1064 if count > 0 && ((*style).Colormap < 0 || (*style).Colormap >= count) {
1065 (*style).Colormap = 0;
1066 }
1067 }
1068 sys::ImPlot3D_BeginPlot(
1069 title_ptr,
1070 imvec2(size[0], size[1]),
1071 self.flags.bits() as i32,
1072 )
1073 });
1074 if ok {
1075 debug_begin_plot();
1076 Some(Plot3DToken)
1077 } else {
1078 None
1079 }
1080 }
1081}
1082
1083#[cfg(feature = "mint")]
1110impl<'ui> Plot3DUi<'ui> {
1111 pub fn plot_line_mint<S: AsRef<str>>(
1115 &self,
1116 label: S,
1117 pts: &[mint::Point3<f32>],
1118 flags: Line3DFlags,
1119 ) {
1120 let mut xs = Vec::with_capacity(pts.len());
1121 let mut ys = Vec::with_capacity(pts.len());
1122 let mut zs = Vec::with_capacity(pts.len());
1123 for p in pts {
1124 xs.push(p.x);
1125 ys.push(p.y);
1126 zs.push(p.z);
1127 }
1128 self.plot_line_f32(label, &xs, &ys, &zs, flags);
1129 }
1130
1131 pub fn plot_scatter_mint<S: AsRef<str>>(
1133 &self,
1134 label: S,
1135 pts: &[mint::Point3<f32>],
1136 flags: Scatter3DFlags,
1137 ) {
1138 let mut xs = Vec::with_capacity(pts.len());
1139 let mut ys = Vec::with_capacity(pts.len());
1140 let mut zs = Vec::with_capacity(pts.len());
1141 for p in pts {
1142 xs.push(p.x);
1143 ys.push(p.y);
1144 zs.push(p.z);
1145 }
1146 self.plot_scatter_f32(label, &xs, &ys, &zs, flags);
1147 }
1148
1149 pub fn plot_text_mint(
1151 &self,
1152 text: &str,
1153 pos: mint::Point3<f32>,
1154 angle: f32,
1155 pix_offset: [f32; 2],
1156 ) {
1157 self.plot_text(text, pos.x, pos.y, pos.z, angle, pix_offset);
1158 }
1159
1160 pub fn plot_to_pixels_mint(&self, point: mint::Point3<f32>) -> [f32; 2] {
1162 self.plot_to_pixels([point.x, point.y, point.z])
1163 }
1164}
1165
1166pub struct Surface3DBuilder<'ui> {
1168 ui: &'ui Plot3DUi<'ui>,
1169 label: Cow<'ui, str>,
1170 xs: &'ui [f32],
1171 ys: &'ui [f32],
1172 zs: &'ui [f32],
1173 scale_min: f64,
1174 scale_max: f64,
1175 flags: Surface3DFlags,
1176}
1177
1178impl<'ui> Surface3DBuilder<'ui> {
1179 pub fn scale(mut self, min: f64, max: f64) -> Self {
1180 self.scale_min = min;
1181 self.scale_max = max;
1182 self
1183 }
1184 pub fn flags(mut self, flags: Surface3DFlags) -> Self {
1185 self.flags = flags;
1186 self
1187 }
1188 pub fn plot(self) {
1189 let x_count = match i32::try_from(self.xs.len()) {
1190 Ok(v) => v,
1191 Err(_) => return,
1192 };
1193 let y_count = match i32::try_from(self.ys.len()) {
1194 Ok(v) => v,
1195 Err(_) => return,
1196 };
1197 let expected = match self.xs.len().checked_mul(self.ys.len()) {
1198 Some(v) => v,
1199 None => return,
1200 };
1201 if self.zs.len() != expected {
1202 return;
1203 }
1204 let label = self.label.as_ref();
1205 let label = if label.contains('\0') {
1206 "surface"
1207 } else {
1208 label
1209 };
1210 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1211 let spec = plot3d_spec_from(self.flags.bits(), 0, std::mem::size_of::<f32>() as i32);
1212 sys::ImPlot3D_PlotSurface_FloatPtr(
1213 label_ptr,
1214 self.xs.as_ptr(),
1215 self.ys.as_ptr(),
1216 self.zs.as_ptr(),
1217 x_count,
1218 y_count,
1219 self.scale_min,
1220 self.scale_max,
1221 spec,
1222 );
1223 })
1224 }
1225}
1226
1227impl<'ui> Plot3DUi<'ui> {
1228 pub fn surface_f32(
1230 &'ui self,
1231 label: impl Into<Cow<'ui, str>>,
1232 xs: &'ui [f32],
1233 ys: &'ui [f32],
1234 zs: &'ui [f32],
1235 ) -> Surface3DBuilder<'ui> {
1236 Surface3DBuilder {
1237 ui: self,
1238 label: label.into(),
1239 xs,
1240 ys,
1241 zs,
1242 scale_min: f64::NAN,
1243 scale_max: f64::NAN,
1244 flags: Surface3DFlags::NONE,
1245 }
1246 }
1247
1248 pub fn surface_f32_raw<S: AsRef<str>>(
1250 &self,
1251 label: S,
1252 xs: &[f32],
1253 ys: &[f32],
1254 zs: &[f32],
1255 scale_min: f64,
1256 scale_max: f64,
1257 flags: Surface3DFlags,
1258 offset: i32,
1259 stride: i32,
1260 ) {
1261 debug_before_plot();
1262 let x_count = xs.len();
1263 let y_count = ys.len();
1264 let expected = match x_count.checked_mul(y_count) {
1265 Some(v) => v,
1266 None => return,
1267 };
1268 if zs.len() != expected {
1269 return;
1271 }
1272
1273 let mut xs_flat = Vec::with_capacity(expected);
1275 let mut ys_flat = Vec::with_capacity(expected);
1276 for yi in 0..y_count {
1277 for xi in 0..x_count {
1278 xs_flat.push(xs[xi]);
1279 ys_flat.push(ys[yi]);
1280 }
1281 }
1282
1283 let label = label.as_ref();
1284 if label.contains('\0') {
1285 return;
1286 }
1287 let stride_bytes = if stride == 0 {
1288 std::mem::size_of::<f32>() as i32
1289 } else {
1290 stride
1291 };
1292 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1293 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
1294 sys::ImPlot3D_PlotSurface_FloatPtr(
1295 label_ptr,
1296 xs_flat.as_ptr(),
1297 ys_flat.as_ptr(),
1298 zs.as_ptr(),
1299 x_count as i32,
1300 y_count as i32,
1301 scale_min,
1302 scale_max,
1303 spec,
1304 );
1305 })
1306 }
1307
1308 pub fn surface_f32_flat<S: AsRef<str>>(
1313 &self,
1314 label: S,
1315 xs_flat: &[f32],
1316 ys_flat: &[f32],
1317 zs: &[f32],
1318 x_count: i32,
1319 y_count: i32,
1320 scale_min: f64,
1321 scale_max: f64,
1322 flags: Surface3DFlags,
1323 offset: i32,
1324 stride: i32,
1325 ) {
1326 debug_before_plot();
1327 if x_count <= 0 || y_count <= 0 {
1328 return;
1329 }
1330 let expected = (x_count as usize).saturating_mul(y_count as usize);
1331 if xs_flat.len() != expected || ys_flat.len() != expected || zs.len() != expected {
1332 return;
1333 }
1334 let label = label.as_ref();
1335 if label.contains('\0') {
1336 return;
1337 }
1338 let stride_bytes = if stride == 0 {
1339 std::mem::size_of::<f32>() as i32
1340 } else {
1341 stride
1342 };
1343 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1344 let spec = plot3d_spec_from(flags.bits(), offset, stride_bytes);
1345 sys::ImPlot3D_PlotSurface_FloatPtr(
1346 label_ptr,
1347 xs_flat.as_ptr(),
1348 ys_flat.as_ptr(),
1349 zs.as_ptr(),
1350 x_count,
1351 y_count,
1352 scale_min,
1353 scale_max,
1354 spec,
1355 );
1356 })
1357 }
1358}
1359
1360pub struct Image3DByAxesBuilder<'ui> {
1362 _ui: &'ui Plot3DUi<'ui>,
1363 label: Cow<'ui, str>,
1364 tex_ref: sys::ImTextureRef_c,
1365 center: [f32; 3],
1366 axis_u: [f32; 3],
1367 axis_v: [f32; 3],
1368 uv0: [f32; 2],
1369 uv1: [f32; 2],
1370 tint: [f32; 4],
1371 flags: Image3DFlags,
1372}
1373
1374impl<'ui> Image3DByAxesBuilder<'ui> {
1375 pub fn uv(mut self, uv0: [f32; 2], uv1: [f32; 2]) -> Self {
1376 self.uv0 = uv0;
1377 self.uv1 = uv1;
1378 self
1379 }
1380 pub fn tint(mut self, col: [f32; 4]) -> Self {
1381 self.tint = col;
1382 self
1383 }
1384 pub fn flags(mut self, flags: Image3DFlags) -> Self {
1385 self.flags = flags;
1386 self
1387 }
1388 pub fn plot(self) {
1389 let label = self.label.as_ref();
1390 let label = if label.contains('\0') { "image" } else { label };
1391 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1392 debug_before_plot();
1393 let spec = plot3d_spec_from(self.flags.bits(), 0, IMPLOT3D_AUTO);
1394 sys::ImPlot3D_PlotImage_Vec2(
1395 label_ptr,
1396 self.tex_ref,
1397 sys::ImPlot3DPoint_c {
1398 x: self.center[0] as f64,
1399 y: self.center[1] as f64,
1400 z: self.center[2] as f64,
1401 },
1402 sys::ImPlot3DPoint_c {
1403 x: self.axis_u[0] as f64,
1404 y: self.axis_u[1] as f64,
1405 z: self.axis_u[2] as f64,
1406 },
1407 sys::ImPlot3DPoint_c {
1408 x: self.axis_v[0] as f64,
1409 y: self.axis_v[1] as f64,
1410 z: self.axis_v[2] as f64,
1411 },
1412 imvec2(self.uv0[0], self.uv0[1]),
1413 imvec2(self.uv1[0], self.uv1[1]),
1414 imvec4(self.tint[0], self.tint[1], self.tint[2], self.tint[3]),
1415 spec,
1416 );
1417 })
1418 }
1419}
1420
1421pub struct Image3DByCornersBuilder<'ui> {
1423 _ui: &'ui Plot3DUi<'ui>,
1424 label: Cow<'ui, str>,
1425 tex_ref: sys::ImTextureRef_c,
1426 p0: [f32; 3],
1427 p1: [f32; 3],
1428 p2: [f32; 3],
1429 p3: [f32; 3],
1430 uv0: [f32; 2],
1431 uv1: [f32; 2],
1432 uv2: [f32; 2],
1433 uv3: [f32; 2],
1434 tint: [f32; 4],
1435 flags: Image3DFlags,
1436}
1437
1438impl<'ui> Image3DByCornersBuilder<'ui> {
1439 pub fn uvs(mut self, uv0: [f32; 2], uv1: [f32; 2], uv2: [f32; 2], uv3: [f32; 2]) -> Self {
1440 self.uv0 = uv0;
1441 self.uv1 = uv1;
1442 self.uv2 = uv2;
1443 self.uv3 = uv3;
1444 self
1445 }
1446 pub fn tint(mut self, col: [f32; 4]) -> Self {
1447 self.tint = col;
1448 self
1449 }
1450 pub fn flags(mut self, flags: Image3DFlags) -> Self {
1451 self.flags = flags;
1452 self
1453 }
1454 pub fn plot(self) {
1455 let label = self.label.as_ref();
1456 let label = if label.contains('\0') { "image" } else { label };
1457 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1458 debug_before_plot();
1459 let spec = plot3d_spec_from(self.flags.bits(), 0, IMPLOT3D_AUTO);
1460 sys::ImPlot3D_PlotImage_Plot3DPoint(
1461 label_ptr,
1462 self.tex_ref,
1463 sys::ImPlot3DPoint_c {
1464 x: self.p0[0] as f64,
1465 y: self.p0[1] as f64,
1466 z: self.p0[2] as f64,
1467 },
1468 sys::ImPlot3DPoint_c {
1469 x: self.p1[0] as f64,
1470 y: self.p1[1] as f64,
1471 z: self.p1[2] as f64,
1472 },
1473 sys::ImPlot3DPoint_c {
1474 x: self.p2[0] as f64,
1475 y: self.p2[1] as f64,
1476 z: self.p2[2] as f64,
1477 },
1478 sys::ImPlot3DPoint_c {
1479 x: self.p3[0] as f64,
1480 y: self.p3[1] as f64,
1481 z: self.p3[2] as f64,
1482 },
1483 imvec2(self.uv0[0], self.uv0[1]),
1484 imvec2(self.uv1[0], self.uv1[1]),
1485 imvec2(self.uv2[0], self.uv2[1]),
1486 imvec2(self.uv3[0], self.uv3[1]),
1487 imvec4(self.tint[0], self.tint[1], self.tint[2], self.tint[3]),
1488 spec,
1489 );
1490 })
1491 }
1492}
1493
1494impl<'ui> Plot3DUi<'ui> {
1495 pub fn image_by_axes<T: Into<TextureRef>>(
1497 &'ui self,
1498 label: impl Into<Cow<'ui, str>>,
1499 tex: T,
1500 center: [f32; 3],
1501 axis_u: [f32; 3],
1502 axis_v: [f32; 3],
1503 ) -> Image3DByAxesBuilder<'ui> {
1504 let tr = tex.into().raw();
1505 let tex_ref = sys::ImTextureRef_c {
1506 _TexData: tr._TexData as *mut sys::ImTextureData,
1507 _TexID: tr._TexID as sys::ImTextureID,
1508 };
1509 debug_before_plot();
1510 Image3DByAxesBuilder {
1511 _ui: self,
1512 label: label.into(),
1513 tex_ref,
1514 center,
1515 axis_u,
1516 axis_v,
1517 uv0: [0.0, 0.0],
1518 uv1: [1.0, 1.0],
1519 tint: [1.0, 1.0, 1.0, 1.0],
1520 flags: Image3DFlags::NONE,
1521 }
1522 }
1523
1524 pub fn image_by_corners<T: Into<TextureRef>>(
1526 &'ui self,
1527 label: impl Into<Cow<'ui, str>>,
1528 tex: T,
1529 p0: [f32; 3],
1530 p1: [f32; 3],
1531 p2: [f32; 3],
1532 p3: [f32; 3],
1533 ) -> Image3DByCornersBuilder<'ui> {
1534 let tr = tex.into().raw();
1535 let tex_ref = sys::ImTextureRef_c {
1536 _TexData: tr._TexData as *mut sys::ImTextureData,
1537 _TexID: tr._TexID as sys::ImTextureID,
1538 };
1539 debug_before_plot();
1540 Image3DByCornersBuilder {
1541 _ui: self,
1542 label: label.into(),
1543 tex_ref,
1544 p0,
1545 p1,
1546 p2,
1547 p3,
1548 uv0: [0.0, 0.0],
1549 uv1: [1.0, 0.0],
1550 uv2: [1.0, 1.0],
1551 uv3: [0.0, 1.0],
1552 tint: [1.0, 1.0, 1.0, 1.0],
1553 flags: Image3DFlags::NONE,
1554 }
1555 }
1556}
1557
1558impl<'ui> Plot3DUi<'ui> {
1560 pub fn setup_axes(
1561 &self,
1562 x_label: &str,
1563 y_label: &str,
1564 z_label: &str,
1565 x_flags: Axis3DFlags,
1566 y_flags: Axis3DFlags,
1567 z_flags: Axis3DFlags,
1568 ) {
1569 debug_before_setup();
1570 if x_label.contains('\0') || y_label.contains('\0') || z_label.contains('\0') {
1571 return;
1572 }
1573 dear_imgui_rs::with_scratch_txt_three(
1574 x_label,
1575 y_label,
1576 z_label,
1577 |x_ptr, y_ptr, z_ptr| unsafe {
1578 sys::ImPlot3D_SetupAxes(
1579 x_ptr,
1580 y_ptr,
1581 z_ptr,
1582 x_flags.bits() as i32,
1583 y_flags.bits() as i32,
1584 z_flags.bits() as i32,
1585 )
1586 },
1587 )
1588 }
1589
1590 pub fn setup_axis(&self, axis: Axis3D, label: &str, flags: Axis3DFlags) {
1591 debug_before_setup();
1592 if label.contains('\0') {
1593 return;
1594 }
1595 dear_imgui_rs::with_scratch_txt(label, |ptr| unsafe {
1596 sys::ImPlot3D_SetupAxis(axis as i32, ptr, flags.bits() as i32)
1597 })
1598 }
1599
1600 pub fn setup_axis_limits(&self, axis: Axis3D, min: f64, max: f64, cond: Plot3DCond) {
1601 debug_before_setup();
1602 unsafe { sys::ImPlot3D_SetupAxisLimits(axis as i32, min, max, cond as i32) }
1603 }
1604
1605 pub fn setup_axes_limits(
1606 &self,
1607 x_min: f64,
1608 x_max: f64,
1609 y_min: f64,
1610 y_max: f64,
1611 z_min: f64,
1612 z_max: f64,
1613 cond: Plot3DCond,
1614 ) {
1615 debug_before_setup();
1616 unsafe {
1617 sys::ImPlot3D_SetupAxesLimits(x_min, x_max, y_min, y_max, z_min, z_max, cond as i32)
1618 }
1619 }
1620
1621 pub fn setup_axis_limits_constraints(&self, axis: Axis3D, v_min: f64, v_max: f64) {
1622 debug_before_setup();
1623 unsafe { sys::ImPlot3D_SetupAxisLimitsConstraints(axis as i32, v_min, v_max) }
1624 }
1625
1626 pub fn setup_axis_zoom_constraints(&self, axis: Axis3D, z_min: f64, z_max: f64) {
1627 debug_before_setup();
1628 unsafe { sys::ImPlot3D_SetupAxisZoomConstraints(axis as i32, z_min, z_max) }
1629 }
1630
1631 pub fn setup_axis_ticks_values(
1635 &self,
1636 axis: Axis3D,
1637 values: &[f64],
1638 labels: Option<&[&str]>,
1639 keep_default: bool,
1640 ) {
1641 debug_before_setup();
1642 let Some(n_ticks) = len_i32(values.len()) else {
1643 return;
1644 };
1645 if let Some(lbls) = labels {
1646 if lbls.len() != values.len() {
1647 return;
1648 }
1649 let cleaned: Vec<&str> = lbls
1650 .iter()
1651 .map(|&s| if s.contains('\0') { "" } else { s })
1652 .collect();
1653 dear_imgui_rs::with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
1654 sys::ImPlot3D_SetupAxisTicks_doublePtr(
1655 axis as i32,
1656 values.as_ptr(),
1657 n_ticks,
1658 ptrs.as_ptr(),
1659 keep_default,
1660 )
1661 });
1662 } else {
1663 unsafe {
1664 sys::ImPlot3D_SetupAxisTicks_doublePtr(
1665 axis as i32,
1666 values.as_ptr(),
1667 n_ticks,
1668 std::ptr::null(),
1669 keep_default,
1670 )
1671 };
1672 }
1673 }
1674
1675 pub fn setup_axis_ticks_range(
1676 &self,
1677 axis: Axis3D,
1678 v_min: f64,
1679 v_max: f64,
1680 n_ticks: i32,
1681 labels: Option<&[&str]>,
1682 keep_default: bool,
1683 ) {
1684 debug_before_setup();
1685 if let Some(lbls) = labels {
1686 let cleaned: Vec<&str> = lbls
1687 .iter()
1688 .map(|&s| if s.contains('\0') { "" } else { s })
1689 .collect();
1690 dear_imgui_rs::with_scratch_txt_slice(&cleaned, |ptrs| unsafe {
1691 sys::ImPlot3D_SetupAxisTicks_double(
1692 axis as i32,
1693 v_min,
1694 v_max,
1695 n_ticks,
1696 ptrs.as_ptr(),
1697 keep_default,
1698 )
1699 });
1700 } else {
1701 unsafe {
1702 sys::ImPlot3D_SetupAxisTicks_double(
1703 axis as i32,
1704 v_min,
1705 v_max,
1706 n_ticks,
1707 std::ptr::null(),
1708 keep_default,
1709 )
1710 };
1711 }
1712 }
1713
1714 pub fn setup_box_scale(&self, x: f32, y: f32, z: f32) {
1715 debug_before_setup();
1716 unsafe { sys::ImPlot3D_SetupBoxScale(x as f64, y as f64, z as f64) }
1717 }
1718
1719 pub fn setup_box_rotation(
1720 &self,
1721 elevation: f32,
1722 azimuth: f32,
1723 animate: bool,
1724 cond: Plot3DCond,
1725 ) {
1726 debug_before_setup();
1727 unsafe {
1728 sys::ImPlot3D_SetupBoxRotation_double(
1729 elevation as f64,
1730 azimuth as f64,
1731 animate,
1732 cond as i32,
1733 )
1734 }
1735 }
1736
1737 pub fn setup_box_initial_rotation(&self, elevation: f32, azimuth: f32) {
1738 debug_before_setup();
1739 unsafe { sys::ImPlot3D_SetupBoxInitialRotation_double(elevation as f64, azimuth as f64) }
1740 }
1741
1742 pub fn plot_text(&self, text: &str, x: f32, y: f32, z: f32, angle: f32, pix_offset: [f32; 2]) {
1743 if text.contains('\0') {
1744 return;
1745 }
1746 dear_imgui_rs::with_scratch_txt(text, |text_ptr| unsafe {
1747 debug_before_plot();
1748 sys::ImPlot3D_PlotText(
1749 text_ptr,
1750 x as f64,
1751 y as f64,
1752 z as f64,
1753 angle as f64,
1754 imvec2(pix_offset[0], pix_offset[1]),
1755 )
1756 })
1757 }
1758
1759 pub fn plot_to_pixels(&self, point: [f32; 3]) -> [f32; 2] {
1760 unsafe {
1761 let out = compat_ffi::ImPlot3D_PlotToPixels_double(
1762 point[0] as f64,
1763 point[1] as f64,
1764 point[2] as f64,
1765 );
1766 [out.x, out.y]
1767 }
1768 }
1769
1770 pub fn get_plot_draw_list(&self) -> *mut sys::ImDrawList {
1771 unsafe { sys::ImPlot3D_GetPlotDrawList() }
1772 }
1773
1774 pub fn get_frame_pos(&self) -> [f32; 2] {
1775 unsafe {
1776 let out = compat_ffi::ImPlot3D_GetPlotRectPos();
1777 [out.x, out.y]
1778 }
1779 }
1780
1781 pub fn get_frame_size(&self) -> [f32; 2] {
1782 unsafe {
1783 let out = compat_ffi::ImPlot3D_GetPlotRectSize();
1784 [out.x, out.y]
1785 }
1786 }
1787}
1788
1789pub struct Mesh3DBuilder<'ui> {
1791 _ui: &'ui Plot3DUi<'ui>,
1792 label: Cow<'ui, str>,
1793 vertices: &'ui [[f32; 3]],
1794 indices: &'ui [u32],
1795 flags: Mesh3DFlags,
1796}
1797
1798impl<'ui> Mesh3DBuilder<'ui> {
1799 pub fn flags(mut self, flags: Mesh3DFlags) -> Self {
1800 self.flags = flags;
1801 self
1802 }
1803 pub fn plot(self) {
1804 let Some(vtx_count) = len_i32(self.vertices.len()) else {
1805 return;
1806 };
1807 let Some(idx_count) = len_i32(self.indices.len()) else {
1808 return;
1809 };
1810 let vertices: Vec<sys::ImPlot3DPoint> = self
1813 .vertices
1814 .iter()
1815 .map(|v| {
1816 let [x, y, z] = *v;
1817 sys::ImPlot3DPoint_c {
1818 x: x as f64,
1819 y: y as f64,
1820 z: z as f64,
1821 }
1822 })
1823 .collect();
1824
1825 let label = self.label.as_ref();
1826 let label = if label.contains('\0') { "mesh" } else { label };
1827 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
1828 debug_before_plot();
1829 let spec = plot3d_spec_from(self.flags.bits(), 0, IMPLOT3D_AUTO);
1830 sys::ImPlot3D_PlotMesh(
1831 label_ptr,
1832 vertices.as_ptr(),
1833 self.indices.as_ptr(),
1834 vtx_count,
1835 idx_count,
1836 spec,
1837 );
1838 })
1839 }
1840}
1841
1842impl<'ui> Plot3DUi<'ui> {
1843 pub fn mesh(
1845 &'ui self,
1846 label: impl Into<Cow<'ui, str>>,
1847 vertices: &'ui [[f32; 3]],
1848 indices: &'ui [u32],
1849 ) -> Mesh3DBuilder<'ui> {
1850 Mesh3DBuilder {
1851 _ui: self,
1852 label: label.into(),
1853 vertices,
1854 indices,
1855 flags: Mesh3DFlags::NONE,
1856 }
1857 }
1858}
1859
1860#[cfg(test)]
1861mod tests {
1862 use super::sys;
1863 use std::mem::{align_of, size_of};
1864
1865 #[test]
1866 fn ffi_layout_implot3d_point_is_3_f64() {
1867 assert_eq!(size_of::<sys::ImPlot3DPoint>(), 3 * size_of::<f64>());
1868 assert_eq!(align_of::<sys::ImPlot3DPoint>(), align_of::<f64>());
1869 }
1870}