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