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
13
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/* -------------------------------------------------------------------- */
50
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
164
165/* -------------------------------------------------------------------- */
168
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
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
250
251/* -------------------------------------------------------------------- */
254
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
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
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
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
532
533/* -------------------------------------------------------------------- */
536
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
584
586 /* pass */
587 }
591 }
592 else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
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;
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) {
659 }
660 }
661
662 if (use_depth) {
664 }
665 color[3] = 1.0f;
667
668 if (use_depth) {
669 if (depth_test_enabled == false) {
671 }
672 }
673}
674
676
677/* -------------------------------------------------------------------- */
682
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
705
706/* -------------------------------------------------------------------- */
709
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 {
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. */
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
1349
1350/* -------------------------------------------------------------------- */
1356
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.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
@ 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
#define C
Definition RandGen.cpp:29
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_GIZMO_PRIMARY
@ WM_GIZMOGROUPTYPE_SCALE
@ WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL
@ WM_GIZMOGROUPTYPE_3D
@ WM_OP_EXEC_DEFAULT
Definition WM_types.hh:225
@ KM_PRESS
Definition WM_types.hh:284
@ KM_CLICK_DRAG
Definition WM_types.hh:292
@ KM_RELEASE
Definition WM_types.hh:285
#define U
ATTR_WARN_UNUSED_RESULT const BMVert * v2
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
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
blender::gpu::Batch * quad
struct @157336070235062372277311340362362342103123126032::@262166344314164341202215145112231240022370055142 batch
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)
static bool snap_cursor_poll(ARegion *region, void *data)
void * regiondata
struct wmGizmoMap * gizmo_map
struct ARegionType * type
enum ePlace_PrimType primitive_type
struct InteractivePlaceData::@034017351343133047004175364132332026014162110035 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:336
float plane_omat[3][3]
Definition ED_view3d.hh:341
bool(* poll)(ARegion *region, void *custom_poll_data)
Definition ED_view3d.hh:360
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
struct PointerRNA * ptr
static const float eps_view_align
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
@ 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 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 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)
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)