Blender V5.0
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_geom.h"
17#include "BLI_math_matrix.h"
18#include "BLI_math_rotation.h"
19
20#include "BKE_context.hh"
21#include "BKE_lib_id.hh"
22#include "BKE_screen.hh"
23
24#include "RNA_access.hh"
25#include "RNA_define.hh"
26
27#include "WM_api.hh"
28#include "WM_toolsystem.hh"
29
30#include "ED_gizmo_utils.hh"
31#include "ED_screen.hh"
32#include "ED_space_api.hh"
33#include "ED_view3d.hh"
34
35#include "UI_resources.hh"
36
37#include "GPU_immediate.hh"
38#include "GPU_state.hh"
39
40#include "view3d_intern.hh"
41
42static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement";
43
49static const float eps_view_align = 1e-2f;
50
51/* -------------------------------------------------------------------- */
54
62
67
72
76};
77
79 /* Window manager variables (set these even when waiting for input). */
84
87
88 float co_src[3];
89
91 struct {
103 float plane[4];
104 float co_dst[3];
105
130
135
136 } step[2];
137
139 float view_plane[4];
140
141 float matrix_orient[3][3];
143
146 float snap_co[3];
147
150
152
155
158
161
162 /* WORKAROUND: We need to remove #SCE_SNAP_TO_GRID temporarily. */
165};
166
168
169/* -------------------------------------------------------------------- */
172
177 const float plane[4],
178 const float mval[2],
179 const float *plane_fallback,
180 float r_out[3])
181{
182 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
183 bool do_clip = rv3d->is_persp;
184 if (plane_fallback != nullptr) {
186 region, plane, mval, do_clip, plane_fallback, r_out);
187 }
188 return ED_view3d_win_to_3d_on_plane(region, plane, mval, do_clip, r_out);
189}
190
194static int dot_v3_array_find_max_index(const float dirs[][3],
195 const int dirs_len,
196 const float dir_test[3],
197 bool is_signed)
198{
199 int index_found = -1;
200 float dot_best = -1.0f;
201 for (int i = 0; i < dirs_len; i++) {
202 float dot_test = dot_v3v3(dirs[i], dir_test);
203 if (is_signed == false) {
204 dot_test = fabsf(dot_test);
205 }
206 if ((index_found == -1) || (dot_test > dot_best)) {
207 dot_best = dot_test;
208 index_found = i;
209 }
210 }
211 return index_found;
212}
213
215 idp_gizmogroup_from_region)(ARegion *region)
216{
217 wmGizmoMap *gzmap = region->runtime->gizmo_map;
218 return gzmap ? WM_gizmomap_group_find(gzmap, view3d_gzgt_placement_id) : nullptr;
219}
220
227 Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3])
228{
229 const float grid_size = ED_view3d_grid_view_scale(scene, v3d, region, nullptr);
230 if (UNLIKELY(grid_size == 0.0f)) {
231 return false;
232 }
233
235 co_relative = nullptr;
236 }
237
238 if (co_relative != nullptr) {
239 sub_v3_v3(co, co_relative);
240 }
241 mul_v3_fl(co, 1.0f / grid_size);
242 co[0] = roundf(co[0]);
243 co[1] = roundf(co[1]);
244 co[2] = roundf(co[2]);
245 mul_v3_fl(co, grid_size);
246 if (co_relative != nullptr) {
247 add_v3_v3(co, co_relative);
248 }
249
250 return true;
251}
252
254
255/* -------------------------------------------------------------------- */
258
259static void draw_line_loop(const float coords[][3], int coords_len, const float color[4])
260{
262 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
263
265 GPU_vertbuf_data_alloc(*vert, coords_len);
266
267 for (int i = 0; i < coords_len; i++) {
268 GPU_vertbuf_attr_set(vert, pos, i, coords[i]);
269 }
270
272 blender::gpu::Batch *batch = GPU_batch_create_ex(
273 GPU_PRIM_LINE_LOOP, vert, nullptr, GPU_BATCH_OWNS_VBO);
275
276 GPU_batch_uniform_4fv(batch, "color", color);
277
278 float viewport[4];
279 GPU_viewport_size_get_f(viewport);
280 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
281 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
282
284
287}
288
289static void draw_line_pairs(const float coords_a[][3],
290 float coords_b[][3],
291 int coords_len,
292 const float color[4])
293{
295 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
296
298 GPU_vertbuf_data_alloc(*vert, coords_len * 2);
299
300 for (int i = 0; i < coords_len; i++) {
301 GPU_vertbuf_attr_set(vert, pos, i * 2, coords_a[i]);
302 GPU_vertbuf_attr_set(vert, pos, (i * 2) + 1, coords_b[i]);
303 }
304
306 blender::gpu::Batch *batch = GPU_batch_create_ex(
307 GPU_PRIM_LINES, vert, nullptr, GPU_BATCH_OWNS_VBO);
309
310 GPU_batch_uniform_4fv(batch, "color", color);
311
312 float viewport[4];
313 GPU_viewport_size_get_f(viewport);
314 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
315 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
316
318
321}
322
323static void draw_line_bounds(const BoundBox *bounds, const float color[4])
324{
326 uint pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32_32);
327
328 const int edges[12][2] = {
329 /* First side. */
330 {0, 1},
331 {1, 2},
332 {2, 3},
333 {3, 0}, /* Second side. */
334 {4, 5},
335 {5, 6},
336 {6, 7},
337 {7, 4}, /* Edges between. */
338 {0, 4},
339 {1, 5},
340 {2, 6},
341 {3, 7},
342 };
343
345 GPU_vertbuf_data_alloc(*vert, ARRAY_SIZE(edges) * 2);
346
347 for (int i = 0, j = 0; i < ARRAY_SIZE(edges); i++) {
348 GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][0]]);
349 GPU_vertbuf_attr_set(vert, pos, j++, bounds->vec[edges[i][1]]);
350 }
351
353 blender::gpu::Batch *batch = GPU_batch_create_ex(
354 GPU_PRIM_LINES, vert, nullptr, GPU_BATCH_OWNS_VBO);
356
357 GPU_batch_uniform_4fv(batch, "color", color);
358
359 float viewport[4];
360 GPU_viewport_size_get_f(viewport);
361 GPU_batch_uniform_2fv(batch, "viewportSize", &viewport[2]);
362 GPU_batch_uniform_1f(batch, "lineWidth", U.pixelsize);
363
365
368}
369
371{
372 *bounds = BoundBox{};
373
374 if (compare_v3v3(ipd->co_src, ipd->step[0].co_dst, FLT_EPSILON)) {
375 return false;
376 }
377
378 float matrix_orient_inv[3][3];
379 invert_m3_m3(matrix_orient_inv, ipd->matrix_orient);
380
381 const int x_axis = (ipd->orient_axis + 1) % 3;
382 const int y_axis = (ipd->orient_axis + 2) % 3;
383
384 float quad_base[4][3];
385 float quad_secondary[4][3];
386
387 copy_v3_v3(quad_base[0], ipd->co_src);
388 copy_v3_v3(quad_base[2], ipd->step[0].co_dst);
389
390 /* Only set when we have a fixed aspect. */
391 float fixed_aspect_dimension;
392
393 /* *** Primary *** */
394
395 {
396 float delta_local[3];
397 float delta_a[3];
398 float delta_b[3];
399
400 sub_v3_v3v3(delta_local, ipd->step[0].co_dst, ipd->co_src);
401 mul_m3_v3(matrix_orient_inv, delta_local);
402
403 copy_v3_v3(delta_a, delta_local);
404 copy_v3_v3(delta_b, delta_local);
405 delta_a[ipd->orient_axis] = 0.0f;
406 delta_b[ipd->orient_axis] = 0.0f;
407
408 delta_a[x_axis] = 0.0f;
409 delta_b[y_axis] = 0.0f;
410
411 /* Assign here in case secondary. */
412 fixed_aspect_dimension = max_ff(fabsf(delta_a[y_axis]), fabsf(delta_b[x_axis]));
413
414 if (ipd->step[0].is_fixed_aspect) {
415 delta_a[y_axis] = copysignf(fixed_aspect_dimension, delta_a[y_axis]);
416 delta_b[x_axis] = copysignf(fixed_aspect_dimension, delta_b[x_axis]);
417 }
418
419 mul_m3_v3(ipd->matrix_orient, delta_a);
420 mul_m3_v3(ipd->matrix_orient, delta_b);
421
422 if (ipd->step[0].is_fixed_aspect) {
423 /* Recalculate the destination point. */
424 copy_v3_v3(quad_base[2], ipd->co_src);
425 add_v3_v3(quad_base[2], delta_a);
426 add_v3_v3(quad_base[2], delta_b);
427 }
428
429 add_v3_v3v3(quad_base[1], ipd->co_src, delta_a);
430 add_v3_v3v3(quad_base[3], ipd->co_src, delta_b);
431 }
432
433 if (ipd->step[0].is_centered) {
434 /* Use a copy in case aspect was applied to the quad. */
435 float base_co_dst[3];
436 copy_v3_v3(base_co_dst, quad_base[2]);
437 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
438 sub_v3_v3(quad_base[i], base_co_dst);
439 mul_v3_fl(quad_base[i], 2.0f);
440 add_v3_v3(quad_base[i], base_co_dst);
441 }
442 fixed_aspect_dimension *= 2.0f;
443 }
444
445 /* *** Secondary *** */
446
447 float delta_local[3];
448 if (ipd->step_index == STEP_DEPTH) {
449 sub_v3_v3v3(delta_local, ipd->step[1].co_dst, ipd->step[0].co_dst);
450 }
451 else {
452 zero_v3(delta_local);
453 }
454
455 if (ipd->step[1].is_fixed_aspect) {
456 if (!is_zero_v3(delta_local)) {
457 normalize_v3_length(delta_local, fixed_aspect_dimension);
458 }
459 }
460
461 if (ipd->step[1].is_centered) {
462 float temp_delta[3];
463 if (ipd->step[1].is_fixed_aspect) {
464 mul_v3_v3fl(temp_delta, delta_local, 0.5f);
465 }
466 else {
467 copy_v3_v3(temp_delta, delta_local);
468 mul_v3_fl(delta_local, 2.0f);
469 }
470
471 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
472 sub_v3_v3(quad_base[i], temp_delta);
473 }
474 }
475
476 if ((ipd->step_index == STEP_DEPTH) &&
477 (compare_v3v3(ipd->step[0].co_dst, ipd->step[1].co_dst, FLT_EPSILON) == false))
478 {
479
480 for (int i = 0; i < ARRAY_SIZE(quad_base); i++) {
481 add_v3_v3v3(quad_secondary[i], quad_base[i], delta_local);
482 }
483 }
484 else {
485 copy_v3_v3(quad_secondary[0], quad_base[0]);
486 copy_v3_v3(quad_secondary[1], quad_base[1]);
487 copy_v3_v3(quad_secondary[2], quad_base[2]);
488 copy_v3_v3(quad_secondary[3], quad_base[3]);
489 }
490
491 for (int i = 0; i < 4; i++) {
492 copy_v3_v3(bounds->vec[i], quad_base[i]);
493 copy_v3_v3(bounds->vec[i + 4], quad_secondary[i]);
494 }
495
496 return true;
497}
498
499static void draw_circle_in_quad(const float v1[3],
500 const float v2[3],
501 const float v3[3],
502 const float v4[3],
503 const int resolution,
504 const float color[4])
505{
506 /* This isn't so efficient. */
507 const float quad[4][2] = {
508 {-1, -1},
509 {+1, -1},
510 {+1, +1},
511 {-1, +1},
512 };
513
514 float (*coords)[3] = static_cast<float (*)[3]>(
515 MEM_mallocN(sizeof(float[3]) * (resolution + 1), __func__));
516 for (int i = 0; i <= resolution; i++) {
517 float theta = ((2.0f * M_PI) * (float(i) / float(resolution))) + 0.01f;
518 float x = cosf(theta);
519 float y = sinf(theta);
520 const float pt[2] = {x, y};
521 float w[4];
523
524 float *co = coords[i];
525 zero_v3(co);
526 madd_v3_v3fl(co, v1, w[0]);
527 madd_v3_v3fl(co, v2, w[1]);
528 madd_v3_v3fl(co, v3, w[2]);
529 madd_v3_v3fl(co, v4, w[3]);
530 }
531 draw_line_loop(coords, resolution + 1, color);
532 MEM_freeN(coords);
533}
534
536
537/* -------------------------------------------------------------------- */
540
543 const float color[4],
544 int flatten_axis)
545{
546 UNUSED_VARS(C);
547
549 calc_bbox(ipd, &bounds);
550
551 /* Use cavalier projection, since it maps the scale usefully to the cursor. */
552 if (flatten_axis == STEP_BASE) {
553 /* Calculate the plane that would be defined by the side of the cube vertices
554 * if the plane had any volume. */
555
556 float no[3];
557
559 no, ipd->matrix_orient[ipd->orient_axis], ipd->matrix_orient[(ipd->orient_axis + 1) % 3]);
560
561 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
562 copy_v3_v3(no, rv3d->viewinv[2]);
563 normalize_v3(no);
564
565 float base_plane[4];
566
567 plane_from_point_normal_v3(base_plane, bounds.vec[0], no);
568
569 /* Offset all vertices even though we only need to offset the half of them.
570 * This is harmless as `dist` will be zero for the `base_plane` aligned side of the cube. */
571 for (int i = 0; i < ARRAY_SIZE(bounds.vec); i++) {
572 const float dist = dist_signed_to_plane_v3(bounds.vec[i], base_plane);
573 madd_v3_v3fl(bounds.vec[i], base_plane, -dist);
575 }
576 }
577
578 if (flatten_axis == STEP_DEPTH) {
579 const float *base_plane = ipd->step[0].plane;
580 for (int i = 0; i < 4; i++) {
581 const float dist = dist_signed_to_plane_v3(bounds.vec[i + 4], base_plane);
582 madd_v3_v3fl(bounds.vec[i + 4], base_plane, -dist);
584 }
585 }
586
587 draw_line_bounds(&bounds, color);
588
590 /* pass */
591 }
593 draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
594 draw_circle_in_quad(UNPACK4(&bounds.vec[4]), 32, color);
595 }
596 else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
597 draw_circle_in_quad(UNPACK4(bounds.vec), 32, color);
598
599 float center[3];
600 mid_v3_v3v3v3v3(center, UNPACK4(&bounds.vec[4]));
601
602 float coords_a[4][3];
603 float coords_b[4][3];
604
605 for (int i = 0; i < 4; i++) {
606 copy_v3_v3(coords_a[i], center);
607 mid_v3_v3v3(coords_b[i], bounds.vec[i], bounds.vec[(i + 1) % 4]);
608 }
609
610 draw_line_pairs(coords_a, coords_b, 4, color);
611 }
612 else if (ELEM(ipd->primitive_type,
615 {
616 /* See bound-box diagram for reference. */
617
618 /* Primary Side. */
619 float v01[3], v12[3], v23[3], v30[3];
620 mid_v3_v3v3(v01, bounds.vec[0], bounds.vec[1]);
621 mid_v3_v3v3(v12, bounds.vec[1], bounds.vec[2]);
622 mid_v3_v3v3(v23, bounds.vec[2], bounds.vec[3]);
623 mid_v3_v3v3(v30, bounds.vec[3], bounds.vec[0]);
624 /* Secondary Side. */
625 float v45[3], v56[3], v67[3], v74[3];
626 mid_v3_v3v3(v45, bounds.vec[4], bounds.vec[5]);
627 mid_v3_v3v3(v56, bounds.vec[5], bounds.vec[6]);
628 mid_v3_v3v3(v67, bounds.vec[6], bounds.vec[7]);
629 mid_v3_v3v3(v74, bounds.vec[7], bounds.vec[4]);
630 /* Edges between. */
631 float v04[3], v15[3], v26[3], v37[3];
632 mid_v3_v3v3(v04, bounds.vec[0], bounds.vec[4]);
633 mid_v3_v3v3(v15, bounds.vec[1], bounds.vec[5]);
634 mid_v3_v3v3(v26, bounds.vec[2], bounds.vec[6]);
635 mid_v3_v3v3(v37, bounds.vec[3], bounds.vec[7]);
636
637 draw_circle_in_quad(v01, v45, v67, v23, 32, color);
638 draw_circle_in_quad(v30, v12, v56, v74, 32, color);
639 draw_circle_in_quad(v04, v15, v26, v37, 32, color);
640 }
641}
642
643static void draw_primitive_view(const bContext *C, ARegion * /*region*/, void *arg)
644{
645 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(arg);
646 float color[4];
648
649 const bool use_depth = !XRAY_ENABLED(ipd->v3d);
650 const GPUDepthTest depth_test_enabled = GPU_depth_test_get();
651
652 if (use_depth) {
654 color[3] = 0.15f;
655 draw_primitive_view_impl(C, ipd, color, -1);
656 }
657
658 /* Show a flattened projection if the current step is aligned to the view. */
660 const RegionView3D *rv3d = static_cast<const RegionView3D *>(ipd->region->regiondata);
661 if (!rv3d->is_persp) {
662 draw_primitive_view_impl(C, ipd, color, ipd->step_index);
663 }
664 }
665
666 if (use_depth) {
668 }
669 color[3] = 1.0f;
670 draw_primitive_view_impl(C, ipd, color, -1);
671
672 if (use_depth) {
673 if (depth_test_enabled == false) {
675 }
676 }
677}
678
680
681/* -------------------------------------------------------------------- */
686
688 const wmEvent * /*event*/,
689 float r_co_src[3],
690 float r_matrix_orient[3][3],
691 bool *r_is_enabled,
692 bool *r_is_snap_invert)
693{
695 copy_v3_v3(r_co_src, snap_data->loc);
696 if (r_matrix_orient) {
697 copy_m3_m3(r_matrix_orient, snap_data->plane_omat);
698 }
699 if (r_is_enabled) {
700 *r_is_enabled = snap_data->is_enabled;
701 }
702 if (r_is_snap_invert) {
703 *r_is_snap_invert = snap_data->is_snap_invert;
704 }
705 return snap_data->type_target != SCE_SNAP_TO_NONE;
706}
707
709
710/* -------------------------------------------------------------------- */
713
715{
717 ToolSettings *tool_settings = CTX_data_tool_settings(C);
718
719 const int plane_axis = tool_settings->plane_axis;
720
721 const enum ePlace_Origin plane_origin[2] = {
722 ePlace_Origin(RNA_enum_get(op->ptr, "plane_origin_base")),
723 ePlace_Origin(RNA_enum_get(op->ptr, "plane_origin_depth")),
724 };
725 const enum ePlace_Aspect plane_aspect[2] = {
726 ePlace_Aspect(RNA_enum_get(op->ptr, "plane_aspect_base")),
727 ePlace_Aspect(RNA_enum_get(op->ptr, "plane_aspect_depth")),
728 };
729
730 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
731
733
735 if (snap_state_new) {
736 ipd->snap_state = snap_state = snap_state_new;
737
738 /* For drag events, update the location since it will be set from the drag-start.
739 * This is needed as cursor-drawing doesn't deal with drag events and will use
740 * the current cursor location instead of the drag-start. */
741 if (event->val == KM_PRESS_DRAG) {
742 /* Set this flag so snapping always updated. */
743 int mval[2];
744 WM_event_drag_start_mval(event, ipd->region, mval);
745
746 /* Be sure to also compute the #V3DSnapCursorData.plane_omat. */
747 snap_state->draw_plane = true;
748
749 ED_view3d_cursor_snap_data_update(snap_state_new, C, ipd->region, mval);
750 }
751 }
752
753 snap_state->draw_point = true;
754 snap_state->draw_plane = true;
755 ipd->is_snap_found =
757 C, event, ipd->co_src, ipd->matrix_orient, &ipd->use_snap, &ipd->is_snap_invert) != 0;
758
759 snap_state->draw_plane = false;
761
762 ipd->orient_axis = plane_axis;
763 for (int i = 0; i < 2; i++) {
764 ipd->step[i].is_centered_init = (plane_origin[i] == PLACE_ORIGIN_CENTER);
765 ipd->step[i].is_centered = ipd->step[i].is_centered_init;
766
767 ipd->step[i].is_fixed_aspect_init = (plane_aspect[i] == PLACE_ASPECT_FIXED);
769 }
770
771 ipd->step_index = STEP_BASE;
772
773 ipd->snap_to_ptr = &tool_settings->snap_mode_tools;
774 if (eSnapMode(*ipd->snap_to_ptr) == SCE_SNAP_TO_NONE) {
775 ipd->snap_to_ptr = &tool_settings->snap_mode;
776 }
778
779 plane_from_point_normal_v3(ipd->step[0].plane, ipd->co_src, ipd->matrix_orient[plane_axis]);
780
781 copy_v3_v3(ipd->step[0].co_dst, ipd->co_src);
782
783 {
784 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
785 const float view_axis_dot = fabsf(dot_v3v3(rv3d->viewinv[2], ipd->matrix_orient[plane_axis]));
787 ipd->step[STEP_DEPTH].is_degenerate_view_align = fabsf(view_axis_dot - 1.0f) < eps_view_align;
788
789 float view_axis[3];
790 normalize_v3_v3(view_axis, rv3d->viewinv[2]);
791 plane_from_point_normal_v3(ipd->view_plane, ipd->co_src, view_axis);
792 }
793
796 {
797 RegionView3D *rv3d = static_cast<RegionView3D *>(ipd->region->regiondata);
798 float axis_view[3];
799 add_v3_v3v3(axis_view, rv3d->viewinv[0], rv3d->viewinv[1]);
800 normalize_v3(axis_view);
801
802 /* Setup fallback axes. */
803 for (int i = 0; i < 2; i++) {
804 if (ipd->step[i].is_degenerate_view_align) {
805 const int degenerate_axis =
806 (i == STEP_BASE) ?
807 /* For #STEP_BASE find the orient axis that align to the view. */
808 dot_v3_array_find_max_index(ipd->matrix_orient, 3, rv3d->viewinv[2], false) :
809 /* For #STEP_DEPTH the orient axis is always view aligned when degenerate. */
810 ipd->orient_axis;
811
812 float axis_fallback[4][3];
813 const int x_axis = (degenerate_axis + 1) % 3;
814 const int y_axis = (degenerate_axis + 2) % 3;
815
816 /* Assign 4x diagonal axes, find which one is closest to the viewport diagonal
817 * bottom left to top right, for a predictable direction from a user perspective. */
818 add_v3_v3v3(axis_fallback[0], ipd->matrix_orient[x_axis], ipd->matrix_orient[y_axis]);
819 sub_v3_v3v3(axis_fallback[1], ipd->matrix_orient[x_axis], ipd->matrix_orient[y_axis]);
820 negate_v3_v3(axis_fallback[2], axis_fallback[0]);
821 negate_v3_v3(axis_fallback[3], axis_fallback[1]);
822
823 const int axis_best = dot_v3_array_find_max_index(axis_fallback, 4, axis_view, true);
824 normalize_v3_v3(ipd->step[i].degenerate_diagonal, axis_fallback[axis_best]);
825 ipd->step[i].degenerate_axis = degenerate_axis;
826
827 /* `degenerate_view_plane_fallback` is used to map cursor motion from a view aligned
828 * plane back onto the view aligned plane.
829 *
830 * The dot product check below ensures cursor motion
831 * isn't inverted from a user perspective. */
832 const bool degenerate_axis_is_flip = dot_v3v3(ipd->matrix_orient[degenerate_axis],
833 ((i == STEP_BASE) ?
835 rv3d->viewinv[2])) < 0.0f;
836
838 if (degenerate_axis_is_flip) {
840 }
841 }
842 }
843 }
844
847
849
850 /* Setup the primitive type. */
851 {
852 PropertyRNA *prop = RNA_struct_find_property(op->ptr, "primitive_type");
853 if (RNA_property_is_set(op->ptr, prop)) {
855 ipd->use_tool = false;
856 }
857 else {
858 ipd->use_tool = true;
859
860 /* Get from the tool, a bit of a non-standard way of operating. */
861 const bToolRef *tref = ipd->area->runtime.tool;
862 if (tref && STREQ(tref->idname, "builtin.primitive_cube_add")) {
864 }
865 else if (tref && STREQ(tref->idname, "builtin.primitive_cylinder_add")) {
867 }
868 else if (tref && STREQ(tref->idname, "builtin.primitive_cone_add")) {
870 }
871 else if (tref && STREQ(tref->idname, "builtin.primitive_uv_sphere_add")) {
873 }
874 else if (tref && STREQ(tref->idname, "builtin.primitive_ico_sphere_add")) {
876 }
877 else {
878 /* If the user runs this as an operator they should set the 'primitive_type',
879 * however running from operator search will end up at this point. */
881 ipd->use_tool = false;
882 }
883 }
884 }
885}
886
888 wmOperator *op,
889 const wmEvent *event)
890{
891 const bool wait_for_input = RNA_boolean_get(op->ptr, "wait_for_input");
892
893 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(
894 MEM_callocN(sizeof(*ipd), __func__));
895 op->customdata = ipd;
896
897 ipd->scene = CTX_data_scene(C);
898 ipd->area = CTX_wm_area(C);
899 ipd->region = CTX_wm_region(C);
900 ipd->v3d = CTX_wm_view3d(C);
901
902 if (wait_for_input) {
903 ipd->wait_for_input = true;
904/* TODO: support snapping when not using with tool. */
905#if 0
907#endif
908 }
909 else {
911 }
912
914
916}
917
919{
920 UNUSED_VARS(C);
921
922 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
924
925 if (ipd->region != nullptr) {
926 if (ipd->draw_handle_view != nullptr) {
928 }
930 }
931
932 MEM_freeN(ipd);
933}
934
939
940enum {
947};
948
950{
951 static const EnumPropertyItem modal_items[] = {
952 {PLACE_MODAL_SNAP_ON, "SNAP_ON", 0, "Snap On", ""},
953 {PLACE_MODAL_SNAP_OFF, "SNAP_OFF", 0, "Snap Off", ""},
954 {PLACE_MODAL_FIXED_ASPECT_ON, "FIXED_ASPECT_ON", 0, "Fixed Aspect On", ""},
955 {PLACE_MODAL_FIXED_ASPECT_OFF, "FIXED_ASPECT_OFF", 0, "Fixed Aspect Off", ""},
956 {PLACE_MODAL_PIVOT_CENTER_ON, "PIVOT_CENTER_ON", 0, "Center Pivot On", ""},
957 {PLACE_MODAL_PIVOT_CENTER_OFF, "PIVOT_CENTER_OFF", 0, "Center Pivot Off", ""},
958 {0, nullptr, 0, nullptr, nullptr},
959 };
960
961 const char *keymap_name = "View3D Placement Modal";
962 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, keymap_name);
963
964 /* This function is called for each space-type, only needs to add map once. */
965 if (keymap && keymap->modal_items) {
966 return;
967 }
968
969 keymap = WM_modalkeymap_ensure(keyconf, keymap_name, modal_items);
970
971 WM_modalkeymap_assign(keymap, "VIEW3D_OT_interactive_add");
972}
973
975 wmOperator *op,
976 const wmEvent *event)
977{
978 UNUSED_VARS(C, op);
979
980 InteractivePlaceData *ipd = static_cast<InteractivePlaceData *>(op->customdata);
981
982 ARegion *region = ipd->region;
983 bool do_redraw = false;
984 bool do_cursor_update = false;
985
986 /* Handle modal key-map. */
987 if (event->type == EVT_MODAL_MAP) {
988 bool is_fallthrough = false;
989 switch (event->val) {
991 is_fallthrough = true;
993 }
995 ipd->step[ipd->step_index].is_fixed_aspect =
996 is_fallthrough ^ ipd->step[ipd->step_index].is_fixed_aspect_init;
997 do_redraw = true;
998 break;
999 }
1001 is_fallthrough = true;
1003 }
1005 ipd->step[ipd->step_index].is_centered = is_fallthrough ^
1006 ipd->step[ipd->step_index].is_centered_init;
1007 do_redraw = true;
1008 break;
1009 }
1010 case PLACE_MODAL_SNAP_ON: {
1011 is_fallthrough = true;
1013 }
1014 case PLACE_MODAL_SNAP_OFF: {
1015 const ToolSettings *ts = ipd->scene->toolsettings;
1016 ipd->is_snap_invert = is_fallthrough;
1017 ipd->use_snap = (ipd->is_snap_invert == !(ts->snap_flag & SCE_SNAP));
1018 do_cursor_update = true;
1019 break;
1020 }
1021 }
1022 }
1023 else {
1024 switch (event->type) {
1025 case EVT_ESCKEY:
1026 case RIGHTMOUSE: {
1027 /* Restore snap mode. */
1028 *ipd->snap_to_ptr = ipd->snap_to_restore;
1030 return OPERATOR_CANCELLED;
1031 }
1032 case MOUSEMOVE: {
1033 do_cursor_update = true;
1034 break;
1035 }
1036 default: {
1037 break;
1038 }
1039 }
1040 }
1041
1042 if (ipd->wait_for_input) {
1043 if (ELEM(event->type, LEFTMOUSE)) {
1044 if (event->val == KM_PRESS) {
1045 view3d_interactive_add_begin(C, op, event);
1046 ipd->wait_for_input = false;
1048 }
1049 }
1051 }
1052
1053 if (ipd->step_index == STEP_BASE) {
1054 if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
1055 if (event->val == KM_RELEASE) {
1057 if (ipd->snap_to_restore & SCE_SNAP_TO_GRID) {
1058 /* Don't snap to grid in #STEP_DEPTH. */
1060 }
1061
1062 /* Set secondary plane. */
1063
1064 /* Create normal. */
1065 {
1066 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1067 float no[3], no_temp[3];
1068
1070 cross_v3_v3v3(no_temp, ipd->step[0].plane, ipd->step[STEP_DEPTH].degenerate_diagonal);
1071 cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
1072 }
1073 else {
1074 cross_v3_v3v3(no_temp, ipd->step[0].plane, rv3d->viewinv[2]);
1075 cross_v3_v3v3(no, no_temp, ipd->step[0].plane);
1076 }
1077 normalize_v3(no);
1078
1079 plane_from_point_normal_v3(ipd->step[1].plane, ipd->step[0].co_dst, no);
1080 }
1081
1082 copy_v3_v3(ipd->step[1].co_dst, ipd->step[0].co_dst);
1083 ipd->step_index = STEP_DEPTH;
1084
1085 /* Use the toggle from the previous step. */
1086 if (ipd->step[0].is_centered != ipd->step[0].is_centered_init) {
1087 ipd->step[1].is_centered = !ipd->step[1].is_centered;
1088 }
1089 if (ipd->step[0].is_fixed_aspect != ipd->step[0].is_fixed_aspect_init) {
1090 ipd->step[1].is_fixed_aspect = !ipd->step[1].is_fixed_aspect;
1091 }
1092 }
1093 }
1094 }
1095 else if (ipd->step_index == STEP_DEPTH) {
1096 if (ELEM(event->type, ipd->launch_event, LEFTMOUSE)) {
1097 if (event->val == KM_PRESS) {
1098 /* Restore snap mode. */
1099 *ipd->snap_to_ptr = ipd->snap_to_restore;
1100
1101 /* Confirm. */
1103 calc_bbox(ipd, &bounds);
1104
1105 float location[3];
1106 float rotation[3];
1107 float scale[3];
1108
1109 float matrix_orient_axis[3][3];
1110 copy_m3_m3(matrix_orient_axis, ipd->matrix_orient);
1111 if (ipd->orient_axis != 2) {
1112 swap_v3_v3(matrix_orient_axis[2], matrix_orient_axis[ipd->orient_axis]);
1113 swap_v3_v3(matrix_orient_axis[0], matrix_orient_axis[1]);
1114 }
1115 /* Needed for shapes where the sign matters (cone for eg). */
1116 {
1117 float delta[3];
1118 sub_v3_v3v3(delta, bounds.vec[0], bounds.vec[4]);
1119 if (dot_v3v3(ipd->matrix_orient[ipd->orient_axis], delta) > 0.0f) {
1120 negate_v3(matrix_orient_axis[2]);
1121
1122 /* Only flip Y so we don't flip a single axis which causes problems. */
1123 negate_v3(matrix_orient_axis[1]);
1124 }
1125 }
1126
1127 mat3_to_eul(rotation, matrix_orient_axis);
1128
1129 mid_v3_v3v3(location, bounds.vec[0], bounds.vec[6]);
1130 const int cube_verts[3] = {3, 1, 4};
1131 for (int i = 0; i < 3; i++) {
1132 scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]);
1133 /* Primitives have size 2 by default, compensate for this here. */
1134 scale[i] /= 2.0f;
1135 }
1136
1137 wmOperatorType *ot = nullptr;
1138 PointerRNA op_props;
1140 ot = WM_operatortype_find("MESH_OT_primitive_cube_add", false);
1141 }
1143 ot = WM_operatortype_find("MESH_OT_primitive_cylinder_add", false);
1144 }
1145 else if (ipd->primitive_type == PLACE_PRIMITIVE_TYPE_CONE) {
1146 ot = WM_operatortype_find("MESH_OT_primitive_cone_add", false);
1147 }
1149 ot = WM_operatortype_find("MESH_OT_primitive_uv_sphere_add", false);
1150 }
1152 ot = WM_operatortype_find("MESH_OT_primitive_ico_sphere_add", false);
1153 }
1154
1155 if (ot != nullptr) {
1157
1158 if (ipd->use_tool) {
1159 bToolRef *tref = ipd->area->runtime.tool;
1160 PointerRNA temp_props;
1161 WM_toolsystem_ref_properties_init_for_keymap(tref, &temp_props, &op_props, ot);
1162 std::swap(temp_props, op_props);
1163 WM_operator_properties_free(&temp_props);
1164 }
1165
1166 RNA_float_set_array(&op_props, "rotation", rotation);
1167 RNA_float_set_array(&op_props, "location", location);
1168 RNA_float_set_array(&op_props, "scale", scale);
1169
1170 /* Always use the defaults here since desired bounds have been set interactively, it does
1171 * not make sense to use a different values from a previous command. */
1173 RNA_float_set(&op_props, "size", 2.0f);
1174 }
1175 if (ELEM(ipd->primitive_type,
1179 {
1180 RNA_float_set(&op_props, "radius", 1.0f);
1181 }
1183 {
1184 RNA_float_set(&op_props, "depth", 2.0f);
1185 }
1187 RNA_float_set(&op_props, "radius1", 1.0f);
1188 RNA_float_set(&op_props, "radius2", 0.0f);
1189 }
1190
1192 C, ot, blender::wm::OpCallContext::ExecDefault, &op_props, nullptr);
1193 WM_operator_properties_free(&op_props);
1194 }
1195 else {
1196 BLI_assert(0);
1197 }
1198
1200 return OPERATOR_FINISHED;
1201 }
1202 }
1203 }
1204 else {
1205 BLI_assert(0);
1206 }
1207
1208 if (do_cursor_update) {
1209 float mval_fl[2];
1210 WM_event_drag_start_mval_fl(event, region, mval_fl);
1211
1212 /* Calculate the snap location on mouse-move or when toggling snap. */
1213 ipd->is_snap_found = false;
1214 if (ipd->use_snap) {
1216 C, event, ipd->snap_co, nullptr, nullptr, nullptr);
1217 }
1218
1219 if (ipd->step_index == STEP_BASE) {
1220 if (ipd->is_snap_found) {
1222 ipd->step[STEP_BASE].co_dst, ipd->step[STEP_BASE].plane, ipd->snap_co);
1223 }
1224 else {
1226 region,
1227 ipd->step[STEP_BASE].plane,
1228 mval_fl,
1229 ipd->step[STEP_BASE].is_degenerate_view_align ? ipd->view_plane : nullptr,
1230 ipd->step[STEP_BASE].co_dst))
1231 {
1232 /* pass */
1233 }
1234
1237 ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_BASE].co_dst))
1238 {
1239 }
1240 }
1241 }
1242 }
1243 else if (ipd->step_index == STEP_DEPTH) {
1244 if (ipd->is_snap_found) {
1246 ipd->step[STEP_DEPTH].co_dst, ipd->step[STEP_DEPTH].plane, ipd->snap_co);
1247 }
1248 else {
1250 region,
1251 ipd->step[STEP_DEPTH].plane,
1252 mval_fl,
1253 ipd->step[STEP_DEPTH].is_degenerate_view_align ? ipd->view_plane : nullptr,
1254 ipd->step[STEP_DEPTH].co_dst))
1255 {
1256 /* pass */
1257 }
1258
1261 ipd->scene, ipd->v3d, ipd->region, ipd->co_src, ipd->step[STEP_DEPTH].co_dst))
1262 {
1263 }
1264 }
1265 }
1266
1267 /* Correct the point so it's aligned with the 'ipd->step[0].co_dst'. */
1268 float close[3], delta[3];
1270 close, ipd->step[STEP_BASE].plane, ipd->step[STEP_DEPTH].co_dst);
1271 sub_v3_v3v3(delta, close, ipd->step[STEP_BASE].co_dst);
1272 sub_v3_v3(ipd->step[STEP_DEPTH].co_dst, delta);
1273 }
1274 do_redraw = true;
1275 }
1276
1277 if (do_redraw) {
1278 ED_region_tag_redraw(region);
1279 }
1280
1282}
1283
1285{
1286 const enum eContextObjectMode mode = CTX_data_mode_enum(C);
1288}
1289
1291{
1292 /* identifiers */
1293 ot->name = "Add Primitive Object";
1294 ot->description = "Interactively add an object";
1295 ot->idname = "VIEW3D_OT_interactive_add";
1296
1297 /* API callbacks. */
1302
1303 /* NOTE: let the operator we call handle undo and registering itself. */
1304 /* flags */
1305 ot->flag = 0;
1306
1307 /* properties */
1308 PropertyRNA *prop;
1309
1310 /* Normally not accessed directly, leave unset and check the active tool. */
1311 static const EnumPropertyItem primitive_type[] = {
1312 {PLACE_PRIMITIVE_TYPE_CUBE, "CUBE", 0, "Cube", ""},
1313 {PLACE_PRIMITIVE_TYPE_CYLINDER, "CYLINDER", 0, "Cylinder", ""},
1314 {PLACE_PRIMITIVE_TYPE_CONE, "CONE", 0, "Cone", ""},
1315 {PLACE_PRIMITIVE_TYPE_SPHERE_UV, "SPHERE_UV", 0, "UV Sphere", ""},
1316 {PLACE_PRIMITIVE_TYPE_SPHERE_ICO, "SPHERE_ICO", 0, "ICO Sphere", ""},
1317 {0, nullptr, 0, nullptr, nullptr},
1318 };
1319
1320 prop = RNA_def_property(ot->srna, "primitive_type", PROP_ENUM, PROP_NONE);
1321 RNA_def_property_ui_text(prop, "Primitive", "");
1322 RNA_def_property_enum_items(prop, primitive_type);
1324
1325 { /* Plane Origin. */
1326 static const EnumPropertyItem items[] = {
1327 {PLACE_ORIGIN_BASE, "EDGE", 0, "Edge", "Start placing the edge position"},
1328 {PLACE_ORIGIN_CENTER, "CENTER", 0, "Center", "Start placing the center position"},
1329 {0, nullptr, 0, nullptr, nullptr},
1330 };
1331 const char *identifiers[2] = {"plane_origin_base", "plane_origin_depth"};
1332 for (int i = 0; i < 2; i++) {
1333 prop = RNA_def_property(ot->srna, identifiers[i], PROP_ENUM, PROP_NONE);
1334 RNA_def_property_ui_text(prop, "Origin", "The initial position for placement");
1336 RNA_def_property_enum_items(prop, items);
1338 }
1339 }
1340
1341 { /* Plane Aspect. */
1342 static const EnumPropertyItem items[] = {
1343 {PLACE_ASPECT_FREE, "FREE", 0, "Free", "Use an unconstrained aspect"},
1344 {PLACE_ASPECT_FIXED, "FIXED", 0, "Fixed", "Use a fixed 1:1 aspect"},
1345 {0, nullptr, 0, nullptr, nullptr},
1346 };
1347 const char *identifiers[2] = {"plane_aspect_base", "plane_aspect_depth"};
1348 for (int i = 0; i < 2; i++) {
1349 prop = RNA_def_property(ot->srna, identifiers[i], PROP_ENUM, PROP_NONE);
1350 RNA_def_property_ui_text(prop, "Aspect", "The initial aspect setting");
1352 RNA_def_property_enum_items(prop, items);
1354 }
1355 }
1356
1357 /* When not accessed via a tool. */
1358 prop = RNA_def_boolean(ot->srna, "wait_for_input", true, "Wait for Input", "");
1360}
1361
1363
1364/* -------------------------------------------------------------------- */
1370
1371static void preview_plane_free_fn(void *customdata)
1372{
1373 V3DSnapCursorState *snap_state = static_cast<V3DSnapCursorState *>(customdata);
1375}
1376
1377static bool snap_cursor_poll(ARegion *region, void *data)
1378{
1379 if (WM_gizmomap_group_find_ptr(region->runtime->gizmo_map, (wmGizmoGroupType *)data) == nullptr)
1380 {
1381 /* Wrong viewport. */
1382 return false;
1383 }
1384 return true;
1385}
1386
1387static void WIDGETGROUP_placement_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
1388{
1390 if (snap_state) {
1391 snap_state->poll = snap_cursor_poll;
1392 snap_state->poll_data = gzgroup->type;
1393 snap_state->draw_plane = true;
1394
1395 gzgroup->customdata = snap_state;
1397 }
1398}
1399
1401{
1403 const Scene *scene = CTX_data_scene(C);
1404 if (BKE_id_is_editable(CTX_data_main(C), &scene->id)) {
1405 return true;
1406 }
1407 }
1408 return false;
1409}
1410
1424
eContextObjectMode
@ CTX_MODE_OBJECT
@ CTX_MODE_EDIT_MESH
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(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)
bool BKE_id_is_editable(const Main *bmain, const ID *id)
Definition lib_id.cc:2523
#define BLI_assert(a)
Definition BLI_assert.h:46
#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:217
void closest_to_plane_normalized_v3(float r_close[3], const float plane[4], const float pt[3])
Definition math_geom.cc:442
float dist_signed_to_plane_v3(const float p[3], const float plane[4])
Definition math_geom.cc:495
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_CANCELLED
@ OPERATOR_FINISHED
@ 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:618
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)
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()
void ED_view3d_cursor_snap_data_update(V3DSnapCursorState *state, const bContext *C, const ARegion *region, const blender::int2 &mval)
#define GPU_batch_uniform_1f(batch, name, x)
Definition GPU_batch.hh:271
void GPU_batch_discard(blender::gpu::Batch *batch)
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
#define GPU_batch_uniform_2fv(batch, name, val)
Definition GPU_batch.hh:277
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, GPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
void GPU_batch_draw(blender::gpu::Batch *batch)
#define GPU_batch_uniform_4fv(batch, name, val)
Definition GPU_batch.hh:279
GPUVertFormat * immVertexFormat()
@ GPU_PRIM_LINE_LOOP
@ GPU_PRIM_LINES
@ GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR
GPUDepthTest
Definition GPU_state.hh:110
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:114
@ GPU_DEPTH_NONE
Definition GPU_state.hh:111
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_depth_test(GPUDepthTest test)
Definition gpu_state.cc:68
GPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:244
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:273
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &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)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
Read Guarded memory(de)allocation.
@ PROP_ENUM
Definition RNA_types.hh:166
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
@ PROP_NONE
Definition RNA_types.hh:233
#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
@ KM_PRESS
Definition WM_types.hh:311
@ KM_PRESS_DRAG
Definition WM_types.hh:319
@ KM_RELEASE
Definition WM_types.hh:312
#define U
BMesh const char void * data
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
nullptr float
#define copysignf(x, y)
#define roundf(x)
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
uint pos
blender::gpu::Batch * quad
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
format
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define fabsf
#define sinf
#define cosf
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
ARegionRuntimeHandle * runtime
enum ePlace_PrimType primitive_type
struct InteractivePlaceData::@230056335236305311233067022040343050171365002270 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:340
float plane_omat[3][3]
Definition ED_view3d.hh:345
bool(* poll)(ARegion *region, void *custom_poll_data)
Definition ED_view3d.hh:364
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
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
i
Definition text_draw.cc:230
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
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])
@ 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 draw_line_bounds(const BoundBox *bounds, const float color[4])
static void view3d_interactive_add_cancel(bContext *C, wmOperator *op)
static wmOperatorStatus view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEvent *event)
static bool idp_snap_calc_incremental(Scene *scene, View3D *v3d, ARegion *region, const float co_relative[3], float co[3])
static bool WIDGETGROUP_placement_poll(const bContext *C, wmGizmoGroupType *gzgt)
@ 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)
void VIEW3D_GGT_placement(wmGizmoGroupType *gzgt)
static wmOperatorStatus view3d_interactive_add_invoke(bContext *C, wmOperator *op, const wmEvent *event)
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 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)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, blender::wm::OpCallContext context, PointerRNA *properties, const wmEvent *event)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
@ RIGHTMOUSE
@ EVT_MODAL_MAP
@ MOUSEMOVE
@ LEFTMOUSE
@ EVT_ESCKEY
wmOperatorType * ot
Definition wm_files.cc:4237
bool WM_gizmo_group_type_ensure(const StringRef 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:932
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:959
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)