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
56trait ImVec2Ctor {
57 fn from_xy(x: f32, y: f32) -> Self;
58}
59
60impl ImVec2Ctor for sys::ImVec2_c {
61 fn from_xy(x: f32, y: f32) -> Self {
62 Self { x, y }
63 }
64}
65
66impl ImVec2Ctor for imgui_sys::ImVec2_c {
67 fn from_xy(x: f32, y: f32) -> Self {
68 Self { x, y }
69 }
70}
71
72#[inline]
73fn imvec2<T: ImVec2Ctor>(x: f32, y: f32) -> T {
74 T::from_xy(x, y)
75}
76
77trait ImVec4Ctor {
78 fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self;
79}
80
81impl ImVec4Ctor for sys::ImVec4_c {
82 fn from_xyzw(x: f32, y: f32, z: f32, w: f32) -> Self {
83 Self { x, y, z, w }
84 }
85}
86
87impl ImVec4Ctor for imgui_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
93#[inline]
94fn imvec4<T: ImVec4Ctor>(x: f32, y: f32, z: f32, w: f32) -> T {
95 T::from_xyzw(x, y, z, w)
96}
97
98#[allow(non_snake_case)]
99mod compat_ffi {
100 use super::{imgui_sys, sys};
101
102 unsafe extern "C" {
103 pub fn ImPlot3D_PlotToPixels_double(x: f64, y: f64, z: f64) -> imgui_sys::ImVec2_c;
104 pub fn ImPlot3D_GetPlotRectPos() -> imgui_sys::ImVec2_c;
105 pub fn ImPlot3D_GetPlotRectSize() -> imgui_sys::ImVec2_c;
106 pub fn ImPlot3D_NextColormapColor() -> imgui_sys::ImVec4_c;
107 pub fn ImPlot3D_GetColormapColor(
108 idx: ::std::os::raw::c_int,
109 cmap: sys::ImPlot3DColormap,
110 ) -> imgui_sys::ImVec4_c;
111 }
112}
113
114#[cfg(debug_assertions)]
116thread_local! {
117 static DEBUG_PLOT_STATE: PlotDebugState = PlotDebugState { in_plot: std::cell::Cell::new(false), setup_locked: std::cell::Cell::new(false) };
118}
119
120#[cfg(debug_assertions)]
121struct PlotDebugState {
122 in_plot: std::cell::Cell<bool>,
123 setup_locked: std::cell::Cell<bool>,
124}
125
126#[cfg(debug_assertions)]
127#[inline]
128fn debug_begin_plot() {
129 DEBUG_PLOT_STATE.with(|s| {
130 s.in_plot.set(true);
131 s.setup_locked.set(false);
132 });
133}
134
135#[cfg(debug_assertions)]
136#[inline]
137fn debug_end_plot() {
138 DEBUG_PLOT_STATE.with(|s| {
139 s.in_plot.set(false);
140 s.setup_locked.set(false);
141 });
142}
143
144#[cfg(debug_assertions)]
145#[inline]
146fn debug_before_setup() {
147 DEBUG_PLOT_STATE.with(|s| {
148 debug_assert!(
149 s.in_plot.get(),
150 "Setup* called outside of BeginPlot/EndPlot"
151 );
152 debug_assert!(
153 !s.setup_locked.get(),
154 "Setup* must be called before any plotting (PlotX) or locking operations"
155 );
156 });
157}
158
159#[cfg(debug_assertions)]
160#[inline]
161fn debug_before_plot() {
162 DEBUG_PLOT_STATE.with(|s| {
163 debug_assert!(s.in_plot.get(), "Plot* called outside of BeginPlot/EndPlot");
164 s.setup_locked.set(true);
165 });
166}
167
168#[cfg(not(debug_assertions))]
169#[inline]
170fn debug_begin_plot() {}
171#[cfg(not(debug_assertions))]
172#[inline]
173fn debug_end_plot() {}
174#[cfg(not(debug_assertions))]
175#[inline]
176fn debug_before_setup() {}
177#[cfg(not(debug_assertions))]
178#[inline]
179fn debug_before_plot() {}
180
181pub fn show_all_demos() {
186 unsafe { sys::ImPlot3D_ShowAllDemos() }
187}
188
189pub fn show_demo_window() {
203 unsafe { sys::ImPlot3D_ShowDemoWindow(std::ptr::null_mut()) }
204}
205
206pub fn show_demo_window_with_flag(p_open: &mut bool) {
208 unsafe { sys::ImPlot3D_ShowDemoWindow(p_open as *mut bool) }
209}
210
211pub fn show_style_editor() {
216 unsafe { sys::ImPlot3D_ShowStyleEditor(std::ptr::null_mut()) }
217}
218
219pub fn show_metrics_window() {
224 unsafe { sys::ImPlot3D_ShowMetricsWindow(std::ptr::null_mut()) }
225}
226
227pub fn show_metrics_window_with_flag(p_open: &mut bool) {
229 unsafe { sys::ImPlot3D_ShowMetricsWindow(p_open as *mut bool) }
230}
231
232pub struct Plot3DContext {
251 owned: bool,
252}
253
254impl Plot3DContext {
255 pub fn create(_imgui: &Context) -> Self {
259 unsafe {
260 let ctx = sys::ImPlot3D_CreateContext();
261 sys::ImPlot3D_SetCurrentContext(ctx);
263 }
264 Self { owned: true }
265 }
266
267 pub fn raw_style_mut() -> *mut sys::ImPlot3DStyle {
272 unsafe { sys::ImPlot3D_GetStyle() }
273 }
274
275 pub fn get_plot_ui<'ui>(&self, ui: &'ui Ui) -> Plot3DUi<'ui> {
280 Plot3DUi { _ui: ui }
281 }
282}
283
284impl Drop for Plot3DContext {
285 fn drop(&mut self) {
286 if self.owned {
287 unsafe {
288 sys::ImPlot3D_DestroyContext(std::ptr::null_mut());
289 }
290 }
291 }
292}
293
294pub struct Plot3DUi<'ui> {
315 _ui: &'ui Ui,
316}
317
318pub struct Plot3DToken;
323
324impl<'ui> Plot3DUi<'ui> {
325 pub fn begin_plot<S: AsRef<str>>(&self, title: S) -> Plot3DBuilder {
345 Plot3DBuilder {
346 title: title.as_ref().into(),
347 size: None,
348 flags: Plot3DFlags::empty(),
349 }
350 }
351
352 pub fn plot_line_f32<S: AsRef<str>>(
377 &self,
378 label: S,
379 xs: &[f32],
380 ys: &[f32],
381 zs: &[f32],
382 flags: Line3DFlags,
383 ) {
384 if xs.len() != ys.len() || ys.len() != zs.len() {
385 return;
386 }
387 let label_c = match std::ffi::CString::new(label.as_ref()) {
388 Ok(s) => s,
389 Err(_) => return,
390 };
391 let stride_bytes = std::mem::size_of::<f32>() as i32;
392 unsafe {
393 sys::ImPlot3D_PlotLine_FloatPtr(
394 label_c.as_ptr(),
395 xs.as_ptr(),
396 ys.as_ptr(),
397 zs.as_ptr(),
398 xs.len() as i32,
399 flags.bits() as i32,
400 0,
401 stride_bytes,
402 );
403 }
404 }
405
406 pub fn plot_line_f32_raw<S: AsRef<str>>(
408 &self,
409 label: S,
410 xs: &[f32],
411 ys: &[f32],
412 zs: &[f32],
413 flags: Line3DFlags,
414 offset: i32,
415 stride: i32,
416 ) {
417 if xs.len() != ys.len() || ys.len() != zs.len() {
418 return;
419 }
420 let label_c = match std::ffi::CString::new(label.as_ref()) {
421 Ok(s) => s,
422 Err(_) => return,
423 };
424 let stride_bytes = if stride == 0 {
425 std::mem::size_of::<f32>() as i32
426 } else {
427 stride
428 };
429 unsafe {
430 sys::ImPlot3D_PlotLine_FloatPtr(
431 label_c.as_ptr(),
432 xs.as_ptr(),
433 ys.as_ptr(),
434 zs.as_ptr(),
435 xs.len() as i32,
436 flags.bits() as i32,
437 offset,
438 stride_bytes,
439 );
440 }
441 }
442
443 pub fn plot_line_f64<S: AsRef<str>>(
445 &self,
446 label: S,
447 xs: &[f64],
448 ys: &[f64],
449 zs: &[f64],
450 flags: Line3DFlags,
451 ) {
452 if xs.len() != ys.len() || ys.len() != zs.len() {
453 return;
454 }
455 let label_c = match std::ffi::CString::new(label.as_ref()) {
456 Ok(s) => s,
457 Err(_) => return,
458 };
459 let stride_bytes = std::mem::size_of::<f64>() as i32;
460 unsafe {
461 sys::ImPlot3D_PlotLine_doublePtr(
462 label_c.as_ptr(),
463 xs.as_ptr(),
464 ys.as_ptr(),
465 zs.as_ptr(),
466 xs.len() as i32,
467 flags.bits() as i32,
468 0,
469 stride_bytes,
470 );
471 }
472 }
473
474 pub fn plot_line_f64_raw<S: AsRef<str>>(
476 &self,
477 label: S,
478 xs: &[f64],
479 ys: &[f64],
480 zs: &[f64],
481 flags: Line3DFlags,
482 offset: i32,
483 stride: i32,
484 ) {
485 if xs.len() != ys.len() || ys.len() != zs.len() {
486 return;
487 }
488 let label_c = match std::ffi::CString::new(label.as_ref()) {
489 Ok(s) => s,
490 Err(_) => return,
491 };
492 let stride_bytes = if stride == 0 {
493 std::mem::size_of::<f64>() as i32
494 } else {
495 stride
496 };
497 unsafe {
498 sys::ImPlot3D_PlotLine_doublePtr(
499 label_c.as_ptr(),
500 xs.as_ptr(),
501 ys.as_ptr(),
502 zs.as_ptr(),
503 xs.len() as i32,
504 flags.bits() as i32,
505 offset,
506 stride_bytes,
507 );
508 }
509 }
510
511 pub fn plot_scatter_f32<S: AsRef<str>>(
513 &self,
514 label: S,
515 xs: &[f32],
516 ys: &[f32],
517 zs: &[f32],
518 flags: Scatter3DFlags,
519 ) {
520 if xs.len() != ys.len() || ys.len() != zs.len() {
521 return;
522 }
523 let label_c = match std::ffi::CString::new(label.as_ref()) {
524 Ok(s) => s,
525 Err(_) => return,
526 };
527 let stride_bytes = std::mem::size_of::<f32>() as i32;
528 unsafe {
529 sys::ImPlot3D_PlotScatter_FloatPtr(
530 label_c.as_ptr(),
531 xs.as_ptr(),
532 ys.as_ptr(),
533 zs.as_ptr(),
534 xs.len() as i32,
535 flags.bits() as i32,
536 0,
537 stride_bytes,
538 );
539 }
540 }
541
542 pub fn plot_scatter_f32_raw<S: AsRef<str>>(
544 &self,
545 label: S,
546 xs: &[f32],
547 ys: &[f32],
548 zs: &[f32],
549 flags: Scatter3DFlags,
550 offset: i32,
551 stride: i32,
552 ) {
553 if xs.len() != ys.len() || ys.len() != zs.len() {
554 return;
555 }
556 let label_c = match std::ffi::CString::new(label.as_ref()) {
557 Ok(s) => s,
558 Err(_) => return,
559 };
560 let stride_bytes = if stride == 0 {
561 std::mem::size_of::<f32>() as i32
562 } else {
563 stride
564 };
565 unsafe {
566 sys::ImPlot3D_PlotScatter_FloatPtr(
567 label_c.as_ptr(),
568 xs.as_ptr(),
569 ys.as_ptr(),
570 zs.as_ptr(),
571 xs.len() as i32,
572 flags.bits() as i32,
573 offset,
574 stride_bytes,
575 );
576 }
577 }
578
579 pub fn plot_scatter_f64<S: AsRef<str>>(
581 &self,
582 label: S,
583 xs: &[f64],
584 ys: &[f64],
585 zs: &[f64],
586 flags: Scatter3DFlags,
587 ) {
588 if xs.len() != ys.len() || ys.len() != zs.len() {
589 return;
590 }
591 let label_c = match std::ffi::CString::new(label.as_ref()) {
592 Ok(s) => s,
593 Err(_) => return,
594 };
595 let stride_bytes = std::mem::size_of::<f64>() as i32;
596 unsafe {
597 sys::ImPlot3D_PlotScatter_doublePtr(
598 label_c.as_ptr(),
599 xs.as_ptr(),
600 ys.as_ptr(),
601 zs.as_ptr(),
602 xs.len() as i32,
603 flags.bits() as i32,
604 0,
605 stride_bytes,
606 );
607 }
608 }
609
610 pub fn plot_scatter_f64_raw<S: AsRef<str>>(
612 &self,
613 label: S,
614 xs: &[f64],
615 ys: &[f64],
616 zs: &[f64],
617 flags: Scatter3DFlags,
618 offset: i32,
619 stride: i32,
620 ) {
621 if xs.len() != ys.len() || ys.len() != zs.len() {
622 return;
623 }
624 let label_c = match std::ffi::CString::new(label.as_ref()) {
625 Ok(s) => s,
626 Err(_) => return,
627 };
628 let stride_bytes = if stride == 0 {
629 std::mem::size_of::<f64>() as i32
630 } else {
631 stride
632 };
633 unsafe {
634 sys::ImPlot3D_PlotScatter_doublePtr(
635 label_c.as_ptr(),
636 xs.as_ptr(),
637 ys.as_ptr(),
638 zs.as_ptr(),
639 xs.len() as i32,
640 flags.bits() as i32,
641 offset,
642 stride_bytes,
643 );
644 }
645 }
646
647 pub fn plot_triangles_f32<S: AsRef<str>>(
649 &self,
650 label: S,
651 xs: &[f32],
652 ys: &[f32],
653 zs: &[f32],
654 flags: Triangle3DFlags,
655 ) {
656 if xs.len() != ys.len() || ys.len() != zs.len() {
657 return;
658 }
659 let label_c = match std::ffi::CString::new(label.as_ref()) {
660 Ok(s) => s,
661 Err(_) => return,
662 };
663 let stride_bytes = std::mem::size_of::<f32>() as i32;
664 unsafe {
665 sys::ImPlot3D_PlotTriangle_FloatPtr(
666 label_c.as_ptr(),
667 xs.as_ptr(),
668 ys.as_ptr(),
669 zs.as_ptr(),
670 xs.len() as i32,
671 flags.bits() as i32,
672 0,
673 stride_bytes,
674 );
675 }
676 }
677
678 pub fn plot_triangles_f32_raw<S: AsRef<str>>(
679 &self,
680 label: S,
681 xs: &[f32],
682 ys: &[f32],
683 zs: &[f32],
684 flags: Triangle3DFlags,
685 offset: i32,
686 stride: i32,
687 ) {
688 if xs.len() != ys.len() || ys.len() != zs.len() {
689 return;
690 }
691 let label_c = match std::ffi::CString::new(label.as_ref()) {
692 Ok(s) => s,
693 Err(_) => return,
694 };
695 let stride_bytes = if stride == 0 {
696 std::mem::size_of::<f32>() as i32
697 } else {
698 stride
699 };
700 unsafe {
701 sys::ImPlot3D_PlotTriangle_FloatPtr(
702 label_c.as_ptr(),
703 xs.as_ptr(),
704 ys.as_ptr(),
705 zs.as_ptr(),
706 xs.len() as i32,
707 flags.bits() as i32,
708 offset,
709 stride_bytes,
710 );
711 }
712 }
713
714 pub fn plot_quads_f32<S: AsRef<str>>(
716 &self,
717 label: S,
718 xs: &[f32],
719 ys: &[f32],
720 zs: &[f32],
721 flags: Quad3DFlags,
722 ) {
723 if xs.len() != ys.len() || ys.len() != zs.len() {
724 return;
725 }
726 let label_c = match std::ffi::CString::new(label.as_ref()) {
727 Ok(s) => s,
728 Err(_) => return,
729 };
730 let stride_bytes = std::mem::size_of::<f32>() as i32;
731 unsafe {
732 sys::ImPlot3D_PlotQuad_FloatPtr(
733 label_c.as_ptr(),
734 xs.as_ptr(),
735 ys.as_ptr(),
736 zs.as_ptr(),
737 xs.len() as i32,
738 flags.bits() as i32,
739 0,
740 stride_bytes,
741 );
742 }
743 }
744
745 pub fn plot_quads_f32_raw<S: AsRef<str>>(
746 &self,
747 label: S,
748 xs: &[f32],
749 ys: &[f32],
750 zs: &[f32],
751 flags: Quad3DFlags,
752 offset: i32,
753 stride: i32,
754 ) {
755 if xs.len() != ys.len() || ys.len() != zs.len() {
756 return;
757 }
758 let label_c = match std::ffi::CString::new(label.as_ref()) {
759 Ok(s) => s,
760 Err(_) => return,
761 };
762 let stride_bytes = if stride == 0 {
763 std::mem::size_of::<f32>() as i32
764 } else {
765 stride
766 };
767 unsafe {
768 sys::ImPlot3D_PlotQuad_FloatPtr(
769 label_c.as_ptr(),
770 xs.as_ptr(),
771 ys.as_ptr(),
772 zs.as_ptr(),
773 xs.len() as i32,
774 flags.bits() as i32,
775 offset,
776 stride_bytes,
777 );
778 }
779 }
780
781 pub fn plot_triangles_f64<S: AsRef<str>>(
783 &self,
784 label: S,
785 xs: &[f64],
786 ys: &[f64],
787 zs: &[f64],
788 flags: Triangle3DFlags,
789 ) {
790 if xs.len() != ys.len() || ys.len() != zs.len() {
791 return;
792 }
793 let label_c = match std::ffi::CString::new(label.as_ref()) {
794 Ok(s) => s,
795 Err(_) => return,
796 };
797 let stride_bytes = std::mem::size_of::<f64>() as i32;
798 unsafe {
799 sys::ImPlot3D_PlotTriangle_doublePtr(
800 label_c.as_ptr(),
801 xs.as_ptr(),
802 ys.as_ptr(),
803 zs.as_ptr(),
804 xs.len() as i32,
805 flags.bits() as i32,
806 0,
807 stride_bytes,
808 );
809 }
810 }
811
812 pub fn plot_triangles_f64_raw<S: AsRef<str>>(
813 &self,
814 label: S,
815 xs: &[f64],
816 ys: &[f64],
817 zs: &[f64],
818 flags: Triangle3DFlags,
819 offset: i32,
820 stride: i32,
821 ) {
822 if xs.len() != ys.len() || ys.len() != zs.len() {
823 return;
824 }
825 let label_c = match std::ffi::CString::new(label.as_ref()) {
826 Ok(s) => s,
827 Err(_) => return,
828 };
829 let stride_bytes = if stride == 0 {
830 std::mem::size_of::<f64>() as i32
831 } else {
832 stride
833 };
834 unsafe {
835 sys::ImPlot3D_PlotTriangle_doublePtr(
836 label_c.as_ptr(),
837 xs.as_ptr(),
838 ys.as_ptr(),
839 zs.as_ptr(),
840 xs.len() as i32,
841 flags.bits() as i32,
842 offset,
843 stride_bytes,
844 );
845 }
846 }
847
848 pub fn plot_quads_f64<S: AsRef<str>>(
850 &self,
851 label: S,
852 xs: &[f64],
853 ys: &[f64],
854 zs: &[f64],
855 flags: Quad3DFlags,
856 ) {
857 if xs.len() != ys.len() || ys.len() != zs.len() {
858 return;
859 }
860 let label_c = match std::ffi::CString::new(label.as_ref()) {
861 Ok(s) => s,
862 Err(_) => return,
863 };
864 let stride_bytes = std::mem::size_of::<f64>() as i32;
865 unsafe {
866 sys::ImPlot3D_PlotQuad_doublePtr(
867 label_c.as_ptr(),
868 xs.as_ptr(),
869 ys.as_ptr(),
870 zs.as_ptr(),
871 xs.len() as i32,
872 flags.bits() as i32,
873 0,
874 stride_bytes,
875 );
876 }
877 }
878
879 pub fn plot_quads_f64_raw<S: AsRef<str>>(
880 &self,
881 label: S,
882 xs: &[f64],
883 ys: &[f64],
884 zs: &[f64],
885 flags: Quad3DFlags,
886 offset: i32,
887 stride: i32,
888 ) {
889 if xs.len() != ys.len() || ys.len() != zs.len() {
890 return;
891 }
892 let label_c = match std::ffi::CString::new(label.as_ref()) {
893 Ok(s) => s,
894 Err(_) => return,
895 };
896 let stride_bytes = if stride == 0 {
897 std::mem::size_of::<f64>() as i32
898 } else {
899 stride
900 };
901 unsafe {
902 sys::ImPlot3D_PlotQuad_doublePtr(
903 label_c.as_ptr(),
904 xs.as_ptr(),
905 ys.as_ptr(),
906 zs.as_ptr(),
907 xs.len() as i32,
908 flags.bits() as i32,
909 offset,
910 stride_bytes,
911 );
912 }
913 }
914}
915
916impl Drop for Plot3DToken {
917 fn drop(&mut self) {
918 unsafe {
919 debug_end_plot();
920 sys::ImPlot3D_EndPlot();
921 }
922 }
923}
924
925pub struct Plot3DBuilder {
927 title: String,
928 size: Option<[f32; 2]>,
929 flags: Plot3DFlags,
930}
931
932impl Plot3DBuilder {
933 pub fn size(mut self, size: [f32; 2]) -> Self {
934 self.size = Some(size);
935 self
936 }
937 pub fn flags(mut self, flags: Plot3DFlags) -> Self {
938 self.flags = flags;
939 self
940 }
941 pub fn build(self) -> Option<Plot3DToken> {
942 let title_c = std::ffi::CString::new(self.title).ok()?;
943 let size = self.size.unwrap_or([0.0, 0.0]);
944 let ok = unsafe {
945 let style = sys::ImPlot3D_GetStyle();
947 if !style.is_null() {
948 let count = sys::ImPlot3D_GetColormapCount();
949 if count > 0 {
950 if (*style).Colormap < 0 || (*style).Colormap >= count {
951 (*style).Colormap = 0;
952 }
953 }
954 }
955 sys::ImPlot3D_BeginPlot(
956 title_c.as_ptr(),
957 imvec2(size[0], size[1]),
958 self.flags.bits() as i32,
959 )
960 };
961 if ok {
962 debug_begin_plot();
963 Some(Plot3DToken)
964 } else {
965 None
966 }
967 }
968}
969
970#[cfg(feature = "mint")]
997impl<'ui> Plot3DUi<'ui> {
998 pub fn plot_line_mint<S: AsRef<str>>(
1002 &self,
1003 label: S,
1004 pts: &[mint::Point3<f32>],
1005 flags: Line3DFlags,
1006 ) {
1007 let mut xs = Vec::with_capacity(pts.len());
1008 let mut ys = Vec::with_capacity(pts.len());
1009 let mut zs = Vec::with_capacity(pts.len());
1010 for p in pts {
1011 xs.push(p.x);
1012 ys.push(p.y);
1013 zs.push(p.z);
1014 }
1015 self.plot_line_f32(label, &xs, &ys, &zs, flags);
1016 }
1017
1018 pub fn plot_scatter_mint<S: AsRef<str>>(
1020 &self,
1021 label: S,
1022 pts: &[mint::Point3<f32>],
1023 flags: Scatter3DFlags,
1024 ) {
1025 let mut xs = Vec::with_capacity(pts.len());
1026 let mut ys = Vec::with_capacity(pts.len());
1027 let mut zs = Vec::with_capacity(pts.len());
1028 for p in pts {
1029 xs.push(p.x);
1030 ys.push(p.y);
1031 zs.push(p.z);
1032 }
1033 self.plot_scatter_f32(label, &xs, &ys, &zs, flags);
1034 }
1035
1036 pub fn plot_text_mint(
1038 &self,
1039 text: &str,
1040 pos: mint::Point3<f32>,
1041 angle: f32,
1042 pix_offset: [f32; 2],
1043 ) {
1044 self.plot_text(text, pos.x, pos.y, pos.z, angle, pix_offset);
1045 }
1046
1047 pub fn plot_to_pixels_mint(&self, point: mint::Point3<f32>) -> [f32; 2] {
1049 self.plot_to_pixels([point.x, point.y, point.z])
1050 }
1051}
1052
1053pub struct Surface3DBuilder<'ui> {
1055 ui: &'ui Plot3DUi<'ui>,
1056 label: std::ffi::CString,
1057 xs: &'ui [f32],
1058 ys: &'ui [f32],
1059 zs: &'ui [f32],
1060 scale_min: f64,
1061 scale_max: f64,
1062 flags: Surface3DFlags,
1063}
1064
1065impl<'ui> Surface3DBuilder<'ui> {
1066 pub fn scale(mut self, min: f64, max: f64) -> Self {
1067 self.scale_min = min;
1068 self.scale_max = max;
1069 self
1070 }
1071 pub fn flags(mut self, flags: Surface3DFlags) -> Self {
1072 self.flags = flags;
1073 self
1074 }
1075 pub fn plot(self) {
1076 let x_count = self.xs.len() as i32;
1077 let y_count = self.ys.len() as i32;
1078 let expected = (x_count as usize) * (y_count as usize);
1079 if self.zs.len() != expected {
1080 return;
1081 }
1082 unsafe {
1083 sys::ImPlot3D_PlotSurface_FloatPtr(
1084 self.label.as_ptr(),
1085 self.xs.as_ptr(),
1086 self.ys.as_ptr(),
1087 self.zs.as_ptr(),
1088 x_count,
1089 y_count,
1090 self.scale_min,
1091 self.scale_max,
1092 self.flags.bits() as i32,
1093 0,
1094 0,
1095 );
1096 }
1097 }
1098}
1099
1100impl<'ui> Plot3DUi<'ui> {
1101 pub fn surface_f32<S: AsRef<str>>(
1103 &'ui self,
1104 label: S,
1105 xs: &'ui [f32],
1106 ys: &'ui [f32],
1107 zs: &'ui [f32],
1108 ) -> Surface3DBuilder<'ui> {
1109 let label_c = std::ffi::CString::new(label.as_ref())
1110 .unwrap_or_else(|_| std::ffi::CString::new("surface").unwrap());
1111 Surface3DBuilder {
1112 ui: self,
1113 label: label_c,
1114 xs,
1115 ys,
1116 zs,
1117 scale_min: f64::NAN,
1118 scale_max: f64::NAN,
1119 flags: Surface3DFlags::NONE,
1120 }
1121 }
1122
1123 pub fn surface_f32_raw<S: AsRef<str>>(
1125 &self,
1126 label: S,
1127 xs: &[f32],
1128 ys: &[f32],
1129 zs: &[f32],
1130 scale_min: f64,
1131 scale_max: f64,
1132 flags: Surface3DFlags,
1133 offset: i32,
1134 stride: i32,
1135 ) {
1136 debug_before_plot();
1137 let x_count = xs.len();
1138 let y_count = ys.len();
1139 let expected = match x_count.checked_mul(y_count) {
1140 Some(v) => v,
1141 None => return,
1142 };
1143 if zs.len() != expected {
1144 return;
1146 }
1147
1148 let mut xs_flat = Vec::with_capacity(expected);
1150 let mut ys_flat = Vec::with_capacity(expected);
1151 for yi in 0..y_count {
1152 for xi in 0..x_count {
1153 xs_flat.push(xs[xi]);
1154 ys_flat.push(ys[yi]);
1155 }
1156 }
1157
1158 let label_c = match std::ffi::CString::new(label.as_ref()) {
1159 Ok(s) => s,
1160 Err(_) => return,
1161 };
1162 let stride_bytes = if stride == 0 {
1163 std::mem::size_of::<f32>() as i32
1164 } else {
1165 stride
1166 };
1167 unsafe {
1168 sys::ImPlot3D_PlotSurface_FloatPtr(
1169 label_c.as_ptr(),
1170 xs_flat.as_ptr(),
1171 ys_flat.as_ptr(),
1172 zs.as_ptr(),
1173 x_count as i32,
1174 y_count as i32,
1175 scale_min,
1176 scale_max,
1177 flags.bits() as i32,
1178 offset,
1179 stride_bytes,
1180 );
1181 }
1182 }
1183
1184 pub fn surface_f32_flat<S: AsRef<str>>(
1189 &self,
1190 label: S,
1191 xs_flat: &[f32],
1192 ys_flat: &[f32],
1193 zs: &[f32],
1194 x_count: i32,
1195 y_count: i32,
1196 scale_min: f64,
1197 scale_max: f64,
1198 flags: Surface3DFlags,
1199 offset: i32,
1200 stride: i32,
1201 ) {
1202 debug_before_plot();
1203 if x_count <= 0 || y_count <= 0 {
1204 return;
1205 }
1206 let expected = (x_count as usize).saturating_mul(y_count as usize);
1207 if xs_flat.len() != expected || ys_flat.len() != expected || zs.len() != expected {
1208 return;
1209 }
1210 let label_c = match std::ffi::CString::new(label.as_ref()) {
1211 Ok(s) => s,
1212 Err(_) => return,
1213 };
1214 let stride_bytes = if stride == 0 {
1215 std::mem::size_of::<f32>() as i32
1216 } else {
1217 stride
1218 };
1219 unsafe {
1220 sys::ImPlot3D_PlotSurface_FloatPtr(
1221 label_c.as_ptr(),
1222 xs_flat.as_ptr(),
1223 ys_flat.as_ptr(),
1224 zs.as_ptr(),
1225 x_count,
1226 y_count,
1227 scale_min,
1228 scale_max,
1229 flags.bits() as i32,
1230 offset,
1231 stride_bytes,
1232 );
1233 }
1234 }
1235}
1236
1237pub struct Image3DByAxesBuilder<'ui> {
1239 _ui: &'ui Plot3DUi<'ui>,
1240 label: std::ffi::CString,
1241 tex_ref: sys::ImTextureRef_c,
1242 center: [f32; 3],
1243 axis_u: [f32; 3],
1244 axis_v: [f32; 3],
1245 uv0: [f32; 2],
1246 uv1: [f32; 2],
1247 tint: [f32; 4],
1248 flags: Image3DFlags,
1249}
1250
1251impl<'ui> Image3DByAxesBuilder<'ui> {
1252 pub fn uv(mut self, uv0: [f32; 2], uv1: [f32; 2]) -> Self {
1253 self.uv0 = uv0;
1254 self.uv1 = uv1;
1255 self
1256 }
1257 pub fn tint(mut self, col: [f32; 4]) -> Self {
1258 self.tint = col;
1259 self
1260 }
1261 pub fn flags(mut self, flags: Image3DFlags) -> Self {
1262 self.flags = flags;
1263 self
1264 }
1265 pub fn plot(self) {
1266 unsafe {
1267 debug_before_plot();
1268 sys::ImPlot3D_PlotImage_Vec2(
1269 self.label.as_ptr(),
1270 self.tex_ref,
1271 sys::ImPlot3DPoint_c {
1272 x: self.center[0] as f64,
1273 y: self.center[1] as f64,
1274 z: self.center[2] as f64,
1275 },
1276 sys::ImPlot3DPoint_c {
1277 x: self.axis_u[0] as f64,
1278 y: self.axis_u[1] as f64,
1279 z: self.axis_u[2] as f64,
1280 },
1281 sys::ImPlot3DPoint_c {
1282 x: self.axis_v[0] as f64,
1283 y: self.axis_v[1] as f64,
1284 z: self.axis_v[2] as f64,
1285 },
1286 imvec2(self.uv0[0], self.uv0[1]),
1287 imvec2(self.uv1[0], self.uv1[1]),
1288 imvec4(self.tint[0], self.tint[1], self.tint[2], self.tint[3]),
1289 self.flags.bits() as i32,
1290 );
1291 }
1292 }
1293}
1294
1295pub struct Image3DByCornersBuilder<'ui> {
1297 _ui: &'ui Plot3DUi<'ui>,
1298 label: std::ffi::CString,
1299 tex_ref: sys::ImTextureRef_c,
1300 p0: [f32; 3],
1301 p1: [f32; 3],
1302 p2: [f32; 3],
1303 p3: [f32; 3],
1304 uv0: [f32; 2],
1305 uv1: [f32; 2],
1306 uv2: [f32; 2],
1307 uv3: [f32; 2],
1308 tint: [f32; 4],
1309 flags: Image3DFlags,
1310}
1311
1312impl<'ui> Image3DByCornersBuilder<'ui> {
1313 pub fn uvs(mut self, uv0: [f32; 2], uv1: [f32; 2], uv2: [f32; 2], uv3: [f32; 2]) -> Self {
1314 self.uv0 = uv0;
1315 self.uv1 = uv1;
1316 self.uv2 = uv2;
1317 self.uv3 = uv3;
1318 self
1319 }
1320 pub fn tint(mut self, col: [f32; 4]) -> Self {
1321 self.tint = col;
1322 self
1323 }
1324 pub fn flags(mut self, flags: Image3DFlags) -> Self {
1325 self.flags = flags;
1326 self
1327 }
1328 pub fn plot(self) {
1329 unsafe {
1330 debug_before_plot();
1331 sys::ImPlot3D_PlotImage_Plot3DPoInt(
1332 self.label.as_ptr(),
1333 self.tex_ref,
1334 sys::ImPlot3DPoint_c {
1335 x: self.p0[0] as f64,
1336 y: self.p0[1] as f64,
1337 z: self.p0[2] as f64,
1338 },
1339 sys::ImPlot3DPoint_c {
1340 x: self.p1[0] as f64,
1341 y: self.p1[1] as f64,
1342 z: self.p1[2] as f64,
1343 },
1344 sys::ImPlot3DPoint_c {
1345 x: self.p2[0] as f64,
1346 y: self.p2[1] as f64,
1347 z: self.p2[2] as f64,
1348 },
1349 sys::ImPlot3DPoint_c {
1350 x: self.p3[0] as f64,
1351 y: self.p3[1] as f64,
1352 z: self.p3[2] as f64,
1353 },
1354 imvec2(self.uv0[0], self.uv0[1]),
1355 imvec2(self.uv1[0], self.uv1[1]),
1356 imvec2(self.uv2[0], self.uv2[1]),
1357 imvec2(self.uv3[0], self.uv3[1]),
1358 imvec4(self.tint[0], self.tint[1], self.tint[2], self.tint[3]),
1359 self.flags.bits() as i32,
1360 );
1361 }
1362 }
1363}
1364
1365impl<'ui> Plot3DUi<'ui> {
1366 pub fn image_by_axes<S: AsRef<str>, T: Into<TextureRef>>(
1368 &'ui self,
1369 label: S,
1370 tex: T,
1371 center: [f32; 3],
1372 axis_u: [f32; 3],
1373 axis_v: [f32; 3],
1374 ) -> Image3DByAxesBuilder<'ui> {
1375 let label_c = std::ffi::CString::new(label.as_ref())
1376 .unwrap_or_else(|_| std::ffi::CString::new("image").unwrap());
1377 let tr = tex.into().raw();
1378 let tex_ref = sys::ImTextureRef_c {
1379 _TexData: tr._TexData as *mut sys::ImTextureData,
1380 _TexID: tr._TexID as sys::ImTextureID,
1381 };
1382 debug_before_plot();
1383 Image3DByAxesBuilder {
1384 _ui: self,
1385 label: label_c,
1386 tex_ref,
1387 center,
1388 axis_u,
1389 axis_v,
1390 uv0: [0.0, 0.0],
1391 uv1: [1.0, 1.0],
1392 tint: [1.0, 1.0, 1.0, 1.0],
1393 flags: Image3DFlags::NONE,
1394 }
1395 }
1396
1397 pub fn image_by_corners<S: AsRef<str>, T: Into<TextureRef>>(
1399 &'ui self,
1400 label: S,
1401 tex: T,
1402 p0: [f32; 3],
1403 p1: [f32; 3],
1404 p2: [f32; 3],
1405 p3: [f32; 3],
1406 ) -> Image3DByCornersBuilder<'ui> {
1407 let label_c = std::ffi::CString::new(label.as_ref())
1408 .unwrap_or_else(|_| std::ffi::CString::new("image").unwrap());
1409 let tr = tex.into().raw();
1410 let tex_ref = sys::ImTextureRef_c {
1411 _TexData: tr._TexData as *mut sys::ImTextureData,
1412 _TexID: tr._TexID as sys::ImTextureID,
1413 };
1414 debug_before_plot();
1415 Image3DByCornersBuilder {
1416 _ui: self,
1417 label: label_c,
1418 tex_ref,
1419 p0,
1420 p1,
1421 p2,
1422 p3,
1423 uv0: [0.0, 0.0],
1424 uv1: [1.0, 0.0],
1425 uv2: [1.0, 1.0],
1426 uv3: [0.0, 1.0],
1427 tint: [1.0, 1.0, 1.0, 1.0],
1428 flags: Image3DFlags::NONE,
1429 }
1430 }
1431}
1432
1433impl<'ui> Plot3DUi<'ui> {
1435 pub fn setup_axes(
1436 &self,
1437 x_label: &str,
1438 y_label: &str,
1439 z_label: &str,
1440 x_flags: Axis3DFlags,
1441 y_flags: Axis3DFlags,
1442 z_flags: Axis3DFlags,
1443 ) {
1444 debug_before_setup();
1445 let cx = std::ffi::CString::new(x_label).unwrap_or_default();
1446 let cy = std::ffi::CString::new(y_label).unwrap_or_default();
1447 let cz = std::ffi::CString::new(z_label).unwrap_or_default();
1448 unsafe {
1449 sys::ImPlot3D_SetupAxes(
1450 cx.as_ptr(),
1451 cy.as_ptr(),
1452 cz.as_ptr(),
1453 x_flags.bits() as i32,
1454 y_flags.bits() as i32,
1455 z_flags.bits() as i32,
1456 )
1457 }
1458 }
1459
1460 pub fn setup_axis(&self, axis: Axis3D, label: &str, flags: Axis3DFlags) {
1461 debug_before_setup();
1462 let c = std::ffi::CString::new(label).unwrap_or_default();
1463 unsafe { sys::ImPlot3D_SetupAxis(axis as i32, c.as_ptr(), flags.bits() as i32) }
1464 }
1465
1466 pub fn setup_axis_limits(&self, axis: Axis3D, min: f64, max: f64, cond: Plot3DCond) {
1467 debug_before_setup();
1468 unsafe { sys::ImPlot3D_SetupAxisLimits(axis as i32, min, max, cond as i32) }
1469 }
1470
1471 pub fn setup_axes_limits(
1472 &self,
1473 x_min: f64,
1474 x_max: f64,
1475 y_min: f64,
1476 y_max: f64,
1477 z_min: f64,
1478 z_max: f64,
1479 cond: Plot3DCond,
1480 ) {
1481 debug_before_setup();
1482 unsafe {
1483 sys::ImPlot3D_SetupAxesLimits(x_min, x_max, y_min, y_max, z_min, z_max, cond as i32)
1484 }
1485 }
1486
1487 pub fn setup_axis_limits_constraints(&self, axis: Axis3D, v_min: f64, v_max: f64) {
1488 debug_before_setup();
1489 unsafe { sys::ImPlot3D_SetupAxisLimitsConstraints(axis as i32, v_min, v_max) }
1490 }
1491
1492 pub fn setup_axis_zoom_constraints(&self, axis: Axis3D, z_min: f64, z_max: f64) {
1493 debug_before_setup();
1494 unsafe { sys::ImPlot3D_SetupAxisZoomConstraints(axis as i32, z_min, z_max) }
1495 }
1496
1497 pub fn setup_axis_ticks_values(
1498 &self,
1499 axis: Axis3D,
1500 values: &[f64],
1501 labels: Option<&[&str]>,
1502 keep_default: bool,
1503 ) {
1504 debug_before_setup();
1505 let n_ticks = values.len() as i32;
1506 let labels_ptr = if let Some(lbls) = labels {
1507 let c_labels: Vec<std::ffi::CString> = lbls
1508 .iter()
1509 .map(|s| std::ffi::CString::new(*s).unwrap_or_default())
1510 .collect();
1511 let ptrs: Vec<*const i8> = c_labels.iter().map(|cs| cs.as_ptr()).collect();
1512 ptrs.as_ptr()
1513 } else {
1514 std::ptr::null()
1515 };
1516 unsafe {
1517 sys::ImPlot3D_SetupAxisTicks_doublePtr(
1518 axis as i32,
1519 values.as_ptr(),
1520 n_ticks,
1521 labels_ptr,
1522 keep_default,
1523 )
1524 }
1525 }
1526
1527 pub fn setup_axis_ticks_range(
1528 &self,
1529 axis: Axis3D,
1530 v_min: f64,
1531 v_max: f64,
1532 n_ticks: i32,
1533 labels: Option<&[&str]>,
1534 keep_default: bool,
1535 ) {
1536 debug_before_setup();
1537 let labels_ptr = if let Some(lbls) = labels {
1538 let c_labels: Vec<std::ffi::CString> = lbls
1539 .iter()
1540 .map(|s| std::ffi::CString::new(*s).unwrap_or_default())
1541 .collect();
1542 let ptrs: Vec<*const i8> = c_labels.iter().map(|cs| cs.as_ptr()).collect();
1543 ptrs.as_ptr()
1544 } else {
1545 std::ptr::null()
1546 };
1547 unsafe {
1548 sys::ImPlot3D_SetupAxisTicks_double(
1549 axis as i32,
1550 v_min,
1551 v_max,
1552 n_ticks,
1553 labels_ptr,
1554 keep_default,
1555 )
1556 }
1557 }
1558
1559 pub fn setup_box_scale(&self, x: f32, y: f32, z: f32) {
1560 debug_before_setup();
1561 unsafe { sys::ImPlot3D_SetupBoxScale(x as f64, y as f64, z as f64) }
1562 }
1563
1564 pub fn setup_box_rotation(
1565 &self,
1566 elevation: f32,
1567 azimuth: f32,
1568 animate: bool,
1569 cond: Plot3DCond,
1570 ) {
1571 debug_before_setup();
1572 unsafe {
1573 sys::ImPlot3D_SetupBoxRotation_double(
1574 elevation as f64,
1575 azimuth as f64,
1576 animate,
1577 cond as i32,
1578 )
1579 }
1580 }
1581
1582 pub fn setup_box_initial_rotation(&self, elevation: f32, azimuth: f32) {
1583 debug_before_setup();
1584 unsafe { sys::ImPlot3D_SetupBoxInitialRotation_double(elevation as f64, azimuth as f64) }
1585 }
1586
1587 pub fn plot_text(&self, text: &str, x: f32, y: f32, z: f32, angle: f32, pix_offset: [f32; 2]) {
1588 let c_text = std::ffi::CString::new(text).unwrap_or_default();
1589 unsafe {
1590 debug_before_plot();
1591 sys::ImPlot3D_PlotText(
1592 c_text.as_ptr(),
1593 x as f64,
1594 y as f64,
1595 z as f64,
1596 angle as f64,
1597 imvec2(pix_offset[0], pix_offset[1]),
1598 )
1599 }
1600 }
1601
1602 pub fn plot_to_pixels(&self, point: [f32; 3]) -> [f32; 2] {
1603 unsafe {
1604 let out = compat_ffi::ImPlot3D_PlotToPixels_double(
1605 point[0] as f64,
1606 point[1] as f64,
1607 point[2] as f64,
1608 );
1609 [out.x, out.y]
1610 }
1611 }
1612
1613 pub fn get_plot_draw_list(&self) -> *mut sys::ImDrawList {
1614 unsafe { sys::ImPlot3D_GetPlotDrawList() }
1615 }
1616
1617 pub fn get_frame_pos(&self) -> [f32; 2] {
1618 unsafe {
1619 let out = compat_ffi::ImPlot3D_GetPlotRectPos();
1620 [out.x, out.y]
1621 }
1622 }
1623
1624 pub fn get_frame_size(&self) -> [f32; 2] {
1625 unsafe {
1626 let out = compat_ffi::ImPlot3D_GetPlotRectSize();
1627 [out.x, out.y]
1628 }
1629 }
1630}
1631
1632pub struct Mesh3DBuilder<'ui> {
1634 _ui: &'ui Plot3DUi<'ui>,
1635 label: std::ffi::CString,
1636 vertices: &'ui [[f32; 3]],
1637 indices: &'ui [u32],
1638 flags: Mesh3DFlags,
1639}
1640
1641impl<'ui> Mesh3DBuilder<'ui> {
1642 pub fn flags(mut self, flags: Mesh3DFlags) -> Self {
1643 self.flags = flags;
1644 self
1645 }
1646 pub fn plot(self) {
1647 let vtx_count = self.vertices.len() as i32;
1650 let idx_count = self.indices.len() as i32;
1651 unsafe {
1652 debug_before_plot();
1653 let vtx_ptr = self.vertices.as_ptr() as *const sys::ImPlot3DPoint;
1654 sys::ImPlot3D_PlotMesh(
1655 self.label.as_ptr(),
1656 vtx_ptr,
1657 self.indices.as_ptr(),
1658 vtx_count,
1659 idx_count,
1660 self.flags.bits() as i32,
1661 );
1662 }
1663 }
1664}
1665
1666impl<'ui> Plot3DUi<'ui> {
1667 pub fn mesh<S: AsRef<str>>(
1669 &'ui self,
1670 label: S,
1671 vertices: &'ui [[f32; 3]],
1672 indices: &'ui [u32],
1673 ) -> Mesh3DBuilder<'ui> {
1674 let label_c = std::ffi::CString::new(label.as_ref())
1675 .unwrap_or_else(|_| std::ffi::CString::new("mesh").unwrap());
1676 Mesh3DBuilder {
1677 _ui: self,
1678 label: label_c,
1679 vertices,
1680 indices,
1681 flags: Mesh3DFlags::NONE,
1682 }
1683 }
1684}