Blender V4.3
view3d_placement.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
14#include "MEM_guardedalloc.h"
15
16#include "BLI_math_matrix.h"
17#include "BLI_math_rotation.h"
18
19#include "BKE_context.hh"
20
21#include "RNA_access.hh"
22#include "RNA_define.hh"
23
24#include "WM_api.hh"
25#include "WM_toolsystem.hh"
26
27#include "ED_gizmo_utils.hh"
28#include "ED_screen.hh"
29#include "ED_space_api.hh"
30#include "ED_view3d.hh"
31
32#include "UI_resources.hh"
33
34#include "GPU_immediate.hh"
35
36#include "view3d_intern.hh"
37
38static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
39
45static const float eps_view_align = 1e-2f;
46
47/* -------------------------------------------------------------------- */
58
63
68
72};
73
75 /* Window manager variables (set these even when waiting for input). */
80
83
84 float co_src[3];
85
87 struct {
99 float plane[4];
100 float co_dst[3];
101
126
131
132 } step[2];
133
135 float view_plane[4];
136
137 float matrix_orient[3][3];
139
142 float snap_co[3];
143
146
148
151
154
157
158 /* WORKAROUND: We need to remove #SCE_SNAP_TO_GRID temporarily. */
161};
162
165/* -------------------------------------------------------------------- */
173 const float plane[4],
174 const float mval[2],
175 const float *plane_fallback,
176 float r_out[3])
177{
178 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
179 bool do_clip = rv3d->is_persp;
180 if (plane_fallback != nullptr) {
182 region, plane, mval, do_clip, plane_fallback, r_out);
183 }
184 return ED_view3d_win_to_3d_on_plane(region, plane, mval, do_clip, r_out);
185}
186
190static int dot_v3_array_find_max_index(const float dirs[][3],
191 const int dirs_len,
192 const float dir_test[3],
193 bool is_signed)
194{
195 int index_found = -1;
196 float dot_best = -1.0f;
197 for (int i = 0; i < dirs_len; i++) {
198 float dot_test = dot_v3v3(dirs[i], dir_test);
199 if (is_signed == false) {
200 dot_test = fabsf(dot_test);
201 }
202 if ((index_found == -1) || (dot_test > dot_best)) {
203 dot_best = dot_test;
204 index_found = i;
205 }
206 }
207 return index_found;
208}
209
211 idp_gizmogroup_from_region)(ARegion *region)
212{
213 wmGizmoMap *gzmap = region->gizmo_map;
214 return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : nullptr;
215}
216
223 Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3])
224{
225 const float grid_size = ED_view3d_grid_view_scale(scene, v3d, region, nullptr);
226 if (UNLIKELY(grid_size == 0.0f)) {
227 return false;
228 }
229
230 if (scene->toolsettings->snap_mode & SCE_SNAP_TO_GRID) {
231 co_relative = nullptr;
232 }
233
234 if (co_relative != nullptr) {
235 sub_v3_v3(co, co_relative);
236 }
237 mul_v3_fl(co, 1.0f / grid_size);
238 co[0] = roundf(co[0]);
239 co[1] = roundf(co[1]);
240 co[2] = roundf(co[2]);
241 mul_v3_fl(co, grid_size);
242 if (co_relative != nullptr) {
243 add_v3_v3(co, co_relative);
244 }
245
246 return true;
247}
248
251/* -------------------------------------------------------------------- */
255static void draw_line_loop(const float coords[][3], int coords_len, const float color[4])
256{
259
261 GPU_vertbuf_data_alloc(*vert, coords_len);
262
263 for (int i = 0; i < coords_len; i++) {
264 GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
265 }
266
268 blender::gpu::Batch *batch = GPU_batch_create_ex(
269 GPU_PRIM_LINE_LOOP, vert, nullptr, GPU_BATCH_OWNS_VBO);
271
272 GPU_batch_uniform_4fv(batch, "color", color);
273
274 float viewport[4];
275 GPU_viewport_size_get_f(viewport);
276 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
277 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
278
280
283}
284
285static void draw_line_pairs(const float coords_a[][3],
286 float coords_b[][3],
287 int coords_len,
288 const float color[4])
289{
292
294 GPU_vertbuf_data_alloc(*vert, coords_len * 2);
295
296 for (int i = 0; i < coords_len; i++) {
297 GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
298 GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
299 }
300
302 blender::gpu::Batch *batch = GPU_batch_create_ex(
303 GPU_PRIM_LINES, vert, nullptr, GPU_BATCH_OWNS_VBO);
305
306 GPU_batch_uniform_4fv(batch, "color", color);
307
308 float viewport[4];
309 GPU_viewport_size_get_f(viewport);
310 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
311 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
312
314
317}
318
319static void draw_line_bounds(const BoundBox *bounds, const float color[4])
320{
323
324 const int edges[12][2] = {
325 /* First side. */
326 {0, 1},
327 {1, 2},
328 {2, 3},
329 {3, 0}, /* Second side. */
330 {4, 5},
331 {5, 6},
332 {6, 7},
333 {7, 4}, /* Edges between. */
334 {0, 4},
335 {1, 5},
336 {2, 6},
337 {3, 7},
338 };
339
341 GPU_vertbuf_data_alloc(*vert, ARRAY_SIZE(edges) * 2);
342
343 for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
344 GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
345 GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
346 }
347
349 blender::gpu::Batch *batch = GPU_batch_create_ex(
350 GPU_PRIM_LINES, vert, nullptr, GPU_BATCH_OWNS_VBO);
352
353 GPU_batch_uniform_4fv(batch, "color", color);
354
355 float viewport[4];
356 GPU_viewport_size_get_f(viewport);
357 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
358 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
359
361
364}
365
367{
368 memset(bounds, 0x0, sizeof(*bounds));
369
370 if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
371 return false;
372 }
373
374 float matrix_orient_inv[3][3];
375 invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
376
377 const int x_axis = (ipd->orient_axis + 1) % 3;
378 const int y_axis = (ipd->orient_axis + 2) % 3;
379
380 float quad_base[4][3];
381 float quad_secondary[4][3];
382
383 copy_v3_v3(quad_base[0], ipd->co_src);
384 copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
385
386 /* Only set when we have a fixed aspect. */
387 float fixed_aspect_dimension;
388
389 /* *** Primary *** */
390
391 {
392 float delta_local[3];
393 float delta_a[3];
394 float delta_b[3];
395
396 sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
397 mul_m3_v3(matrix_orient_inv, delta_local);
398
399 copy_v3_v3(delta_a, delta_local);
400 copy_v3_v3(delta_b, delta_local);
401 delta_a[ipd->orient_axis] = 0.0f;
402 delta_b[ipd->orient_axis] = 0.0f;
403
404 delta_a[x_axis] = 0.0f;
405 delta_b[y_axis] = 0.0f;
406
407 /* Assign here in case secondary. */
408 fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
409
410 if (ipd->step[0].is_fixed_aspect) {
411 delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
412 delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
413 }
414
415 mul_m3_v3(ipd->matrix_orient, delta_a);
416 mul_m3_v3(ipd->matrix_orient, delta_b);
417
418 if (ipd->step[0].is_fixed_aspect) {
419 /* Recalculate the destination point. */
420 copy_v3_v3(quad_base[2], ipd->co_src);
421 add_v3_v3(quad_base[2], delta_a);
422 add_v3_v3(quad_base[2], delta_b);
423 }
424
425 add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
426 add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
427 }
428
429 if (ipd->step[0].is_centered) {
430 /* Use a copy in case aspect was applied to the quad. */
431 float base_co_dst[3];
432 copy_v3_v3(base_co_dst, quad_base[2]);
433 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
434 sub_v3_v3(quad_base[i], base_co_dst);
435 mul_v3_fl(quad_base[i], 2.0f);
436 add_v3_v3(quad_base[i], base_co_dst);
437 }
438 fixed_aspect_dimension *= 2.0f;
439 }
440
441 /* *** Secondary *** */
442
443 float delta_local[3];
444 if (ipd->step_index == STEP_DEPTH) {
445 sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
446 }
447 else {
448 zero_v3(delta_local);
449 }
450
451 if (ipd->step[1].is_fixed_aspect) {
452 if (!is_zero_v3(delta_local)) {
453 normalize_v3_length(delta_local, fixed_aspect_dimension);
454 }
455 }
456
457 if (ipd->step[1].is_centered) {
458 float temp_delta[3];
459 if (ipd->step[1].is_fixed_aspect) {
460 mul_v3_v3fl(temp_delta, delta_local, 0.5f);
461 }
462 else {
463 copy_v3_v3(temp_delta, delta_local);
464 mul_v3_fl(delta_local, 2.0f);
465 }
466
467 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
468 sub_v3_v3(quad_base[i], temp_delta);
469 }
470 }
471
472 if ((ipd->step_index == STEP_DEPTH) &&
473 (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false))
474 {
475
476 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
477 add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
478 }
479 }
480 else {
481 copy_v3_v3(quad_secondary[0], quad_base[0]);
482 copy_v3_v3(quad_secondary[1], quad_base[1]);
483 copy_v3_v3(quad_secondary[2], quad_base[2]);
484 copy_v3_v3(quad_secondary[3], quad_base[3]);
485 }
486
487 for (int i = 0; i < 4; i++) {
488 copy_v3_v3(bounds->vec[i], quad_base[i]);
489 copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
490 }
491
492 return true;
493}
494
495static void draw_circle_in_quad(const float v1[3],
496 const float v2[3],
497 const float v3[3],
498 const float v4[3],
499 const int resolution,
500 const float color[4])
501{
502 /* This isn't so efficient. */
503 const float quad[4][2] = {
504 {-1, -1},
505 {+1, -1},
506 {+1, +1},
507 {-1, +1},
508 };
509
510 float(*coords)[3] = static_cast<float(*)[3]>(
511 MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__));
512 for (int i = 0; i <= resolution; i++) {
513 float theta = ((2.0f * M_PI) * (float(i) / float(resolution))) + 0.01f;
514 float x = cosf(theta);
515 float y = sinf(theta);
516 const float pt[2] = {x, y};
517 float w[4];
519
520 float *co = coords[i];
521 zero_v3(co);
522 madd_v3_v3fl(co, v1, w[0]);
523 madd_v3_v3fl(co, v2, w[1]);
524 madd_v3_v3fl(co, v3, w[2]);
525 madd_v3_v3fl(co, v4, w[3]);
526 }
527 draw_line_loop(coords, resolution + 1, color);
528 MEM_freeN(coords);
529}
530
533/* -------------------------------------------------------------------- */
539 const float color[4],
540 int flatten_axis)
541{
542 UNUSED_VARS(C);
543
545 calc_bbox(ipd, &bounds);
546
547 /* Use cavalier projection, since it maps the scale usefully to the cursor. */
548 if (flatten_axis == STEP_BASE) {
549 /* Calculate the plane that would be defined by the side of the cube vertices
550 * if the plane had any volume. */
551
552 float no[3];
553
555 no, ipd->matrix_orient[ipd->orient_axis], ipd->matrix_orient[(ipd->orient_axis + 1) % 3]);
556
557 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
558 copy_v3_v3(no, rv3d->viewinv[2]);
559 normalize_v3(no);
560
561 float base_plane[4];
562
563 plane_from_point_normal_v3(base_plane, bounds.vec[0], no);
564
565 /* Offset all vertices even though we only need to offset the half of them.
566 * This is harmless as `dist` will be zero for the `base_plane` aligned side of the cube. */
567 for (int i = 0; i < ARRAY_SIZE(bounds.vec); i++) {
568 const float dist = dist_signed_to_plane_v3(bounds.vec[i], base_plane);
569 madd_v3_v3fl(bounds.vec[i], base_plane, -dist);
571 }
572 }
573
574 if (flatten_axis == STEP_DEPTH) {
575 const float *base_plane = ipd->step[0].plane;
576 for (int i = 0; i < 4; i++) {
577 const float dist = dist_signed_to_plane_v3(bounds.vec[i + 4], base_plane);
578 madd_v3_v3fl(bounds.vec[i + 4], base_plane, -dist);
580 }
581 }
582
583 draw_line_bounds(&bounds, color);
584
586 /* pass */
587 }
589 draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
590 draw_circle_in_quad(UNPACK4(&bounds.vec[4]), 32, color);
591 }
592 else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
593 draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
594
595 float center[3];
596 mid_v3_v3v3v3v3(center, UNPACK4(&bounds.vec[4]));
597
598 float coords_a[4][3];
599 float coords_b[4][3];
600
601 for (int i = 0; i < 4; i++) {
602 copy_v3_v3(coords_a[i], center);
603 mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
604 }
605
606 draw_line_pairs(coords_a, coords_b, 4, color);
607 }
608 else if (ELEM(ipd->primitive_type,
611 {
612 /* See bound-box diagram for reference. */
613
614 /* Primary Side. */
615 float v01[3], v12[3], v23[3], v30[3];
616 mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
617 mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
618 mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
619 mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
620 /* Secondary Side. */
621 float v45[3], v56[3], v67[3], v74[3];
622 mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
623 mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
624 mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
625 mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
626 /* Edges between. */
627 float v04[3], v15[3], v26[3], v37[3];
628 mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
629 mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
630 mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
631 mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
632
633 draw_circle_in_quad(v01, v45, v67, v23, 32, color);
634 draw_circle_in_quad(v30, v12, v56, v74, 32, color);
635 draw_circle_in_quad(v04, v15, v26, v37, 32, color);
636 }
637}
638
639static void draw_primitive_view(const bContext *C, ARegion * /*region*/, void *arg)
640{
641 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(arg);
642 float color[4];
644
645 const bool use_depth = !XRAY_ENABLED(ipd->v3d);
646 const eGPUDepthTest depth_test_enabled = GPU_depth_test_get();
647
648 if (use_depth) {
650 color[3] = 0.15f;
651 draw_primitive_view_impl(C, ipd, color, -1);
652 }
653
654 /* Show a flattened projection if the current step is aligned to the view. */
656 const RegionView3D *rv3d = static_cast<const RegionView3D *>(ipd->region->regiondata);
657 if (!rv3d->is_persp) {
658 draw_primitive_view_impl(C, ipd, color, ipd->step_index);
659 }
660 }
661
662 if (use_depth) {
664 }
665 color[3] = 1.0f;
666 draw_primitive_view_impl(C, ipd, color, -1);
667
668 if (use_depth) {
669 if (depth_test_enabled == false) {
671 }
672 }
673}
674
677/* -------------------------------------------------------------------- */
684 const wmEvent * /*event*/,
685 float r_co_src[3],
686 float r_matrix_orient[3][3],
687 bool *r_is_enabled,
688 bool *r_is_snap_invert)
689{
691 copy_v3_v3(r_co_src, snap_data->loc);
692 if (r_matrix_orient) {
693 copy_m3_m3(r_matrix_orient, snap_data->plane_omat);
694 }
695 if (r_is_enabled) {
696 *r_is_enabled = snap_data->is_enabled;
697 }
698 if (r_is_snap_invert) {
699 *r_is_snap_invert = snap_data->is_snap_invert;
700 }
701 return snap_data->type_target != SCE_SNAP_TO_NONE;
702}
703
706/* -------------------------------------------------------------------- */
710static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
711{
713 ToolSettings *tool_settings = CTX_data_tool_settings(C);
714
715 const int plane_axis = tool_settings->plane_axis;
716
717 const enum ePlace_Origin plane_origin[2] = {
718 ePlace_Origin(RNA_enum_get(op->ptr, "plane_origin_base")),
719 ePlace_Origin(RNA_enum_get(op->ptr, "plane_origin_depth")),
720 };
721 const enum ePlace_Aspect plane_aspect[2] = {
722 ePlace_Aspect(RNA_enum_get(op->ptr, "plane_aspect_base")),
723 ePlace_Aspect(RNA_enum_get(op->ptr, "plane_aspect_depth")),
724 };
725
726 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
727
729
731 if (snap_state_new) {
732 ipd->snap_state = snap_state = snap_state_new;
733
734 /* For drag events, update the location since it will be set from the drag-start.
735 * This is needed as cursor-drawing doesn't deal with drag events and will use
736 * the current cursor location instead of the drag-start. */
737 if (event->val == KM_CLICK_DRAG) {
738 /* Set this flag so snapping always updated. */
739 int mval[2];
740 WM_event_drag_start_mval(event, ipd->region, mval);
741
742 /* Be sure to also compute the #V3DSnapCursorData.plane_omat. */
743 snap_state->draw_plane = true;
744
745 ED_view3d_cursor_snap_data_update(snap_state_new, C, ipd->region, mval[0], mval[1]);
746 }
747 }
748
749 snap_state->draw_point = true;
750 snap_state->draw_plane = true;
751 ipd->is_snap_found =
753 C, event, ipd->co_src, ipd->matrix_orient, &ipd->use_snap, &ipd->is_snap_invert) != 0;
754
755 snap_state->draw_plane = false;
757
758 ipd->orient_axis = plane_axis;
759 for (int i = 0; i < 2; i++) {
760 ipd->step[i].is_centered_init = (plane_origin[i] == PLACE_ORIGIN_CENTER);
761 ipd->step[i].is_centered = ipd->step[i].is_centered_init;
762
763 ipd->step[i].is_fixed_aspect_init = (plane_aspect[i] == PLACE_ASPECT_FIXED);
765 }
766
767 ipd->step_index = STEP_BASE;
768
769 ipd->snap_to_ptr = &tool_settings->snap_mode_tools;
770 if (eSnapMode(*ipd->snap_to_ptr) == SCE_SNAP_TO_NONE) {
771 ipd->snap_to_ptr = &tool_settings->snap_mode;
772 }
774
775 plane_from_point_normal_v3(ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[plane_axis]);
776
777 copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
778
779 {
780 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
781 const float view_axis_dot = fabsf(dot_v3v3(rv3d->viewinv[2], ipd->matrix_orient[plane_axis]));
783 ipd->step[STEP_DEPTH].is_degenerate_view_align = fabsf(view_axis_dot - 1.0f) < eps_view_align;
784
785 float view_axis[3];
786 normalize_v3_v3(view_axis, rv3d->viewinv[2]);
787 plane_from_point_normal_v3(ipd->view_plane, ipd->co_src, view_axis);
788 }
789
792 {
793 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
794 float axis_view[3];
795 add_v3_v3v3(axis_view, rv3d->viewinv[0], rv3d->viewinv[1]);
796 normalize_v3(axis_view);
797
798 /* Setup fallback axes. */
799 for (int i = 0; i < 2; i++) {
800 if (ipd->step[i].is_degenerate_view_align) {
801 const int degenerate_axis =
802 (i == STEP_BASE) ?
803 /* For #STEP_BASE find the orient axis that align to the view. */
804 dot_v3_array_find_max_index(ipd->matrix_orient, 3, rv3d->viewinv[2], false) :
805 /* For #STEP_DEPTH the orient axis is always view aligned when degenerate. */
806 ipd->orient_axis;
807
808 float axis_fallback[4][3];
809 const int x_axis = (degenerate_axis + 1) % 3;
810 const int y_axis = (degenerate_axis + 2) % 3;
811
812 /* Assign 4x diagonal axes, find which one is closest to the viewport diagonal
813 * bottom left to top right, for a predictable direction from a user perspective. */
814 add_v3_v3v3(axis_fallback[0], ipd->matrix_orient[x_axis], ipd->matrix_orient[y_axis]);
815 sub_v3_v3v3(axis_fallback[1], ipd->matrix_orient[x_axis], ipd->matrix_orient[y_axis]);
816 negate_v3_v3(axis_fallback[2], axis_fallback[0]);
817 negate_v3_v3(axis_fallback[3], axis_fallback[1]);
818
819 const int axis_best = dot_v3_array_find_max_index(axis_fallback, 4, axis_view, true);
820 normalize_v3_v3(ipd->step[i].degenerate_diagonal, axis_fallback[axis_best]);
821 ipd->step[i].degenerate_axis = degenerate_axis;
822
823 /* `degenerate_view_plane_fallback` is used to map cursor motion from a view aligned
824 * plane back onto the view aligned plane.
825 *
826 * The dot product check below ensures cursor motion
827 * isn't inverted from a user perspective. */
828 const bool degenerate_axis_is_flip = dot_v3v3(ipd->matrix_orient[degenerate_axis],
829 ((i == STEP_BASE) ?
830 ipd->step[i].degenerate_diagonal :
831 rv3d->viewinv[2])) < 0.0f;
832
834 if (degenerate_axis_is_flip) {
836 }
837 }
838 }
839 }
840
843
845
846 /* Setup the primitive type. */
847 {
848 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
849 if (RNA_property_is_set(op->ptr, prop)) {
851 ipd->use_tool = false;
852 }
853 else {
854 ipd->use_tool = true;
855
856 /* Get from the tool, a bit of a non-standard way of operating. */
857 const bToolRef *tref = ipd->area->runtime.tool;
858 if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
860 }
861 else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
863 }
864 else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
866 }
867 else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
869 }
870 else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
872 }
873 else {
874 /* If the user runs this as an operator they should set the 'primitive_type',
875 * however running from operator search will end up at this point. */
877 ipd->use_tool = false;
878 }
879 }
880 }
881}
882
884{
885 const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
886
887 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(
888 MEM_callocN(sizeof(*ipd), __func__));
889 op->customdata = ipd;
890
891 ipd->scene = CTX_data_scene(C);
892 ipd->area = CTX_wm_area(C);
893 ipd->region = CTX_wm_region(C);
894 ipd->v3d = CTX_wm_view3d(C);
895
896 if (wait_for_input) {
897 ipd->wait_for_input = true;
898/* TODO: support snapping when not using with tool. */
899#if 0
901#endif
902 }
903 else {
904 view3d_interactive_add_begin(C, op, event);
905 }
906
908
910}
911
913{
914 UNUSED_VARS(C);
915
916 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
918
919 if (ipd->region != nullptr) {
920 if (ipd->draw_handle_view != nullptr) {
922 }
924 }
925
926 MEM_freeN(ipd);
927}
928
933
934enum {
941};
942
944{
945 static const EnumPropertyItem modal_items[] = {
946 {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
947 {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
948 {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
949 {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
950 {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
951 {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
952 {0, nullptr, 0, nullptr, nullptr},
953 };
954
955 const char *keymap_name = "View3D Placement Modal";
956 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
957
958 /* This function is called for each space-type, only needs to add map once. */
959 if (keymap && keymap->modal_items) {
960 return;
961 }
962
963 keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
964
965 WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
966}
967
969{
970 UNUSED_VARS(C, op);
971
972 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
973
974 ARegion *region = ipd->region;
975 bool do_redraw = false;
976 bool do_cursor_update = false;
977
978 /* Handle modal key-map. */
979 if (event->type == EVT_MODAL_MAP) {
980 bool is_fallthrough = false;
981 switch (event->val) {
983 is_fallthrough = true;
985 }
987 ipd->step[ipd->step_index].is_fixed_aspect =
988 is_fallthrough ^ ipd->step[ipd->step_index].is_fixed_aspect_init;
989 do_redraw = true;
990 break;
991 }
993 is_fallthrough = true;
995 }
997 ipd->step[ipd->step_index].is_centered = is_fallthrough ^
999 do_redraw = true;
1000 break;
1001 }
1002 case PLACE_MODAL_SNAP_ON: {
1003 is_fallthrough = true;
1005 }
1006 case PLACE_MODAL_SNAP_OFF: {
1007 const ToolSettings *ts = ipd->scene->toolsettings;
1008 ipd->is_snap_invert = is_fallthrough;
1009 ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
1010 do_cursor_update = true;
1011 break;
1012 }
1013 }
1014 }
1015 else {
1016 switch (event->type) {
1017 case EVT_ESCKEY:
1018 case RIGHTMOUSE: {
1020 return OPERATOR_CANCELLED;
1021 }
1022 case MOUSEMOVE: {
1023 do_cursor_update = true;
1024 break;
1025 }
1026 }
1027 }
1028
1029 if (ipd->wait_for_input) {
1030 if (ELEM(event->type, LEFTMOUSE)) {
1031 if (event->val == KM_PRESS) {
1032 view3d_interactive_add_begin(C, op, event);
1033 ipd->wait_for_input = false;
1035 }
1036 }
1038 }
1039
1040 if (ipd->step_index == STEP_BASE) {
1041 if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
1042 if (event->val == KM_RELEASE) {
1044 if (ipd->snap_to_restore & SCE_SNAP_TO_GRID) {
1045 /* Don't snap to grid in #STEP_DEPTH. */
1046 *ipd->snap_to_ptr = ipd->snap_to_restore & ~SCE_SNAP_TO_GRID;
1047 }
1048
1049 /* Set secondary plane. */
1050
1051 /* Create normal. */
1052 {
1053 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1054 float no[3], no_temp[3];
1055
1057 cross_v3_v3v3(no_temp, ipd->step[0].plane, ipd->step[STEP_DEPTH].degenerate_diagonal);
1058 cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
1059 }
1060 else {
1061 cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
1062 cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
1063 }
1064 normalize_v3(no);
1065
1066 plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
1067 }
1068
1069 copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
1070 ipd->step_index = STEP_DEPTH;
1071
1072 /* Use the toggle from the previous step. */
1073 if (ipd->step[0].is_centered != ipd->step[0].is_centered_init) {
1074 ipd->step[1].is_centered = !ipd->step[1].is_centered;
1075 }
1076 if (ipd->step[0].is_fixed_aspect != ipd->step[0].is_fixed_aspect_init) {
1077 ipd->step[1].is_fixed_aspect = !ipd->step[1].is_fixed_aspect;
1078 }
1079 }
1080 }
1081 }
1082 else if (ipd->step_index == STEP_DEPTH) {
1083 if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
1084 if (event->val == KM_PRESS) {
1085 /* Restore snap mode. */
1086 *ipd->snap_to_ptr = ipd->snap_to_restore;
1087
1088 /* Confirm. */
1090 calc_bbox(ipd, &bounds);
1091
1092 float location[3];
1093 float rotation[3];
1094 float scale[3];
1095
1096 float matrix_orient_axis[3][3];
1097 copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
1098 if (ipd->orient_axis != 2) {
1099 swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
1100 swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
1101 }
1102 /* Needed for shapes where the sign matters (cone for eg). */
1103 {
1104 float delta[3];
1105 sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
1106 if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
1107 negate_v3(matrix_orient_axis[2]);
1108
1109 /* Only flip Y so we don't flip a single axis which causes problems. */
1110 negate_v3(matrix_orient_axis[1]);
1111 }
1112 }
1113
1114 mat3_to_eul(rotation, matrix_orient_axis);
1115
1116 mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
1117 const int cube_verts[3] = {3, 1, 4};
1118 for (int i = 0; i < 3; i++) {
1119 scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
1120 /* Primitives have size 2 by default, compensate for this here. */
1121 scale[i] /= 2.0f;
1122 }
1123
1124 wmOperatorType *ot = nullptr;
1125 PointerRNA op_props;
1127 ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
1128 }
1130 ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
1131 }
1132 else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
1133 ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
1134 }
1136 ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
1137 }
1139 ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
1140 }
1141
1142 if (ot != nullptr) {
1144
1145 if (ipd->use_tool) {
1146 bToolRef *tref = ipd->area->runtime.tool;
1147 PointerRNA temp_props;
1148 WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
1149 std::swap(temp_props, op_props);
1150 WM_operator_properties_free(&temp_props);
1151 }
1152
1153 RNA_float_set_array(&op_props, "rotation", rotation);
1154 RNA_float_set_array(&op_props, "location", location);
1155 RNA_float_set_array(&op_props, "scale", scale);
1156
1157 /* Always use the defaults here since desired bounds have been set interactively, it does
1158 * not make sense to use a different values from a previous command. */
1160 RNA_float_set(&op_props, "size", 2.0f);
1161 }
1162 if (ELEM(ipd->primitive_type,
1166 {
1167 RNA_float_set(&op_props, "radius", 1.0f);
1168 }
1170 {
1171 RNA_float_set(&op_props, "depth", 2.0f);
1172 }
1174 RNA_float_set(&op_props, "radius1", 1.0f);
1175 RNA_float_set(&op_props, "radius2", 0.0f);
1176 }
1177
1178 WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props, nullptr);
1179 WM_operator_properties_free(&op_props);
1180 }
1181 else {
1182 BLI_assert(0);
1183 }
1184
1186 return OPERATOR_FINISHED;
1187 }
1188 }
1189 }
1190 else {
1191 BLI_assert(0);
1192 }
1193
1194 if (do_cursor_update) {
1195 float mval_fl[2];
1196 WM_event_drag_start_mval_fl(event, region, mval_fl);
1197
1198 /* Calculate the snap location on mouse-move or when toggling snap. */
1199 ipd->is_snap_found = false;
1200 if (ipd->use_snap) {
1202 C, event, ipd->snap_co, nullptr, nullptr, nullptr);
1203 }
1204
1205 if (ipd->step_index == STEP_BASE) {
1206 if (ipd->is_snap_found) {
1208 ipd->step[STEP_BASE].co_dst, ipd->step[STEP_BASE].plane, ipd->snap_co);
1209 }
1210 else {
1212 region,
1213 ipd->step[STEP_BASE].plane,
1214 mval_fl,
1215 ipd->step[STEP_BASE].is_degenerate_view_align ? ipd->view_plane : nullptr,
1216 ipd->step[STEP_BASE].co_dst))
1217 {
1218 /* pass */
1219 }
1220
1223 ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_BASE].co_dst))
1224 {
1225 }
1226 }
1227 }
1228 }
1229 else if (ipd->step_index == STEP_DEPTH) {
1230 if (ipd->is_snap_found) {
1232 ipd->step[STEP_DEPTH].co_dst, ipd->step[STEP_DEPTH].plane, ipd->snap_co);
1233 }
1234 else {
1236 region,
1237 ipd->step[STEP_DEPTH].plane,
1238 mval_fl,
1239 ipd->step[STEP_DEPTH].is_degenerate_view_align ? ipd->view_plane : nullptr,
1240 ipd->step[STEP_DEPTH].co_dst))
1241 {
1242 /* pass */
1243 }
1244
1247 ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_DEPTH].co_dst))
1248 {
1249 }
1250 }
1251 }
1252
1253 /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
1254 float close[3], delta[3];
1256 close, ipd->step[STEP_BASE].plane, ipd->step[STEP_DEPTH].co_dst);
1257 sub_v3_v3v3(delta, close, ipd->step[STEP_BASE].co_dst);
1258 sub_v3_v3(ipd->step[STEP_DEPTH].co_dst, delta);
1259 }
1260 do_redraw = true;
1261 }
1262
1263 if (do_redraw) {
1264 ED_region_tag_redraw(region);
1265 }
1266
1268}
1269
1271{
1272 const enum eContextObjectMode mode = CTX_data_mode_enum(C);
1274}
1275
1277{
1278 /* identifiers */
1279 ot->name = "Add Primitive Object";
1280 ot->description = "Interactively add an object";
1281 ot->idname = "VIEW3D_OT_interactive_add";
1282
1283 /* api callbacks */
1288
1289 /* NOTE: let the operator we call handle undo and registering itself. */
1290 /* flags */
1291 ot->flag = 0;
1292
1293 /* properties */
1294 PropertyRNA *prop;
1295
1296 /* Normally not accessed directly, leave unset and check the active tool. */
1297 static const EnumPropertyItem primitive_type[] = {
1298 {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
1299 {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
1300 {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
1301 {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
1302 {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
1303 {0, nullptr, 0, nullptr, nullptr},
1304 };
1305
1306 prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
1307 RNA_def_property_ui_text(prop, "Primitive", "");
1308 RNA_def_property_enum_items(prop, primitive_type);
1310
1311 { /* Plane Origin. */
1312 static const EnumPropertyItem items[] = {
1313 {PLACE_ORIGIN_BASE, "EDGE", 0, "Edge", "Start placing the edge position"},
1314 {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
1315 {0, nullptr, 0, nullptr, nullptr},
1316 };
1317 const char *identifiers[2] = {"plane_origin_base", "plane_origin_depth"};
1318 for (int i = 0; i < 2; i++) {
1319 prop = RNA_def_property(ot->srna, identifiers[i], PROP_ENUM, PROP_NONE);
1320 RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
1322 RNA_def_property_enum_items(prop, items);
1324 }
1325 }
1326
1327 { /* Plane Aspect. */
1328 static const EnumPropertyItem items[] = {
1329 {PLACE_ASPECT_FREE, "FREE", 0, "Free", "Use an unconstrained aspect"},
1330 {PLACE_ASPECT_FIXED, "FIXED", 0, "Fixed", "Use a fixed 1:1 aspect"},
1331 {0, nullptr, 0, nullptr, nullptr},
1332 };
1333 const char *identifiers[2] = {"plane_aspect_base", "plane_aspect_depth"};
1334 for (int i = 0; i < 2; i++) {
1335 prop = RNA_def_property(ot->srna, identifiers[i], PROP_ENUM, PROP_NONE);
1336 RNA_def_property_ui_text(prop, "Aspect", "The initial aspect setting");
1338 RNA_def_property_enum_items(prop, items);
1340 }
1341 }
1342
1343 /* When not accessed via a tool. */
1344 prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1346}
1347
1350/* -------------------------------------------------------------------- */
1357static void preview_plane_free_fn(void *customdata)
1358{
1359 V3DSnapCursorState *snap_state = static_cast<V3DSnapCursorState *>(customdata);
1361}
1362
1363static bool snap_cursor_poll(ARegion *region, void *data)
1364{
1365 if (WM_gizmomap_group_find_ptr(region->gizmo_map, (wmGizmoGroupType *)data) == nullptr) {
1366 /* Wrong viewport. */
1367 return false;
1368 }
1369 return true;
1370}
1371
1372static void WIDGETGROUP_placement_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
1373{
1375 if (snap_state) {
1376 snap_state->poll = snap_cursor_poll;
1377 snap_state->poll_data = gzgroup->type;
1378 snap_state->draw_plane = true;
1379
1380 gzgroup->customdata = snap_state;
1382 }
1383}
1384
1398
eContextObjectMode
@ CTX_MODE_OBJECT
@ CTX_MODE_EDIT_MESH
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
enum eContextObjectMode CTX_data_mode_enum(const bContext *C)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
MINLINE float max_ff(float a, float b)
#define M_PI
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition math_geom.cc:215
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:440
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:493
void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const float v3[2], const float v4[2], const float co[2], float w[4])
void mul_m3_v3(const float M[3][3], float r[3])
void copy_m3_m3(float m1[3][3], const float m2[3][3])
bool invert_m3_m3(float inverse[3][3], const float mat[3][3])
void mat3_to_eul(float eul[3], const float mat[3][3])
void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void negate_v3_v3(float r[3], const float a[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void negate_v3(float r[3])
MINLINE float normalize_v3_v3(float r[3], const float a[3])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void swap_v3_v3(float a[3], float b[3])
MINLINE void zero_v3(float r[3])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3_length(float n[3], float unit_length)
MINLINE float normalize_v3(float n[3])
unsigned int uint
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
#define UNUSED_VARS(...)
#define UNUSED_FUNCTION_WITH_RETURN_TYPE(rtype, x)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
@ SCE_SNAP
@ SCE_SNAP_TO_INCREMENT
@ SCE_SNAP_TO_GRID
@ SCE_SNAP_TO_NONE
@ RGN_TYPE_WINDOW
@ SPACE_VIEW3D
@ OPERATOR_RUNNING_MODAL
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
void * ED_region_draw_cb_activate(ARegionType *art, void(*draw)(const bContext *, ARegion *, void *), void *customdata, int type)
#define REGION_DRAW_POST_VIEW
bool ED_region_draw_cb_exit(ARegionType *art, void *handle)
void ED_view3d_cursor_snap_data_update(V3DSnapCursorState *state, const bContext *C, const ARegion *region, int x, int y)
V3DSnapCursorState * ED_view3d_cursor_snap_state_create()
#define XRAY_ENABLED(v3d)
float ED_view3d_grid_view_scale(const Scene *scene, const View3D *v3d, const ARegion *region, const char **r_grid_unit)
V3DSnapCursorState * ED_view3d_cursor_snap_state_active_get()
void ED_view3d_cursor_snap_state_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3])
void ED_view3d_cursor_snap_state_free(V3DSnapCursorState *state)
bool ED_view3d_win_to_3d_on_plane(const ARegion *region, const float plane[4], const float mval[2], bool do_clip, float r_out[3])
bool ED_view3d_win_to_3d_on_plane_with_fallback(const ARegion *region, const float plane[4], const float mval[2], bool do_clip, const float plane_fallback[4], float r_out[3])
V3DSnapCursorData * ED_view3d_cursor_snap_data_get()
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
#define GPU_batch_uniform_1f(batch, name, x)
Definition GPU_batch.hh:299
void GPU_batch_discard(blender::gpu::Batch *batch)
#define GPU_batch_uniform_2fv(batch, name, val)
Definition GPU_batch.hh:305
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, eGPUBuiltinShader shader_id)
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:307
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
GPUVertFormat * immVertexFormat()
@ GPU_PRIM_LINE_LOOP
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(eGPUBlend blend)
Definition gpu_state.cc:42
eGPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:239
eGPUDepthTest
Definition GPU_state.hh:107
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:111
@ GPU_DEPTH_NONE
Definition GPU_state.hh:108
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_attr_set(blender::gpu::VertBuf *, uint a_idx, uint v_idx, const void *data)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
@ PROP_ENUM
Definition RNA_types.hh:69
@ PROP_SKIP_SAVE
Definition RNA_types.hh:245
@ PROP_HIDDEN
Definition RNA_types.hh:239
@ PROP_NONE
Definition RNA_types.hh:136
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_GIZMO_PRIMARY
@ WM_GIZMOGROUPTYPE_SCALE
@ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL
@ WM_GIZMOGROUPTYPE_3D
@ KM_PRESS
Definition WM_types.hh:284
@ KM_CLICK_DRAG
Definition WM_types.hh:292
@ KM_RELEASE
Definition WM_types.hh:285
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define sinf(x)
#define cosf(x)
#define copysignf(x, y)
#define fabsf(x)
draw_view in_light_buf[] float
struct @620::@622 batch
blender::gpu::Batch * quad
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
int RNA_enum_get(PointerRNA *ptr, const char *name)
void RNA_def_property_enum_default(PropertyRNA *prop, int value)
void RNA_def_property_ui_text(PropertyRNA *prop, const char *name, const char *description)
void RNA_def_property_enum_items(PropertyRNA *prop, const EnumPropertyItem *item)
PropertyRNA * RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier, int type, int subtype)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void * regiondata
struct ARegionType * type
enum ePlace_PrimType primitive_type
struct InteractivePlaceData::@554 step[2]
V3DSnapCursorState * snap_state
float viewinv[4][4]
struct ToolSettings * toolsettings
struct bToolRef * tool
ScrArea_Runtime runtime
eSnapMode type_target
Definition ED_view3d.hh:327
float plane_omat[3][3]
Definition ED_view3d.hh:332
bool(* poll)(ARegion *region, void *custom_poll_data)
Definition ED_view3d.hh:351
short val
Definition WM_types.hh:724
short type
Definition WM_types.hh:722
wmGizmoGroupFnInit setup
const char * idname
wmGizmoMapType_Params gzmap_params
eWM_GizmoFlagGroupTypeFlag flag
wmGizmoGroupFnPoll poll
void(* customdata_free)(void *)
wmGizmoGroupType * type
const void * modal_items
const char * name
Definition WM_types.hh:990
bool(* poll)(bContext *C) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1042
const char * idname
Definition WM_types.hh:992
int(* modal)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1036
int(* invoke)(bContext *C, wmOperator *op, const wmEvent *event) ATTR_WARN_UNUSED_RESULT
Definition WM_types.hh:1022
const char * description
Definition WM_types.hh:996
StructRNA * srna
Definition WM_types.hh:1080
void(* cancel)(bContext *C, wmOperator *op)
Definition WM_types.hh:1028
struct PointerRNA * ptr
static int dot_v3_array_find_max_index(const float dirs[][3], const int dirs_len, const float dir_test[3], bool is_signed)
static bool calc_bbox(InteractivePlaceData *ipd, BoundBox *bounds)
static void draw_line_pairs(const float coords_a[][3], float coords_b[][3], int coords_len, const float color[4])
ePlace_PrimType
@ PLACE_PRIMITIVE_TYPE_SPHERE_ICO
@ PLACE_PRIMITIVE_TYPE_CONE
@ PLACE_PRIMITIVE_TYPE_CUBE
@ PLACE_PRIMITIVE_TYPE_SPHERE_UV
@ PLACE_PRIMITIVE_TYPE_CYLINDER
static const char * view3d_gzgt_placement_id
static bool view3d_win_to_3d_on_plane_maybe_fallback(const ARegion *region, const float plane[4], const float mval[2], const float *plane_fallback, float r_out[3])
static void draw_line_loop(const float coords[][3], int coords_len, const float color[4])
static void draw_line_bounds(const BoundBox *bounds, const float color[4])
static const float eps_view_align
static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
static bool idp_snap_calc_incremental(Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3])
@ STEP_DEPTH
@ STEP_BASE
static void draw_circle_in_quad(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const int resolution, const float color[4])
static bool view3d_interactive_add_poll(bContext *C)
@ PLACE_MODAL_FIXED_ASPECT_OFF
@ PLACE_MODAL_FIXED_ASPECT_ON
@ PLACE_MODAL_SNAP_OFF
@ PLACE_MODAL_SNAP_ON
@ PLACE_MODAL_PIVOT_CENTER_OFF
@ PLACE_MODAL_PIVOT_CENTER_ON
static void preview_plane_free_fn(void *customdata)
static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
ePlace_Origin
@ PLACE_ORIGIN_BASE
@ PLACE_ORIGIN_CENTER
static void WIDGETGROUP_placement_setup(const bContext *, wmGizmoGroup *gzgroup)
void VIEW3D_OT_interactive_add(wmOperatorType *ot)
static void draw_primitive_view(const bContext *C, ARegion *, void *arg)
static int view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void view3d_interactive_add_exit(bContext *C, wmOperator *op)
static bool view3d_interactive_add_calc_snap(bContext *, const wmEvent *, float r_co_src[3], float r_matrix_orient[3][3], bool *r_is_enabled, bool *r_is_snap_invert)
static bool snap_cursor_poll(ARegion *region, void *data)
static void draw_primitive_view_impl(const bContext *C, InteractivePlaceData *ipd, const float color[4], int flatten_axis)
static void view3d_interactive_add_begin(bContext *C, wmOperator *op, const wmEvent *event)
void viewplace_modal_keymap(wmKeyConfig *keyconf)
ePlace_Aspect
@ PLACE_ASPECT_FIXED
@ PLACE_ASPECT_FREE
void WM_event_drag_start_mval_fl(const wmEvent *event, const ARegion *region, float r_mval[2])
void WM_event_drag_start_mval(const wmEvent *event, const ARegion *region, int r_mval[2])
int WM_userdef_event_type_from_keymap_type(int kmitype)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ MOUSEMOVE
@ LEFTMOUSE
@ EVT_ESCKEY
wmOperatorType * ot
Definition wm_files.cc:4125
bool WM_gizmo_group_type_ensure(const char *idname)
wmGizmoGroup * WM_gizmomap_group_find_ptr(wmGizmoMap *gzmap, const wmGizmoGroupType *gzgt)
wmGizmoGroup * WM_gizmomap_group_find(wmGizmoMap *gzmap, const char *idname)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:933
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:960
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
void WM_toolsystem_ref_properties_init_for_keymap(bToolRef *tref, PointerRNA *dst_ptr, PointerRNA *src_ptr, wmOperatorType *ot)