1use std::marker::PhantomData;
2
3use crate::builder::Plot3DBuilder;
4use crate::{
5 Line3DFlags, Plot3DDataLayout, Plot3DFlags, Quad3DFlags, Scatter3DFlags, Triangle3DFlags,
6 imgui_sys, len_i32, plot3d_spec_from, sys,
7};
8use dear_imgui_rs::Ui;
9
10use super::binding::Plot3DContextBinding;
11
12pub struct Plot3DUi<'ui> {
33 pub(crate) _ui: &'ui Ui,
34 pub(crate) binding: Plot3DContextBinding,
35 pub(crate) imgui_alive: Option<dear_imgui_rs::ContextAliveToken>,
36}
37
38impl<'ui> Plot3DUi<'ui> {
39 pub(crate) fn from_current(ui: &'ui Ui) -> Self {
40 let imgui_ctx_raw = unsafe { imgui_sys::igGetCurrentContext() };
41 assert!(
42 !imgui_ctx_raw.is_null(),
43 "dear-implot3d: Plot3DUi requires an active ImGui context"
44 );
45 let plot_ctx_raw = unsafe { sys::ImPlot3D_GetCurrentContext() };
46 assert!(
47 !plot_ctx_raw.is_null(),
48 "dear-implot3d: Plot3DUi requires an active ImPlot3D context"
49 );
50 Self {
51 _ui: ui,
52 binding: Plot3DContextBinding {
53 plot_ctx_raw,
54 imgui_ctx_raw,
55 },
56 imgui_alive: None,
57 }
58 }
59
60 pub(crate) fn bind(&self) {
61 if let Some(alive) = &self.imgui_alive {
62 assert!(
63 alive.is_alive(),
64 "dear-implot3d: ImGui context has been dropped"
65 );
66 }
67 self.binding.bind();
68 }
69
70 pub fn begin_plot<S: AsRef<str>>(&self, title: S) -> Plot3DBuilder<'ui> {
90 self.bind();
91 Plot3DBuilder {
92 binding: self.binding,
93 imgui_alive: self.imgui_alive.clone(),
94 title: title.as_ref().into(),
95 size: None,
96 flags: Plot3DFlags::empty(),
97 _lifetime: PhantomData,
98 }
99 }
100
101 pub fn plot_line_f32<S: AsRef<str>>(
126 &self,
127 label: S,
128 xs: &[f32],
129 ys: &[f32],
130 zs: &[f32],
131 flags: Line3DFlags,
132 ) {
133 self.bind();
134 if xs.len() != ys.len() || ys.len() != zs.len() {
135 return;
136 }
137 let Some(count) = len_i32(xs.len()) else {
138 return;
139 };
140 let label = label.as_ref();
141 if label.contains('\0') {
142 return;
143 }
144 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
145 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
146 sys::ImPlot3D_PlotLine_FloatPtr(
147 label_ptr,
148 xs.as_ptr(),
149 ys.as_ptr(),
150 zs.as_ptr(),
151 count,
152 spec,
153 );
154 })
155 }
156
157 pub fn plot_line_f32_raw<S: AsRef<str>>(
159 &self,
160 label: S,
161 xs: &[f32],
162 ys: &[f32],
163 zs: &[f32],
164 flags: Line3DFlags,
165 layout: Plot3DDataLayout,
166 ) {
167 self.bind();
168 if xs.len() != ys.len() || ys.len() != zs.len() {
169 return;
170 }
171 let Some(count) = len_i32(xs.len()) else {
172 return;
173 };
174 let label = label.as_ref();
175 if label.contains('\0') {
176 return;
177 }
178 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
179 let spec = plot3d_spec_from(flags.bits(), layout);
180 sys::ImPlot3D_PlotLine_FloatPtr(
181 label_ptr,
182 xs.as_ptr(),
183 ys.as_ptr(),
184 zs.as_ptr(),
185 count,
186 spec,
187 );
188 })
189 }
190
191 pub fn plot_line_f64<S: AsRef<str>>(
193 &self,
194 label: S,
195 xs: &[f64],
196 ys: &[f64],
197 zs: &[f64],
198 flags: Line3DFlags,
199 ) {
200 self.bind();
201 if xs.len() != ys.len() || ys.len() != zs.len() {
202 return;
203 }
204 let Some(count) = len_i32(xs.len()) else {
205 return;
206 };
207 let label = label.as_ref();
208 if label.contains('\0') {
209 return;
210 }
211 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
212 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
213 sys::ImPlot3D_PlotLine_doublePtr(
214 label_ptr,
215 xs.as_ptr(),
216 ys.as_ptr(),
217 zs.as_ptr(),
218 count,
219 spec,
220 );
221 })
222 }
223
224 pub fn plot_line_f64_raw<S: AsRef<str>>(
226 &self,
227 label: S,
228 xs: &[f64],
229 ys: &[f64],
230 zs: &[f64],
231 flags: Line3DFlags,
232 layout: Plot3DDataLayout,
233 ) {
234 self.bind();
235 if xs.len() != ys.len() || ys.len() != zs.len() {
236 return;
237 }
238 let Some(count) = len_i32(xs.len()) else {
239 return;
240 };
241 let label = label.as_ref();
242 if label.contains('\0') {
243 return;
244 }
245 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
246 let spec = plot3d_spec_from(flags.bits(), layout);
247 sys::ImPlot3D_PlotLine_doublePtr(
248 label_ptr,
249 xs.as_ptr(),
250 ys.as_ptr(),
251 zs.as_ptr(),
252 count,
253 spec,
254 );
255 })
256 }
257
258 pub fn plot_scatter_f32<S: AsRef<str>>(
260 &self,
261 label: S,
262 xs: &[f32],
263 ys: &[f32],
264 zs: &[f32],
265 flags: Scatter3DFlags,
266 ) {
267 self.bind();
268 if xs.len() != ys.len() || ys.len() != zs.len() {
269 return;
270 }
271 let Some(count) = len_i32(xs.len()) else {
272 return;
273 };
274 let label = label.as_ref();
275 if label.contains('\0') {
276 return;
277 }
278 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
279 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
280 sys::ImPlot3D_PlotScatter_FloatPtr(
281 label_ptr,
282 xs.as_ptr(),
283 ys.as_ptr(),
284 zs.as_ptr(),
285 count,
286 spec,
287 );
288 })
289 }
290
291 pub fn plot_scatter_f32_raw<S: AsRef<str>>(
293 &self,
294 label: S,
295 xs: &[f32],
296 ys: &[f32],
297 zs: &[f32],
298 flags: Scatter3DFlags,
299 layout: Plot3DDataLayout,
300 ) {
301 self.bind();
302 if xs.len() != ys.len() || ys.len() != zs.len() {
303 return;
304 }
305 let Some(count) = len_i32(xs.len()) else {
306 return;
307 };
308 let label = label.as_ref();
309 if label.contains('\0') {
310 return;
311 }
312 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
313 let spec = plot3d_spec_from(flags.bits(), layout);
314 sys::ImPlot3D_PlotScatter_FloatPtr(
315 label_ptr,
316 xs.as_ptr(),
317 ys.as_ptr(),
318 zs.as_ptr(),
319 count,
320 spec,
321 );
322 })
323 }
324
325 pub fn plot_scatter_f64<S: AsRef<str>>(
327 &self,
328 label: S,
329 xs: &[f64],
330 ys: &[f64],
331 zs: &[f64],
332 flags: Scatter3DFlags,
333 ) {
334 self.bind();
335 if xs.len() != ys.len() || ys.len() != zs.len() {
336 return;
337 }
338 let Some(count) = len_i32(xs.len()) else {
339 return;
340 };
341 let label = label.as_ref();
342 if label.contains('\0') {
343 return;
344 }
345 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
346 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
347 sys::ImPlot3D_PlotScatter_doublePtr(
348 label_ptr,
349 xs.as_ptr(),
350 ys.as_ptr(),
351 zs.as_ptr(),
352 count,
353 spec,
354 );
355 })
356 }
357
358 pub fn plot_scatter_f64_raw<S: AsRef<str>>(
360 &self,
361 label: S,
362 xs: &[f64],
363 ys: &[f64],
364 zs: &[f64],
365 flags: Scatter3DFlags,
366 layout: Plot3DDataLayout,
367 ) {
368 self.bind();
369 if xs.len() != ys.len() || ys.len() != zs.len() {
370 return;
371 }
372 let Some(count) = len_i32(xs.len()) else {
373 return;
374 };
375 let label = label.as_ref();
376 if label.contains('\0') {
377 return;
378 }
379 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
380 let spec = plot3d_spec_from(flags.bits(), layout);
381 sys::ImPlot3D_PlotScatter_doublePtr(
382 label_ptr,
383 xs.as_ptr(),
384 ys.as_ptr(),
385 zs.as_ptr(),
386 count,
387 spec,
388 );
389 })
390 }
391
392 pub fn plot_triangles_f32<S: AsRef<str>>(
394 &self,
395 label: S,
396 xs: &[f32],
397 ys: &[f32],
398 zs: &[f32],
399 flags: Triangle3DFlags,
400 ) {
401 self.bind();
402 if xs.len() != ys.len() || ys.len() != zs.len() {
403 return;
404 }
405 let Some(count) = len_i32(xs.len()) else {
406 return;
407 };
408 let label = label.as_ref();
409 if label.contains('\0') {
410 return;
411 }
412 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
413 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
414 sys::ImPlot3D_PlotTriangle_FloatPtr(
415 label_ptr,
416 xs.as_ptr(),
417 ys.as_ptr(),
418 zs.as_ptr(),
419 count,
420 spec,
421 );
422 })
423 }
424
425 pub fn plot_triangles_f32_raw<S: AsRef<str>>(
426 &self,
427 label: S,
428 xs: &[f32],
429 ys: &[f32],
430 zs: &[f32],
431 flags: Triangle3DFlags,
432 layout: Plot3DDataLayout,
433 ) {
434 self.bind();
435 if xs.len() != ys.len() || ys.len() != zs.len() {
436 return;
437 }
438 let Some(count) = len_i32(xs.len()) else {
439 return;
440 };
441 let label = label.as_ref();
442 if label.contains('\0') {
443 return;
444 }
445 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
446 let spec = plot3d_spec_from(flags.bits(), layout);
447 sys::ImPlot3D_PlotTriangle_FloatPtr(
448 label_ptr,
449 xs.as_ptr(),
450 ys.as_ptr(),
451 zs.as_ptr(),
452 count,
453 spec,
454 );
455 })
456 }
457
458 pub fn plot_quads_f32<S: AsRef<str>>(
460 &self,
461 label: S,
462 xs: &[f32],
463 ys: &[f32],
464 zs: &[f32],
465 flags: Quad3DFlags,
466 ) {
467 self.bind();
468 if xs.len() != ys.len() || ys.len() != zs.len() {
469 return;
470 }
471 let Some(count) = len_i32(xs.len()) else {
472 return;
473 };
474 let label = label.as_ref();
475 if label.contains('\0') {
476 return;
477 }
478 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
479 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
480 sys::ImPlot3D_PlotQuad_FloatPtr(
481 label_ptr,
482 xs.as_ptr(),
483 ys.as_ptr(),
484 zs.as_ptr(),
485 count,
486 spec,
487 );
488 })
489 }
490
491 pub fn plot_quads_f32_raw<S: AsRef<str>>(
492 &self,
493 label: S,
494 xs: &[f32],
495 ys: &[f32],
496 zs: &[f32],
497 flags: Quad3DFlags,
498 layout: Plot3DDataLayout,
499 ) {
500 self.bind();
501 if xs.len() != ys.len() || ys.len() != zs.len() {
502 return;
503 }
504 let Some(count) = len_i32(xs.len()) else {
505 return;
506 };
507 let label = label.as_ref();
508 if label.contains('\0') {
509 return;
510 }
511 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
512 let spec = plot3d_spec_from(flags.bits(), layout);
513 sys::ImPlot3D_PlotQuad_FloatPtr(
514 label_ptr,
515 xs.as_ptr(),
516 ys.as_ptr(),
517 zs.as_ptr(),
518 count,
519 spec,
520 );
521 })
522 }
523
524 pub fn plot_triangles_f64<S: AsRef<str>>(
526 &self,
527 label: S,
528 xs: &[f64],
529 ys: &[f64],
530 zs: &[f64],
531 flags: Triangle3DFlags,
532 ) {
533 self.bind();
534 if xs.len() != ys.len() || ys.len() != zs.len() {
535 return;
536 }
537 let Some(count) = len_i32(xs.len()) else {
538 return;
539 };
540 let label = label.as_ref();
541 if label.contains('\0') {
542 return;
543 }
544 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
545 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
546 sys::ImPlot3D_PlotTriangle_doublePtr(
547 label_ptr,
548 xs.as_ptr(),
549 ys.as_ptr(),
550 zs.as_ptr(),
551 count,
552 spec,
553 );
554 })
555 }
556
557 pub fn plot_triangles_f64_raw<S: AsRef<str>>(
558 &self,
559 label: S,
560 xs: &[f64],
561 ys: &[f64],
562 zs: &[f64],
563 flags: Triangle3DFlags,
564 layout: Plot3DDataLayout,
565 ) {
566 self.bind();
567 if xs.len() != ys.len() || ys.len() != zs.len() {
568 return;
569 }
570 let Some(count) = len_i32(xs.len()) else {
571 return;
572 };
573 let label = label.as_ref();
574 if label.contains('\0') {
575 return;
576 }
577 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
578 let spec = plot3d_spec_from(flags.bits(), layout);
579 sys::ImPlot3D_PlotTriangle_doublePtr(
580 label_ptr,
581 xs.as_ptr(),
582 ys.as_ptr(),
583 zs.as_ptr(),
584 count,
585 spec,
586 );
587 })
588 }
589
590 pub fn plot_quads_f64<S: AsRef<str>>(
592 &self,
593 label: S,
594 xs: &[f64],
595 ys: &[f64],
596 zs: &[f64],
597 flags: Quad3DFlags,
598 ) {
599 self.bind();
600 if xs.len() != ys.len() || ys.len() != zs.len() {
601 return;
602 }
603 let Some(count) = len_i32(xs.len()) else {
604 return;
605 };
606 let label = label.as_ref();
607 if label.contains('\0') {
608 return;
609 }
610 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
611 let spec = plot3d_spec_from(flags.bits(), Plot3DDataLayout::DEFAULT);
612 sys::ImPlot3D_PlotQuad_doublePtr(
613 label_ptr,
614 xs.as_ptr(),
615 ys.as_ptr(),
616 zs.as_ptr(),
617 count,
618 spec,
619 );
620 })
621 }
622
623 pub fn plot_quads_f64_raw<S: AsRef<str>>(
624 &self,
625 label: S,
626 xs: &[f64],
627 ys: &[f64],
628 zs: &[f64],
629 flags: Quad3DFlags,
630 layout: Plot3DDataLayout,
631 ) {
632 self.bind();
633 if xs.len() != ys.len() || ys.len() != zs.len() {
634 return;
635 }
636 let Some(count) = len_i32(xs.len()) else {
637 return;
638 };
639 let label = label.as_ref();
640 if label.contains('\0') {
641 return;
642 }
643 dear_imgui_rs::with_scratch_txt(label, |label_ptr| unsafe {
644 let spec = plot3d_spec_from(flags.bits(), layout);
645 sys::ImPlot3D_PlotQuad_doublePtr(
646 label_ptr,
647 xs.as_ptr(),
648 ys.as_ptr(),
649 zs.as_ptr(),
650 count,
651 spec,
652 );
653 })
654 }
655}