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