Blender V5.0
view3d_buttons.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cfloat>
10#include <cstring>
11
12#include "DNA_armature_types.h"
13#include "DNA_curve_types.h"
14#include "DNA_lattice_types.h"
15#include "DNA_mesh_types.h"
16#include "DNA_meshdata_types.h"
17#include "DNA_meta_types.h"
18#include "DNA_object_types.h"
19#include "DNA_scene_types.h"
20
21#include "MEM_guardedalloc.h"
22
23#include "BLT_translation.hh"
24
25#include "BLI_array_utils.h"
26#include "BLI_bit_vector.hh"
27#include "BLI_listbase.h"
28#include "BLI_math_matrix.h"
29#include "BLI_math_rotation.h"
30#include "BLI_math_vector.h"
31#include "BLI_string_utf8.h"
32#include "BLI_utildefines.h"
33#include "BLI_vector.hh"
34
35#include "BKE_action.hh"
36#include "BKE_armature.hh"
37#include "BKE_context.hh"
38#include "BKE_curve.hh"
39#include "BKE_curves.hh"
40#include "BKE_curves_utils.hh"
41#include "BKE_customdata.hh"
42#include "BKE_deform.hh"
43#include "BKE_editmesh.hh"
44#include "BKE_layer.hh"
45#include "BKE_library.hh"
46#include "BKE_mesh_types.hh"
47#include "BKE_object.hh"
48#include "BKE_object_deform.h"
49#include "BKE_object_types.hh"
50#include "BKE_report.hh"
51#include "BKE_screen.hh"
52
53#include "DEG_depsgraph.hh"
54
55#include "WM_api.hh"
56#include "WM_types.hh"
57
58#include "RNA_access.hh"
59#include "RNA_prototypes.hh"
60
61#include "ED_curves.hh"
62#include "ED_grease_pencil.hh"
63#include "ED_mesh.hh"
64#include "ED_object.hh"
65#include "ED_object_vgroup.hh"
66#include "ED_screen.hh"
67
69
70#include "UI_interface.hh"
72#include "UI_resources.hh"
73
74#include "view3d_intern.hh" /* own include */
75
76/* ******************* view3d space & buttons ************** */
77enum {
78 B_REDR = 2,
81};
82
83/* All must start w/ location */
84
86 float location[3];
87};
88
92
96
100
104
112
119
120/* temporary struct for storing transform properties */
121
135
136#define TRANSFORM_MEDIAN_ARRAY_LEN (sizeof(TransformMedian) / sizeof(float))
137
139
140/* -------------------------------------------------------------------- */
143
146 void *arg1)
147{
148 const int retval_test = B_TRANSFORM_PANEL_MEDIAN;
150 params->unique_retval_ids, params->unique_retval_ids_len, &retval_test) == -1)
151 {
152 return nullptr;
153 }
154
155 BMEditMesh *em = static_cast<BMEditMesh *>(arg1);
156
157 int verts_mask_count = 0;
158 BMIter iter;
159 BMVert *eve;
160 int i;
161
162 blender::BitVector<> verts_mask(em->bm->totvert);
163 BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
165 continue;
166 }
167 verts_mask[i].set();
168 verts_mask_count += 1;
169 }
170
171 BMPartialUpdate_Params update_params{};
172 update_params.do_tessellate = true;
173 update_params.do_normals = true;
175 *em->bm, update_params, verts_mask, verts_mask_count);
176
177 return bmpinfo;
178}
179
181 const uiBlockInteraction_Params * /*params*/,
182 void * /*arg1*/,
183 void *user_data)
184{
185 BMPartialUpdate *bmpinfo = static_cast<BMPartialUpdate *>(user_data);
186 if (bmpinfo == nullptr) {
187 return;
188 }
190}
191
193 const uiBlockInteraction_Params * /*params*/,
194 void *arg1,
195 void *user_data)
196{
197 BMPartialUpdate *bmpinfo = static_cast<BMPartialUpdate *>(user_data);
198 if (bmpinfo == nullptr) {
199 return;
200 }
201
202 View3D *v3d = CTX_wm_view3d(C);
204 if (tfp->tag_for_update == false) {
205 return;
206 }
207 tfp->tag_for_update = false;
208
209 BMEditMesh *em = static_cast<BMEditMesh *>(arg1);
210
212}
213
215
216/* Helper function to compute a median changed value,
217 * when the value should be clamped in [0.0, 1.0].
218 * Returns either 0.0, 1.0 (both can be applied directly), a positive scale factor
219 * for scale down, or a negative one for scale up.
220 */
221static float compute_scale_factor(const float ve_median, const float median)
222{
223 if (ve_median <= 0.0f) {
224 return 0.0f;
225 }
226 if (ve_median >= 1.0f) {
227 return 1.0f;
228 }
229
230 /* Scale value to target median. */
231 float median_new = ve_median;
232 float median_orig = ve_median - median; /* Previous median value. */
233
234 /* In case of floating point error. */
235 CLAMP(median_orig, 0.0f, 1.0f);
236 CLAMP(median_new, 0.0f, 1.0f);
237
238 if (median_new <= median_orig) {
239 /* Scale down. */
240 return median_new / median_orig;
241 }
242
243 /* Scale up, negative to indicate it... */
244 return -(1.0f - median_new) / (1.0f - median_orig);
245}
246
253static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
254{
255 *val = (tot == 1) ? ve_median : (*val + median);
256}
257
258static void apply_raw_diff_v3(float val[3],
259 const int tot,
260 const float ve_median[3],
261 const float median[3])
262{
263 if (tot == 1) {
264 copy_v3_v3(val, ve_median);
265 }
266 else {
267 add_v3_v3(val, median);
268 }
269}
270
272 float *val, const int tot, const float ve_median, const float median, const float sca)
273{
274 if (tot == 1 || ve_median == median) {
275 *val = ve_median;
276 }
277 else {
278 *val *= sca;
279 }
280}
281
282static void apply_scale_factor_clamp(float *val,
283 const int tot,
284 const float ve_median,
285 const float sca)
286{
287 if (tot == 1) {
288 *val = ve_median;
289 CLAMP(*val, 0.0f, 1.0f);
290 }
291 else if (ELEM(sca, 0.0f, 1.0f)) {
292 *val = sca;
293 }
294 else {
295 *val = (sca > 0.0f) ? (*val * sca) : (1.0f + ((1.0f - *val) * sca));
296 CLAMP(*val, 0.0f, 1.0f);
297 }
298}
299
301{
302 if (v3d->runtime.properties_storage == nullptr) {
303 TransformProperties *tfp = MEM_new<TransformProperties>("TransformProperties");
304 /* Construct C++ structures in otherwise zero initialized struct. */
305 new (tfp) TransformProperties();
306
307 v3d->runtime.properties_storage = tfp;
308 v3d->runtime.properties_storage_free = [](void *properties_storage) {
309 MEM_delete(static_cast<TransformProperties *>(properties_storage));
310 };
311 }
312 return static_cast<TransformProperties *>(v3d->runtime.properties_storage);
313}
314
317 int total = 0;
320
323 {
325 add_v3_v3v3(result.median.location, a.median.location, b.median.location);
326 result.median.nurbs_weight = a.median.nurbs_weight + b.median.nurbs_weight;
327 result.median.radius = a.median.radius + b.median.radius;
328 result.median.tilt = a.median.tilt + b.median.tilt;
329 result.total = a.total + b.total;
330 result.total_curve_points = a.total_curve_points + b.total_curve_points;
331 result.total_nurbs_weights = a.total_nurbs_weights + b.total_nurbs_weights;
332 return result;
333 }
334};
335
337 const blender::bke::CurvesGeometry &curves)
338{
339 using namespace blender;
340 using namespace ed::curves;
341
342 if (curves.is_empty()) {
344 }
345 const OffsetIndices points_by_curve = curves.points_by_curve();
346 const VArray<int8_t> curve_types = curves.curve_types();
347 const std::optional<Span<float>> nurbs_weights = curves.nurbs_weights();
348 const VArray<float> radius = curves.radius();
349 const VArray<float> tilt = curves.tilt();
350 const Span<float3> positions = curves.positions();
351
352 IndexMaskMemory memory;
353 const IndexMask selection = retrieve_selected_points(curves, memory);
354
356 curves.curves_range(),
357 512,
359 [&](const IndexRange range, const CurvesPointSelectionStatus &acc) {
360 CurvesPointSelectionStatus value = acc;
361
362 for (const int curve : range) {
363 const IndexRange points = points_by_curve[curve];
364 const CurveType curve_type = CurveType(curve_types[curve]);
365 const bool is_nurbs = curve_type == CURVE_TYPE_NURBS;
366 const IndexMask curve_selection = selection.slice_content(points);
367
368 value.total += curve_selection.size();
369 value.total_curve_points += curve_selection.size();
370
371 curve_selection.foreach_index([&](const int point) {
372 add_v3_v3(value.median.location, positions[point]);
373 value.total_nurbs_weights += is_nurbs;
374 value.median.nurbs_weight += is_nurbs ?
375 (nurbs_weights ? (*nurbs_weights)[point] : 1.0f) :
376 0;
377 value.median.radius += radius[point];
378 value.median.tilt += tilt[point];
379 });
380 }
381 return value;
382 },
384
386 return status;
387 }
388
390 curves, CURVE_TYPE_BEZIER, memory);
391
392 auto add_handles = [&](StringRef selection_attribute, std::optional<Span<float3>> positions) {
393 if (!positions) {
394 return;
395 }
396 const IndexMask selection = retrieve_selected_points(
397 curves, selection_attribute, bezier_points, memory);
398 if (selection.is_empty()) {
399 return;
400 }
401
402 status.total += selection.size();
403
404 selection.foreach_index(
405 [&](const int point) { add_v3_v3(status.median.location, (*positions)[point]); });
406 };
407
408 add_handles(".selection_handle_left", curves.handle_positions_left());
409 add_handles(".selection_handle_right", curves.handle_positions_right());
410 return status;
411}
412
413static bool apply_to_curves_point_selection(const int tot,
414 const TransformMedian_Curves &median,
415 const TransformMedian_Curves &ve_median,
417{
418 using namespace blender;
419 using namespace ed::curves;
420 if (curves.is_empty()) {
421 return false;
422 }
423
424 bool changed = false;
425
426 const OffsetIndices points_by_curve = curves.points_by_curve();
427 const VArray<int8_t> curve_types = curves.curve_types();
428 const MutableSpan<float> nurbs_weights = median.nurbs_weight ? curves.nurbs_weights_for_write() :
430 const MutableSpan<float> radius = median.radius ? curves.radius_for_write() :
432 const MutableSpan<float> tilt = median.tilt ? curves.tilt_for_write() : MutableSpan<float>{};
433
434 IndexMaskMemory memory;
435 const IndexMask selection = retrieve_selected_points(curves, memory);
436 const bool update_location = math::length_manhattan(float3(median.location)) > 0;
437 MutableSpan<float3> positions = update_location && !selection.is_empty() ?
438 curves.positions_for_write() :
440
441 threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
442 for (const int curve : range) {
443 const IndexRange points = points_by_curve[curve];
444 const CurveType curve_type = CurveType(curve_types[curve]);
445 const bool is_nurbs = curve_type == CURVE_TYPE_NURBS;
446 const IndexMask curve_selection = selection.slice_content(points);
447
448 if (!curve_selection.is_empty()) {
449 changed = true;
450 }
451
452 curve_selection.foreach_index([&](const int point) {
453 if (is_nurbs && median.nurbs_weight) {
454 apply_raw_diff(&nurbs_weights[point], tot, ve_median.nurbs_weight, median.nurbs_weight);
455 nurbs_weights[point] = math::clamp(nurbs_weights[point], 0.01f, 100.0f);
456 }
457 if (median.radius) {
458 apply_raw_diff(&radius[point], tot, ve_median.radius, median.radius);
459 }
460 if (median.tilt) {
461 apply_raw_diff(&tilt[point], tot, ve_median.tilt, median.tilt);
462 }
463 if (update_location) {
464 apply_raw_diff_v3(positions[point], tot, ve_median.location, median.location);
465 }
466 });
467 }
468 });
469
470 /* Only location can be changed for Bezier handles. */
471 if (!update_location || !curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
472 return changed;
473 }
474
476 curves, CURVE_TYPE_BEZIER, memory);
477
478 auto apply_to_handles = [&](StringRef selection_attribute, StringRef handles_attribute) {
479 const IndexMask selection = retrieve_selected_points(
480 curves, selection_attribute, bezier_points, memory);
481 if (selection.is_empty()) {
482 return;
483 }
484
486 curves.attributes_for_write().lookup_for_write_span<float3>(handles_attribute);
487 selection.foreach_index(GrainSize(2048), [&](const int point) {
488 apply_raw_diff_v3(handles.span[point], tot, ve_median.location, median.location);
489 });
490 handles.finish();
491
492 changed = true;
493 };
494
495 apply_to_handles(".selection_handle_left", "handle_left");
496 apply_to_handles(".selection_handle_right", "handle_right");
497
498 if (changed) {
499 curves.calculate_bezier_auto_handles();
500 }
501
502 return changed;
503}
504
506 int curve_count = 0;
507 int nurbs_count = 0;
509 int poly_count = 0;
510
514 int order_sum = 0;
515 int order_max = 0;
518
520 {
521 return {a.curve_count + b.curve_count,
522 a.nurbs_count + b.nurbs_count,
523 a.bezier_count + b.bezier_count,
524 a.poly_count + b.poly_count,
525 a.cyclic_count + b.cyclic_count,
526 a.nurbs_knot_mode_sum + b.nurbs_knot_mode_sum,
527 std::max(a.nurbs_knot_mode_max, b.nurbs_knot_mode_max),
528 a.order_sum + b.order_sum,
529 std::max(a.order_max, b.order_max),
530 a.resolution_sum + b.resolution_sum,
531 std::max(a.resolution_max, b.resolution_max)};
532 }
533};
534
536 const blender::bke::CurvesGeometry &curves)
537{
538 using namespace blender;
539 using namespace ed::curves;
540
541 if (curves.is_empty()) {
542 return CurvesSelectionStatus();
543 }
544 const VArray<int8_t> curve_types = curves.curve_types();
545 const VArray<bool> cyclic = curves.cyclic();
546 const VArray<int8_t> nurbs_knot_modes = curves.nurbs_knots_modes();
547 const VArray<int8_t> orders = curves.nurbs_orders();
548 const VArray<int> resolution = curves.resolution();
549
550 IndexMaskMemory memory;
551 const IndexMask selection = retrieve_selected_curves(curves, memory);
552
554 curves.curves_range(),
555 512,
557 [&](const IndexRange range, const CurvesSelectionStatus &acc) {
558 CurvesSelectionStatus value = acc;
559
560 selection.slice_content(range).foreach_index([&](const int curve) {
561 const CurveType curve_type = CurveType(curve_types[curve]);
562 const bool is_nurbs = curve_type == CURVE_TYPE_NURBS;
563 const bool is_bezier = curve_type == CURVE_TYPE_BEZIER;
564 const bool is_poly = curve_type == CURVE_TYPE_POLY;
565
566 value.curve_count++;
567 value.nurbs_count += is_nurbs;
568 value.bezier_count += is_bezier;
569 value.poly_count += is_poly;
570
571 value.cyclic_count += cyclic[curve];
572
573 const int order = is_nurbs ? orders[curve] : 0;
574 value.order_sum += order;
575 value.order_max = std::max(value.order_max, order);
576
577 const int nurbs_knot_mode = is_nurbs ? nurbs_knot_modes[curve] : 0;
578 value.nurbs_knot_mode_sum += nurbs_knot_mode;
579 value.nurbs_knot_mode_max = std::max(value.nurbs_knot_mode_max, nurbs_knot_mode);
580
581 const int res = resolution[curve];
582 value.resolution_sum += res;
583 value.resolution_max = std::max(value.resolution_max, res);
584 });
585 return value;
586 },
588}
589
590/* is used for both read and write... */
592 const bContext *C, uiLayout *layout, View3D *v3d, Object *ob, float lim)
593{
594 using namespace blender;
595 uiBlock *block = (layout) ? layout->absolute_block() : nullptr;
597 TransformMedian median_basis, ve_median_basis;
598 int tot, totedgedata, totcurvedata, totlattdata, totcurvebweight;
599 int total_curve_points_data = 0;
600 bool has_meshdata = false;
601 bool has_skinradius = false;
602 PointerRNA data_ptr;
603
604 copy_vn_fl((float *)&median_basis, TRANSFORM_MEDIAN_ARRAY_LEN, 0.0f);
605 tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
606
607 if (ob->type == OB_MESH) {
608 TransformMedian_Mesh *median = &median_basis.mesh;
609 Mesh *mesh = static_cast<Mesh *>(ob->data);
610 BMEditMesh *em = mesh->runtime->edit_mesh.get();
611 BMesh *bm = em->bm;
612 BMVert *eve;
613 BMEdge *eed;
614 BMIter iter;
615
616 const int cd_vert_bweight_offset = CustomData_get_offset_named(
617 &bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
618 const int cd_vert_crease_offset = CustomData_get_offset_named(
619 &bm->vdata, CD_PROP_FLOAT, "crease_vert");
620 const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
621 const int cd_edge_bweight_offset = CustomData_get_offset_named(
622 &bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
623 const int cd_edge_crease_offset = CustomData_get_offset_named(
624 &bm->edata, CD_PROP_FLOAT, "crease_edge");
625
626 has_skinradius = (cd_vert_skin_offset != -1);
627
628 if (bm->totvertsel) {
629 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
631 tot++;
632 add_v3_v3(median->location, eve->co);
633
634 if (cd_vert_bweight_offset != -1) {
635 median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
636 }
637
638 if (cd_vert_crease_offset != -1) {
639 median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset);
640 }
641
642 if (has_skinradius) {
643 MVertSkin *vs = static_cast<MVertSkin *>(
644 BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset));
645 add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */
646 }
647 }
648 }
649 }
650
651 if ((cd_edge_bweight_offset != -1) || (cd_edge_crease_offset != -1)) {
652 if (bm->totedgesel) {
653 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
655 if (cd_edge_bweight_offset != -1) {
656 median->be_weight += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
657 }
658
659 if (cd_edge_crease_offset != -1) {
660 median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset);
661 }
662
663 totedgedata++;
664 }
665 }
666 }
667 }
668 else {
669 totedgedata = bm->totedgesel;
670 }
671
672 has_meshdata = (tot || totedgedata);
673 }
674 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF)) {
675 TransformMedian_Curve *median = &median_basis.curve;
676 Curve *cu = static_cast<Curve *>(ob->data);
677 BPoint *bp;
678 BezTriple *bezt;
679 int a;
681 StructRNA *seltype = nullptr;
682 void *selp = nullptr;
683
684 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
685 if (nu->type == CU_BEZIER) {
686 bezt = nu->bezt;
687 a = nu->pntsu;
688 while (a--) {
689 if (bezt->f2 & SELECT) {
690 add_v3_v3(median->location, bezt->vec[1]);
691 tot++;
692 median->weight += bezt->weight;
693 median->radius += bezt->radius;
694 median->tilt += bezt->tilt;
695 if (!totcurvedata) { /* I.e. first time... */
696 selp = bezt;
697 seltype = &RNA_BezierSplinePoint;
698 }
699 totcurvedata++;
700 }
701 else {
702 if (bezt->f1 & SELECT) {
703 add_v3_v3(median->location, bezt->vec[0]);
704 tot++;
705 }
706 if (bezt->f3 & SELECT) {
707 add_v3_v3(median->location, bezt->vec[2]);
708 tot++;
709 }
710 }
711 bezt++;
712 }
713 }
714 else {
715 bp = nu->bp;
716 a = nu->pntsu * nu->pntsv;
717 while (a--) {
718 if (bp->f1 & SELECT) {
719 add_v3_v3(median->location, bp->vec);
720 median->b_weight += bp->vec[3];
721 totcurvebweight++;
722 tot++;
723 median->weight += bp->weight;
724 median->radius += bp->radius;
725 median->tilt += bp->tilt;
726 if (!totcurvedata) { /* I.e. first time... */
727 selp = bp;
728 seltype = &RNA_SplinePoint;
729 }
730 totcurvedata++;
731 }
732 bp++;
733 }
734 }
735 }
736
737 if (totcurvedata == 1) {
738 data_ptr = RNA_pointer_create_discrete(&cu->id, seltype, selp);
739 }
740 }
741 else if (ob->type == OB_LATTICE) {
742 Lattice *lt = static_cast<Lattice *>(ob->data);
743 TransformMedian_Lattice *median = &median_basis.lattice;
744 BPoint *bp;
745 int a;
746 StructRNA *seltype = nullptr;
747 void *selp = nullptr;
748
749 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
750 bp = lt->editlatt->latt->def;
751 while (a--) {
752 if (bp->f1 & SELECT) {
753 add_v3_v3(median->location, bp->vec);
754 tot++;
755 median->weight += bp->weight;
756 if (!totlattdata) { /* I.e. first time... */
757 selp = bp;
758 seltype = &RNA_LatticePoint;
759 }
760 totlattdata++;
761 }
762 bp++;
763 }
764
765 if (totlattdata == 1) {
766 data_ptr = RNA_pointer_create_discrete(&lt->id, seltype, selp);
767 }
768 }
769 else if (ELEM(ob->type, OB_GREASE_PENCIL, OB_CURVES)) {
771
772 if (ob->type == OB_GREASE_PENCIL) {
773 using namespace ed::greasepencil;
774 using namespace ed::curves;
775 Scene &scene = *CTX_data_scene(C);
776 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
777 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
778
780 drawings.index_range(),
781 1L,
783 [&](const IndexRange range, const CurvesPointSelectionStatus &acc) {
784 CurvesPointSelectionStatus value = acc;
785 for (const int drawing : range) {
787 value, init_curves_point_selection_status(drawings[drawing].drawing.strokes()));
788 }
789 return value;
790 },
792 }
793 else {
794 using namespace ed::curves;
795 const Curves &curves_id = *static_cast<Curves *>(ob->data);
797 }
798
799 TransformMedian_Curves &median = median_basis.curves;
800 median = status.median;
801 tot = status.total;
802 total_curve_points_data = status.total_curve_points;
803 totcurvebweight = status.total_nurbs_weights;
804 }
805
806 if (tot == 0) {
807 uiDefBut(
808 block, ButType::Label, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, nullptr, 0, 0, "");
809 return;
810 }
811
812 /* Location, X/Y/Z */
813 mul_v3_fl(median_basis.generic.location, 1.0f / float(tot));
814 if (v3d->flag & V3D_GLOBAL_STATS) {
815 mul_m4_v3(ob->object_to_world().ptr(), median_basis.generic.location);
816 }
817
818 if (has_meshdata) {
819 TransformMedian_Mesh *median = &median_basis.mesh;
820 if (totedgedata) {
821 median->e_crease /= float(totedgedata);
822 median->be_weight /= float(totedgedata);
823 }
824 if (tot) {
825 median->bv_weight /= float(tot);
826 median->v_crease /= float(tot);
827 if (has_skinradius) {
828 median->skin[0] /= float(tot);
829 median->skin[1] /= float(tot);
830 }
831 }
832 }
833 else if (total_curve_points_data) {
834 TransformMedian_Curves &median = median_basis.curves;
835 if (totcurvebweight) {
836 median.nurbs_weight /= totcurvebweight;
837 }
838 median.radius /= total_curve_points_data;
839 median.tilt /= total_curve_points_data;
840 }
841 else if (totcurvedata) {
842 TransformMedian_Curve *median = &median_basis.curve;
843 if (totcurvebweight) {
844 median->b_weight /= float(totcurvebweight);
845 }
846 median->weight /= float(totcurvedata);
847 median->radius /= float(totcurvedata);
848 median->tilt /= float(totcurvedata);
849 }
850 else if (totlattdata) {
851 TransformMedian_Lattice *median = &median_basis.lattice;
852 median->weight /= float(totlattdata);
853 }
854
855 if (block) { /* buttons */
856 uiBut *but;
857 int yi = 200;
858 const float tilt_limit = DEG2RADF(21600.0f);
859 const int butw = 200;
860 const int buth = 20 * UI_SCALE_FAC;
861 const int but_margin = 2;
862 const char *c;
863
864 memcpy(&tfp->ve_median, &median_basis, sizeof(tfp->ve_median));
865
867 if (tot == 1) {
868 if (totcurvedata) {
869 /* Curve */
870 c = IFACE_("Control Point:");
871 }
872 else if (ELEM(ob->type, OB_CURVES, OB_GREASE_PENCIL)) {
873 c = IFACE_("Point:");
874 }
875 else {
876 /* Mesh or lattice */
877 c = IFACE_("Vertex:");
878 }
879 }
880 else {
881 c = IFACE_("Median:");
882 }
883 uiDefBut(block, ButType::Label, 0, c, 0, yi -= buth, butw, buth, nullptr, 0, 0, "");
884
886
887 /* Should be no need to translate these. */
888 but = uiDefButF(block,
891 IFACE_("X:"),
892 0,
893 yi -= buth,
894 butw,
895 buth,
896 &tfp->ve_median.generic.location[0],
897 -lim,
898 lim,
899 "");
903 but = uiDefButF(block,
906 IFACE_("Y:"),
907 0,
908 yi -= buth,
909 butw,
910 buth,
911 &tfp->ve_median.generic.location[1],
912 -lim,
913 lim,
914 "");
918 but = uiDefButF(block,
921 IFACE_("Z:"),
922 0,
923 yi -= buth,
924 butw,
925 buth,
926 &tfp->ve_median.generic.location[2],
927 -lim,
928 lim,
929 "");
933
934 if (totcurvebweight == tot) {
935 float &weight = ELEM(ob->type, OB_CURVES, OB_GREASE_PENCIL) ?
938 but = uiDefButF(block,
941 IFACE_("W:"),
942 0,
943 yi -= buth,
944 butw,
945 buth,
946 &weight,
947 0.01,
948 100.0,
949 "");
952 }
953
955 uiDefButBitS(block,
958 B_REDR,
959 IFACE_("Global"),
960 0,
961 yi -= buth + but_margin,
962 100,
963 buth,
964 &v3d->flag,
965 0,
966 0,
967 TIP_("Displays global values"));
968 uiDefButBitS(block,
971 B_REDR,
972 IFACE_("Local"),
973 100,
974 yi,
975 100,
976 buth,
977 &v3d->flag,
978 0,
979 0,
980 TIP_("Displays local values"));
981 UI_block_align_end(block);
982
983 /* Meshes... */
984 if (has_meshdata) {
985 TransformMedian_Mesh *ve_median = &tfp->ve_median.mesh;
986 if (tot) {
987 uiDefBut(block,
989 0,
990 tot == 1 ? IFACE_("Vertex Data:") : IFACE_("Vertices Data:"),
991 0,
992 yi -= buth + but_margin,
993 butw,
994 buth,
995 nullptr,
996 0.0,
997 0.0,
998 "");
999 /* customdata layer added on demand */
1000 but = uiDefButF(block,
1003 tot == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
1004 0,
1005 yi -= buth + but_margin,
1006 butw,
1007 buth,
1008 &ve_median->bv_weight,
1009 0.0,
1010 1.0,
1011 TIP_("Vertex weight used by Bevel modifier"));
1014 /* customdata layer added on demand */
1015 but = uiDefButF(block,
1018 tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"),
1019 0,
1020 yi -= buth + but_margin,
1021 butw,
1022 buth,
1023 &ve_median->v_crease,
1024 0.0,
1025 1.0,
1026 TIP_("Weight used by the Subdivision Surface modifier"));
1029 }
1030 if (has_skinradius) {
1031 UI_block_align_begin(block);
1032 but = uiDefButF(block,
1035 tot == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
1036 0,
1037 yi -= buth + but_margin,
1038 butw,
1039 buth,
1040 &ve_median->skin[0],
1041 0.0,
1042 100.0,
1043 TIP_("X radius used by Skin modifier"));
1046 but = uiDefButF(block,
1049 tot == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
1050 0,
1051 yi -= buth + but_margin,
1052 butw,
1053 buth,
1054 &ve_median->skin[1],
1055 0.0,
1056 100.0,
1057 TIP_("Y radius used by Skin modifier"));
1060 UI_block_align_end(block);
1061 }
1062 if (totedgedata) {
1063 uiDefBut(block,
1065 0,
1066 totedgedata == 1 ? IFACE_("Edge Data:") : IFACE_("Edges Data:"),
1067 0,
1068 yi -= buth + but_margin,
1069 butw,
1070 buth,
1071 nullptr,
1072 0.0,
1073 0.0,
1074 "");
1075 /* customdata layer added on demand */
1076 but = uiDefButF(block,
1079 totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
1080 0,
1081 yi -= buth + but_margin,
1082 butw,
1083 buth,
1084 &ve_median->be_weight,
1085 0.0,
1086 1.0,
1087 TIP_("Edge weight used by Bevel modifier"));
1090 /* customdata layer added on demand */
1091 but = uiDefButF(block,
1094 totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
1095 0,
1096 yi -= buth + but_margin,
1097 butw,
1098 buth,
1099 &ve_median->e_crease,
1100 0.0,
1101 1.0,
1102 TIP_("Weight used by the Subdivision Surface modifier"));
1105 }
1106 }
1107 /* Curve or GP... */
1108 else if (total_curve_points_data) {
1109 const bool is_single = total_curve_points_data == 1;
1110 TransformMedian_Curves *ve_median = &tfp->ve_median.curves;
1111
1112 but = uiDefButF(block,
1115 is_single ? IFACE_("Radius:") : IFACE_("Mean Radius:"),
1116 0,
1117 yi -= buth + but_margin,
1118 butw,
1119 buth,
1120 &ve_median->radius,
1121 0.0,
1122 100.0,
1123 is_single ?
1124 std::nullopt :
1125 std::optional<StringRef>{TIP_("Radius of curve control points")});
1128 but = uiDefButF(block,
1131 is_single ? IFACE_("Tilt:") : IFACE_("Mean Tilt:"),
1132 0,
1133 yi -= buth + but_margin,
1134 butw,
1135 buth,
1136 &ve_median->tilt,
1137 -tilt_limit,
1138 tilt_limit,
1139 is_single ? std::nullopt :
1140 std::optional<StringRef>{TIP_("Tilt of curve control points")});
1144 }
1145 /* Curve... */
1146 else if (totcurvedata) {
1147 TransformMedian_Curve *ve_median = &tfp->ve_median.curve;
1148 if (totcurvedata == 1) {
1149 but = uiDefButR(block,
1151 0,
1152 IFACE_("Weight:"),
1153 0,
1154 yi -= buth + but_margin,
1155 butw,
1156 buth,
1157 &data_ptr,
1158 "weight_softbody",
1159 0,
1160 0.0,
1161 1.0,
1162 std::nullopt);
1165 but = uiDefButR(block,
1167 0,
1168 IFACE_("Radius:"),
1169 0,
1170 yi -= buth + but_margin,
1171 butw,
1172 buth,
1173 &data_ptr,
1174 "radius",
1175 0,
1176 0.0,
1177 100.0,
1178 std::nullopt);
1181 but = uiDefButR(block,
1183 0,
1184 IFACE_("Tilt:"),
1185 0,
1186 yi -= buth + but_margin,
1187 butw,
1188 buth,
1189 &data_ptr,
1190 "tilt",
1191 0,
1192 -tilt_limit,
1193 tilt_limit,
1194 std::nullopt);
1197 }
1198 else if (totcurvedata > 1) {
1199 but = uiDefButF(block,
1202 IFACE_("Mean Weight:"),
1203 0,
1204 yi -= buth + but_margin,
1205 butw,
1206 buth,
1207 &ve_median->weight,
1208 0.0,
1209 1.0,
1210 TIP_("Weight used for Soft Body Goal"));
1213 but = uiDefButF(block,
1216 IFACE_("Mean Radius:"),
1217 0,
1218 yi -= buth + but_margin,
1219 butw,
1220 buth,
1221 &ve_median->radius,
1222 0.0,
1223 100.0,
1224 TIP_("Radius of curve control points"));
1227 but = uiDefButF(block,
1230 IFACE_("Mean Tilt:"),
1231 0,
1232 yi -= buth + but_margin,
1233 butw,
1234 buth,
1235 &ve_median->tilt,
1236 -tilt_limit,
1237 tilt_limit,
1238 TIP_("Tilt of curve control points"));
1242 }
1243 }
1244 /* Lattice... */
1245 else if (totlattdata) {
1246 TransformMedian_Lattice *ve_median = &tfp->ve_median.lattice;
1247 if (totlattdata == 1) {
1248 but = uiDefButR(block,
1250 0,
1251 IFACE_("Weight:"),
1252 0,
1253 yi -= buth + but_margin,
1254 butw,
1255 buth,
1256 &data_ptr,
1257 "weight_softbody",
1258 0,
1259 0.0,
1260 1.0,
1261 std::nullopt);
1264 }
1265 else if (totlattdata > 1) {
1266 but = uiDefButF(block,
1269 IFACE_("Mean Weight:"),
1270 0,
1271 yi -= buth + but_margin,
1272 butw,
1273 buth,
1274 &ve_median->weight,
1275 0.0,
1276 1.0,
1277 TIP_("Weight used for Soft Body Goal"));
1280 }
1281 }
1282
1283 UI_block_align_end(block);
1284
1285 if (ob->type == OB_MESH) {
1286 Mesh *mesh = static_cast<Mesh *>(ob->data);
1287 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
1288 uiBlockInteraction_CallbackData callback_data{};
1290 callback_data.end_fn = editmesh_partial_update_end_fn;
1292 callback_data.arg1 = em;
1293 UI_block_interaction_set(block, &callback_data);
1294 }
1295 }
1296 }
1297 else { /* apply */
1298 memcpy(&ve_median_basis, &tfp->ve_median, sizeof(tfp->ve_median));
1299
1300 if (v3d->flag & V3D_GLOBAL_STATS) {
1301 invert_m4_m4(ob->runtime->world_to_object.ptr(), ob->object_to_world().ptr());
1302 mul_m4_v3(ob->world_to_object().ptr(), median_basis.generic.location);
1303 mul_m4_v3(ob->world_to_object().ptr(), ve_median_basis.generic.location);
1304 }
1305 sub_vn_vnvn((float *)&median_basis,
1306 (float *)&ve_median_basis,
1307 (float *)&median_basis,
1309
1310 /* Note with a single element selected, we always do. */
1311 const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f);
1312
1313 if ((ob->type == OB_MESH) &&
1314 (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease ||
1315 median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight ||
1316 median_basis.mesh.e_crease))
1317 {
1318 const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh;
1319 Mesh *mesh = static_cast<Mesh *>(ob->data);
1320 BMEditMesh *em = mesh->runtime->edit_mesh.get();
1321 BMesh *bm = em->bm;
1322 BMIter iter;
1323 BMVert *eve;
1324 BMEdge *eed;
1325
1326 int cd_vert_bweight_offset = -1;
1327 int cd_vert_crease_offset = -1;
1328 int cd_vert_skin_offset = -1;
1329 int cd_edge_bweight_offset = -1;
1330 int cd_edge_crease_offset = -1;
1331
1332 float scale_bv_weight = 1.0f;
1333 float scale_v_crease = 1.0f;
1334 float scale_skin[2] = {1.0f, 1.0f};
1335 float scale_be_weight = 1.0f;
1336 float scale_e_crease = 1.0f;
1337
1338 /* Vertices */
1339
1340 if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] ||
1341 median->skin[1])
1342 {
1343 if (median->bv_weight) {
1344 if (!CustomData_has_layer_named(&bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert")) {
1345 BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
1346 }
1347 cd_vert_bweight_offset = CustomData_get_offset_named(
1348 &bm->vdata, CD_PROP_FLOAT, "bevel_weight_vert");
1349 BLI_assert(cd_vert_bweight_offset != -1);
1350
1351 scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight);
1352 }
1353
1354 if (median->v_crease) {
1355 if (!CustomData_has_layer_named(&bm->vdata, CD_PROP_FLOAT, "crease_vert")) {
1356 BM_data_layer_add_named(bm, &bm->vdata, CD_PROP_FLOAT, "crease_vert");
1357 }
1358 cd_vert_crease_offset = CustomData_get_offset_named(
1359 &bm->vdata, CD_PROP_FLOAT, "crease_vert");
1360 BLI_assert(cd_vert_crease_offset != -1);
1361
1362 scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease);
1363 }
1364
1365 for (int i = 0; i < 2; i++) {
1366 if (median->skin[i]) {
1367 cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
1368 BLI_assert(cd_vert_skin_offset != -1);
1369
1370 if (ve_median->skin[i] != median->skin[i]) {
1371 scale_skin[i] = ve_median->skin[i] / (ve_median->skin[i] - median->skin[i]);
1372 }
1373 }
1374 }
1375
1376 BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
1378 if (apply_vcos) {
1379 apply_raw_diff_v3(eve->co, tot, ve_median->location, median->location);
1380 }
1381
1382 if (cd_vert_bweight_offset != -1) {
1383 float *b_weight = static_cast<float *>(
1384 BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset));
1385 apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight);
1386 }
1387
1388 if (cd_vert_crease_offset != -1) {
1389 float *crease = static_cast<float *>(
1390 BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset));
1391 apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease);
1392 }
1393
1394 if (cd_vert_skin_offset != -1) {
1395 MVertSkin *vs = static_cast<MVertSkin *>(
1396 BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset));
1397
1398 /* That one is not clamped to [0.0, 1.0]. */
1399 for (int i = 0; i < 2; i++) {
1400 if (median->skin[i] != 0.0f) {
1402 &vs->radius[i], tot, ve_median->skin[i], median->skin[i], scale_skin[i]);
1403 }
1404 }
1405 }
1406 }
1407 }
1408 }
1409
1410 if (apply_vcos) {
1411 /* Tell the update callback to run. */
1412 tfp->tag_for_update = true;
1413 }
1414
1415 /* Edges */
1416
1417 if (median->be_weight || median->e_crease) {
1418 if (median->be_weight) {
1419 if (!CustomData_has_layer_named(&bm->edata, CD_PROP_FLOAT, "bevel_weight_edge")) {
1420 BM_data_layer_add_named(bm, &bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
1421 }
1422 cd_edge_bweight_offset = CustomData_get_offset_named(
1423 &bm->edata, CD_PROP_FLOAT, "bevel_weight_edge");
1424 BLI_assert(cd_edge_bweight_offset != -1);
1425
1426 scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight);
1427 }
1428
1429 if (median->e_crease) {
1430 if (!CustomData_has_layer_named(&bm->edata, CD_PROP_FLOAT, "crease_edge")) {
1431 BM_data_layer_add_named(bm, &bm->edata, CD_PROP_FLOAT, "crease_edge");
1432 }
1433 cd_edge_crease_offset = CustomData_get_offset_named(
1434 &bm->edata, CD_PROP_FLOAT, "crease_edge");
1435 BLI_assert(cd_edge_crease_offset != -1);
1436
1437 scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease);
1438 }
1439
1440 BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
1442 if (median->be_weight != 0.0f) {
1443 float *b_weight = static_cast<float *>(
1444 BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset));
1445 apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight);
1446 }
1447
1448 if (median->e_crease != 0.0f) {
1449 float *crease = static_cast<float *>(
1450 BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset));
1451 apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease);
1452 }
1453 }
1454 }
1455 }
1456 }
1457 else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF) &&
1458 (apply_vcos || median_basis.curve.b_weight || median_basis.curve.weight ||
1459 median_basis.curve.radius || median_basis.curve.tilt))
1460 {
1461 const TransformMedian_Curve *median = &median_basis.curve,
1462 *ve_median = &ve_median_basis.curve;
1463 Curve *cu = static_cast<Curve *>(ob->data);
1464 BPoint *bp;
1465 BezTriple *bezt;
1466 int a;
1467 ListBase *nurbs = BKE_curve_editNurbs_get(cu);
1468 const float scale_w = compute_scale_factor(ve_median->weight, median->weight);
1469
1470 LISTBASE_FOREACH (Nurb *, nu, nurbs) {
1471 if (nu->type == CU_BEZIER) {
1472 for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
1473 if (bezt->f2 & SELECT) {
1474 if (apply_vcos) {
1475 /* Here we always have to use the diff... :/
1476 * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see #37327),
1477 * unless we use doubles.
1478 */
1479 add_v3_v3(bezt->vec[0], median->location);
1480 add_v3_v3(bezt->vec[1], median->location);
1481 add_v3_v3(bezt->vec[2], median->location);
1482 }
1483 if (median->weight) {
1484 apply_scale_factor_clamp(&bezt->weight, tot, ve_median->weight, scale_w);
1485 }
1486 if (median->radius) {
1487 apply_raw_diff(&bezt->radius, tot, ve_median->radius, median->radius);
1488 }
1489 if (median->tilt) {
1490 apply_raw_diff(&bezt->tilt, tot, ve_median->tilt, median->tilt);
1491 }
1492 }
1493 else if (apply_vcos) {
1494 /* Handles can only have their coordinates changed here. */
1495 if (bezt->f1 & SELECT) {
1496 apply_raw_diff_v3(bezt->vec[0], tot, ve_median->location, median->location);
1497 }
1498 if (bezt->f3 & SELECT) {
1499 apply_raw_diff_v3(bezt->vec[2], tot, ve_median->location, median->location);
1500 }
1501 }
1502 }
1503 }
1504 else {
1505 for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a--; bp++) {
1506 if (bp->f1 & SELECT) {
1507 if (apply_vcos) {
1508 apply_raw_diff_v3(bp->vec, tot, ve_median->location, median->location);
1509 }
1510 if (median->b_weight) {
1511 apply_raw_diff(&bp->vec[3], tot, ve_median->b_weight, median->b_weight);
1512 }
1513 if (median->weight) {
1514 apply_scale_factor_clamp(&bp->weight, tot, ve_median->weight, scale_w);
1515 }
1516 if (median->radius) {
1517 apply_raw_diff(&bp->radius, tot, ve_median->radius, median->radius);
1518 }
1519 if (median->tilt) {
1520 apply_raw_diff(&bp->tilt, tot, ve_median->tilt, median->tilt);
1521 }
1522 }
1523 }
1524 }
1525 if (CU_IS_2D(cu)) {
1527 }
1528 /* In the case of weight, tilt or radius (these don't change positions),
1529 * don't change handle types. */
1530 if ((nu->type == CU_BEZIER) && apply_vcos) {
1531 BKE_nurb_handles_test(nu, NURB_HANDLE_TEST_EACH, false); /* test for bezier too */
1532 }
1533 }
1534 }
1535 else if ((ob->type == OB_LATTICE) && (apply_vcos || median_basis.lattice.weight)) {
1536 const TransformMedian_Lattice *median = &median_basis.lattice,
1537 *ve_median = &ve_median_basis.lattice;
1538 Lattice *lt = static_cast<Lattice *>(ob->data);
1539 BPoint *bp;
1540 int a;
1541 const float scale_w = compute_scale_factor(ve_median->weight, median->weight);
1542
1543 a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
1544 bp = lt->editlatt->latt->def;
1545 while (a--) {
1546 if (bp->f1 & SELECT) {
1547 if (apply_vcos) {
1548 apply_raw_diff_v3(bp->vec, tot, ve_median->location, median->location);
1549 }
1550 if (median->weight) {
1551 apply_scale_factor_clamp(&bp->weight, tot, ve_median->weight, scale_w);
1552 }
1553 }
1554 bp++;
1555 }
1556 }
1557 else if (ob->type == OB_GREASE_PENCIL &&
1558 (apply_vcos || median_basis.curves.nurbs_weight || median_basis.curves.radius ||
1559 median_basis.curves.tilt))
1560 {
1561 using namespace ed::greasepencil;
1562 using namespace ed::curves;
1563 Scene &scene = *CTX_data_scene(C);
1564 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
1565 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
1566
1567 threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
1568 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
1570 tot, median_basis.curves, ve_median_basis.curves, curves))
1571 {
1572 info.drawing.tag_positions_changed();
1573 }
1574 });
1575 }
1576 else if (ob->type == OB_CURVES && (apply_vcos || median_basis.curves.nurbs_weight ||
1577 median_basis.curves.radius || median_basis.curves.tilt))
1578 {
1579 using namespace ed::curves;
1580 Curves &curves_id = *static_cast<Curves *>(ob->data);
1581 bke::CurvesGeometry &curves = curves_id.geometry.wrap();
1583 tot, median_basis.curves, ve_median_basis.curves, curves))
1584 {
1585 curves.tag_positions_changed();
1586 }
1587 }
1588 }
1589
1590 // ED_undo_push(C, "Transform properties");
1591}
1592
1593#undef TRANSFORM_MEDIAN_ARRAY_LEN
1594
1596{
1597 uiBlock *block = (layout) ? layout->block() : nullptr;
1598 uiLayout *sub_layout = layout ? &layout->absolute(false) : nullptr;
1600 const bool is_editable = ID_IS_EDITABLE(&ob->id);
1601
1602 if (block) {
1603 BLI_assert(C == nullptr);
1604 int yi = 200;
1605 const int butw = 200;
1606 const int buth = 20 * UI_SCALE_FAC;
1607
1609 copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims);
1610 copy_v3_v3(tfp->ob_scale_orig, ob->scale);
1611 copy_m4_m4(tfp->ob_obmat_orig, ob->object_to_world().ptr());
1612
1613 if (!is_editable && sub_layout) {
1614 sub_layout->enabled_set(false);
1615 }
1616
1617 uiDefBut(block,
1619 0,
1620 IFACE_("Dimensions:"),
1621 0,
1622 yi -= buth,
1623 butw,
1624 buth,
1625 nullptr,
1626 0,
1627 0,
1628 "");
1629 UI_block_align_begin(block);
1630 const float lim = FLT_MAX;
1631 for (int i = 0; i < 3; i++) {
1632 uiBut *but;
1633 const char text[3] = {char('X' + i), ':', '\0'};
1634 but = uiDefButF(block,
1637 text,
1638 0,
1639 yi -= buth,
1640 butw,
1641 buth,
1642 &(tfp->ob_dims[i]),
1643 0.0f,
1644 lim,
1645 "");
1649 if (!is_editable) {
1650 UI_but_disable(but, "Cannot edit this property from a linked data-block");
1651 }
1652 }
1653 UI_block_align_end(block);
1654 }
1655 else { /* apply */
1656 int axis_mask = 0;
1657 for (int i = 0; i < 3; i++) {
1658 if (tfp->ob_dims[i] == tfp->ob_dims_orig[i]) {
1659 axis_mask |= (1 << i);
1660 }
1661 }
1663 ob, tfp->ob_dims, axis_mask, tfp->ob_scale_orig, tfp->ob_obmat_orig);
1664
1665 PointerRNA obptr = RNA_id_pointer_create(&ob->id);
1666 PropertyRNA *prop = RNA_struct_find_property(&obptr, "scale");
1667 RNA_property_update(C, &obptr, prop);
1668 }
1669}
1670
1671#define B_VGRP_PNL_EDIT_SINGLE 8 /* or greater */
1672
1673static void do_view3d_vgroup_buttons(bContext *C, void * /*arg*/, int event)
1674{
1675 if (event < B_VGRP_PNL_EDIT_SINGLE) {
1676 /* not for me */
1677 return;
1678 }
1679
1680 const Scene *scene = CTX_data_scene(C);
1681 ViewLayer *view_layer = CTX_data_view_layer(C);
1682 BKE_view_layer_synced_ensure(scene, view_layer);
1683 Object *ob = BKE_view_layer_active_object_get(view_layer);
1685 DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_GEOMETRY);
1687}
1688
1689static bool view3d_panel_vgroup_poll(const bContext *C, PanelType * /*pt*/)
1690{
1691 const Scene *scene = CTX_data_scene(C);
1692 ViewLayer *view_layer = CTX_data_view_layer(C);
1693 BKE_view_layer_synced_ensure(scene, view_layer);
1694 Object *ob = BKE_view_layer_active_object_get(view_layer);
1697 if (dvert_act) {
1698 return (dvert_act->totweight != 0);
1699 }
1700 }
1701
1702 return false;
1703}
1704
1705static void update_active_vertex_weight(bContext *C, void *arg1, void * /*arg2*/)
1706{
1707 View3D *v3d = CTX_wm_view3d(C);
1709 ViewLayer *view_layer = CTX_data_view_layer(C);
1710 Object *ob = BKE_view_layer_active_object_get(view_layer);
1712 const int vertex_group_index = POINTER_AS_INT(arg1);
1713 MDeformWeight *dw = BKE_defvert_find_index(dv, vertex_group_index);
1714 dw->weight = tfp->vertex_weights[vertex_group_index];
1715}
1716
1717static void view3d_panel_vgroup(const bContext *C, Panel *panel)
1718{
1719 uiBlock *block = panel->layout->absolute_block();
1720 Scene *scene = CTX_data_scene(C);
1721 ViewLayer *view_layer = CTX_data_view_layer(C);
1722 BKE_view_layer_synced_ensure(scene, view_layer);
1723 Object *ob = BKE_view_layer_active_object_get(view_layer);
1724 View3D *v3d = CTX_wm_view3d(C);
1726
1727 MDeformVert *dv;
1728
1730
1731 if (dv && dv->totweight) {
1732 ToolSettings *ts = scene->toolsettings;
1733
1735 PointerRNA op_ptr;
1736 PointerRNA *but_ptr;
1737
1738 uiLayout *col, *bcol;
1739 uiLayout *row;
1740 uiBut *but;
1741 bDeformGroup *dg;
1742 uint i;
1743 int subset_count, vgroup_tot;
1744 const bool *vgroup_validmap;
1745 eVGroupSelect subset_type = eVGroupSelect(ts->vgroupsubset);
1746 int yco = 0;
1747 int lock_count = 0;
1748
1750
1751 bcol = &panel->layout->column(true);
1752 row = &bcol->row(true); /* The filter button row */
1753
1754 PointerRNA tools_ptr = RNA_pointer_create_discrete(nullptr, &RNA_ToolSettings, ts);
1755 row->prop(&tools_ptr, "vertex_group_subset", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
1756
1757 col = &bcol->column(true);
1758
1760 ob, subset_type, &vgroup_tot, &subset_count);
1761 const ListBase *defbase = BKE_object_defgroup_list(ob);
1762 const int vgroup_num = BLI_listbase_count(defbase);
1763 tfp->vertex_weights.resize(vgroup_num);
1764
1765 for (i = 0, dg = static_cast<bDeformGroup *>(defbase->first); dg; i++, dg = dg->next) {
1766 bool locked = (dg->flag & DG_LOCK_WEIGHT) != 0;
1767 if (vgroup_validmap[i]) {
1769 if (dw) {
1770 int x, xco = 0;
1771 int icon;
1772 uiLayout *split = &col->split(0.45, true);
1773 row = &split->row(true);
1774
1775 /* The Weight Group Name */
1776
1777 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_set_active", true);
1778 but = uiDefButO_ptr(block,
1780 ot,
1782 dg->name,
1783 xco,
1784 yco,
1785 (x = UI_UNIT_X * 5),
1786 UI_UNIT_Y,
1787 "");
1788 but_ptr = UI_but_operator_ptr_ensure(but);
1789 RNA_int_set(but_ptr, "weight_group", i);
1791 if (BKE_object_defgroup_active_index_get(ob) != i + 1) {
1793 }
1794 xco += x;
1795
1796 row = &split->row(true);
1797 row->enabled_set(!locked);
1798
1799 /* The weight group value */
1800 /* To be reworked still */
1801 float &vertex_weight = tfp->vertex_weights[i];
1802 vertex_weight = dw->weight;
1803 but = uiDefButF(block,
1806 "",
1807 xco,
1808 yco,
1809 (x = UI_UNIT_X * 4),
1810 UI_UNIT_Y,
1811 &vertex_weight,
1812 0.0,
1813 1.0,
1814 "");
1819 if (locked) {
1820 lock_count++;
1821 }
1822 xco += x;
1823
1824 /* The weight group paste function */
1825 icon = (locked) ? ICON_BLANK1 : ICON_PASTEDOWN;
1826 op_ptr = row->op("OBJECT_OT_vertex_weight_paste",
1827 "",
1828 icon,
1830 UI_ITEM_NONE);
1831 RNA_int_set(&op_ptr, "weight_group", i);
1832
1833 /* The weight entry delete function */
1834 icon = (locked) ? ICON_LOCKED : ICON_X;
1835 op_ptr = row->op("OBJECT_OT_vertex_weight_delete",
1836 "",
1837 icon,
1839 UI_ITEM_NONE);
1840 RNA_int_set(&op_ptr, "weight_group", i);
1841
1842 yco -= UI_UNIT_Y;
1843 }
1844 }
1845 }
1846 MEM_freeN(vgroup_validmap);
1847
1848 yco -= 2;
1849
1850 col = &panel->layout->column(true);
1851 row = &col->row(true);
1852
1853 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_normalize_active_vertex", true);
1854 but = uiDefButO_ptr(
1855 block,
1857 ot,
1859 IFACE_("Normalize"),
1860 0,
1861 yco,
1862 UI_UNIT_X * 5,
1863 UI_UNIT_Y,
1864 TIP_("Normalize weights of active vertex (if affected groups are unlocked)"));
1865
1866 ot = WM_operatortype_find("OBJECT_OT_vertex_weight_copy", true);
1867 but = uiDefButO_ptr(
1868 block,
1870 ot,
1872 IFACE_("Copy"),
1873 UI_UNIT_X * 5,
1874 yco,
1875 UI_UNIT_X * 5,
1876 UI_UNIT_Y,
1877 TIP_("Copy active vertex to other selected vertices (if affected groups are unlocked)"));
1878 if (lock_count) {
1880 }
1881 }
1882}
1883
1885{
1886 uiLayout *split, *colsub;
1887
1888 split = &layout->split(0.8f, false);
1889
1890 if (ptr->type == &RNA_PoseBone) {
1891 PointerRNA boneptr;
1892 Bone *bone;
1893
1894 boneptr = RNA_pointer_get(ptr, "bone");
1895 bone = static_cast<Bone *>(boneptr.data);
1896 split->active_set(!(bone->parent && bone->flag & BONE_CONNECTED));
1897 }
1898 colsub = &split->column(true);
1899 colsub->prop(ptr, "location", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1900 colsub = &split->column(true);
1902 colsub->label("", ICON_NONE);
1903 colsub->prop(
1904 ptr, "lock_location", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1905
1906 split = &layout->split(0.8f, false);
1907
1908 switch (RNA_enum_get(ptr, "rotation_mode")) {
1909 case ROT_MODE_QUAT: /* quaternion */
1910 colsub = &split->column(true);
1911 colsub->prop(ptr, "rotation_quaternion", UI_ITEM_NONE, IFACE_("Rotation"), ICON_NONE);
1912 colsub = &split->column(true);
1914 colsub->prop(ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
1915 if (RNA_boolean_get(ptr, "lock_rotations_4d")) {
1916 colsub->prop(ptr,
1917 "lock_rotation_w",
1919 "",
1920 ICON_DECORATE_UNLOCKED);
1921 }
1922 else {
1923 colsub->label("", ICON_NONE);
1924 }
1925 colsub->prop(ptr,
1926 "lock_rotation",
1928 "",
1929 ICON_DECORATE_UNLOCKED);
1930 break;
1931 case ROT_MODE_AXISANGLE: /* axis angle */
1932 colsub = &split->column(true);
1933 colsub->prop(ptr, "rotation_axis_angle", UI_ITEM_NONE, IFACE_("Rotation"), ICON_NONE);
1934 colsub = &split->column(true);
1936 colsub->prop(ptr, "lock_rotations_4d", UI_ITEM_R_TOGGLE, IFACE_("4L"), ICON_NONE);
1937 if (RNA_boolean_get(ptr, "lock_rotations_4d")) {
1938 colsub->prop(ptr,
1939 "lock_rotation_w",
1941 "",
1942 ICON_DECORATE_UNLOCKED);
1943 }
1944 else {
1945 colsub->label("", ICON_NONE);
1946 }
1947 colsub->prop(ptr,
1948 "lock_rotation",
1950 "",
1951 ICON_DECORATE_UNLOCKED);
1952 break;
1953 default: /* euler rotations */
1954 colsub = &split->column(true);
1955 colsub->prop(ptr, "rotation_euler", UI_ITEM_NONE, IFACE_("Rotation"), ICON_NONE);
1956 colsub = &split->column(true);
1958 colsub->label("", ICON_NONE);
1959 colsub->prop(ptr,
1960 "lock_rotation",
1962 "",
1963 ICON_DECORATE_UNLOCKED);
1964 break;
1965 }
1966 layout->prop(ptr, "rotation_mode", UI_ITEM_NONE, "", ICON_NONE);
1967
1968 split = &layout->split(0.8f, false);
1969 colsub = &split->column(true);
1970 colsub->prop(ptr, "scale", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1971 colsub = &split->column(true);
1973 colsub->label("", ICON_NONE);
1974 colsub->prop(
1975 ptr, "lock_scale", UI_ITEM_R_TOGGLE | UI_ITEM_R_ICON_ONLY, "", ICON_DECORATE_UNLOCKED);
1976}
1977
1978static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
1979{
1980 bPoseChannel *pchan;
1981 uiLayout *col;
1982
1984
1985 if (!pchan) {
1986 layout->label(IFACE_("No Bone Active"), ICON_NONE);
1987 return;
1988 }
1989
1990 PointerRNA pchanptr = RNA_pointer_create_discrete(&ob->id, &RNA_PoseBone, pchan);
1991
1992 col = &layout->column(false);
1993
1994 /* XXX: RNA buts show data in native types (i.e. quaternion, 4-component axis/angle, etc.)
1995 * but old-school UI shows in eulers always. Do we want to be able to still display in Eulers?
1996 * Maybe needs RNA/UI options to display rotations as different types. */
1997 v3d_transform_butsR(col, &pchanptr);
1998}
1999
2000static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
2001{
2002 bArmature *arm = static_cast<bArmature *>(ob->data);
2003 EditBone *ebone;
2004 uiLayout *col;
2005
2006 ebone = arm->act_edbone;
2007
2008 if (!ebone || !ANIM_bonecoll_is_visible_editbone(arm, ebone)) {
2009 layout->label(IFACE_("Nothing selected"), ICON_NONE);
2010 return;
2011 }
2012
2013 PointerRNA eboneptr = RNA_pointer_create_discrete(&arm->id, &RNA_EditBone, ebone);
2014
2015 col = &layout->column(false);
2016 col->prop(&eboneptr, "head", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2017 if (ebone->parent && ebone->flag & BONE_CONNECTED) {
2018 PointerRNA parptr = RNA_pointer_get(&eboneptr, "parent");
2019 col->prop(&parptr, "tail_radius", UI_ITEM_NONE, IFACE_("Radius (Parent)"), ICON_NONE);
2020 }
2021 else {
2022 col->prop(&eboneptr, "head_radius", UI_ITEM_NONE, IFACE_("Radius"), ICON_NONE);
2023 }
2024
2025 col->prop(&eboneptr, "tail", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2026 col->prop(&eboneptr, "tail_radius", UI_ITEM_NONE, IFACE_("Radius"), ICON_NONE);
2027
2028 col->prop(&eboneptr, "roll", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2029 col->prop(&eboneptr, "length", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2030 col->prop(&eboneptr, "envelope_distance", UI_ITEM_NONE, IFACE_("Envelope"), ICON_NONE);
2031}
2032
2033static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
2034{
2035 MetaBall *mball = static_cast<MetaBall *>(ob->data);
2036 uiLayout *col;
2037
2038 if (!mball || !(mball->lastelem)) {
2039 layout->label(IFACE_("Nothing selected"), ICON_NONE);
2040 return;
2041 }
2042
2043 PointerRNA ptr = RNA_pointer_create_discrete(&mball->id, &RNA_MetaElement, mball->lastelem);
2044
2045 col = &layout->column(false);
2046 col->prop(&ptr, "co", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2047
2048 col->prop(&ptr, "radius", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2049 col->prop(&ptr, "stiffness", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2050
2051 col->prop(&ptr, "type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
2052
2053 col = &layout->column(true);
2054 switch (RNA_enum_get(&ptr, "type")) {
2055 case MB_BALL:
2056 break;
2057 case MB_CUBE:
2058 col->label(IFACE_("Size:"), ICON_NONE);
2059 col->prop(&ptr, "size_x", UI_ITEM_NONE, IFACE_("X"), ICON_NONE);
2060 col->prop(&ptr, "size_y", UI_ITEM_NONE, IFACE_("Y"), ICON_NONE);
2061 col->prop(&ptr, "size_z", UI_ITEM_NONE, IFACE_("Z"), ICON_NONE);
2062 break;
2063 case MB_TUBE:
2064 col->label(IFACE_("Size:"), ICON_NONE);
2065 col->prop(&ptr, "size_x", UI_ITEM_NONE, IFACE_("X"), ICON_NONE);
2066 break;
2067 case MB_PLANE:
2068 col->label(IFACE_("Size:"), ICON_NONE);
2069 col->prop(&ptr, "size_x", UI_ITEM_NONE, IFACE_("X"), ICON_NONE);
2070 col->prop(&ptr, "size_y", UI_ITEM_NONE, IFACE_("Y"), ICON_NONE);
2071 break;
2072 case MB_ELIPSOID:
2073 col->label(IFACE_("Size:"), ICON_NONE);
2074 col->prop(&ptr, "size_x", UI_ITEM_NONE, IFACE_("X"), ICON_NONE);
2075 col->prop(&ptr, "size_y", UI_ITEM_NONE, IFACE_("Y"), ICON_NONE);
2076 col->prop(&ptr, "size_z", UI_ITEM_NONE, IFACE_("Z"), ICON_NONE);
2077 break;
2078 }
2079}
2080
2081static void do_view3d_region_buttons(bContext *C, void * /*index*/, int event)
2082{
2083 Scene *scene = CTX_data_scene(C);
2084 ViewLayer *view_layer = CTX_data_view_layer(C);
2085 View3D *v3d = CTX_wm_view3d(C);
2086 BKE_view_layer_synced_ensure(scene, view_layer);
2087 Object *ob = BKE_view_layer_active_object_get(view_layer);
2088
2089 switch (event) {
2090
2091 case B_REDR:
2093 return; /* no notifier! */
2094
2096 if (ob) {
2097 v3d_editvertex_buts(C, nullptr, v3d, ob, 1.0);
2098 DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_GEOMETRY);
2099 }
2100 break;
2102 if (ob) {
2103 v3d_object_dimension_buts(C, nullptr, v3d, ob);
2104 }
2105 break;
2106 }
2107
2108 /* default for now */
2110}
2111
2113{
2114 const Scene *scene = CTX_data_scene(C);
2115 ViewLayer *view_layer = CTX_data_view_layer(C);
2116 BKE_view_layer_synced_ensure(scene, view_layer);
2117 return (BKE_view_layer_active_base_get(view_layer) != nullptr);
2118}
2119
2120static void view3d_panel_transform(const bContext *C, Panel *panel)
2121{
2122 uiBlock *block;
2123 const Scene *scene = CTX_data_scene(C);
2124 ViewLayer *view_layer = CTX_data_view_layer(C);
2125 BKE_view_layer_synced_ensure(scene, view_layer);
2126 Object *ob = BKE_view_layer_active_object_get(view_layer);
2127 Object *obedit = OBEDIT_FROM_OBACT(ob);
2128 uiLayout *col;
2129
2130 block = panel->layout->block();
2132
2133 col = &panel->layout->column(false);
2134
2135 if (ob == obedit) {
2136 if (ob->type == OB_ARMATURE) {
2138 }
2139 else if (ob->type == OB_MBALL) {
2141 }
2142 else {
2143 View3D *v3d = CTX_wm_view3d(C);
2144 v3d_editvertex_buts(C, col, v3d, ob, FLT_MAX);
2145 }
2146 }
2147 else if (ob->mode & OB_MODE_POSE) {
2149 }
2150 else {
2151 PointerRNA obptr = RNA_id_pointer_create(&ob->id);
2152 v3d_transform_butsR(col, &obptr);
2153
2154 /* Dimensions and editmode are mostly the same check. */
2156 {
2157 View3D *v3d = CTX_wm_view3d(C);
2158 v3d_object_dimension_buts(nullptr, col, v3d, ob);
2159 }
2160 }
2161}
2162
2164{
2165 const Scene *scene = CTX_data_scene(C);
2166 ViewLayer *view_layer = CTX_data_view_layer(C);
2167 BKE_view_layer_synced_ensure(scene, view_layer);
2168 Object *ob = BKE_view_layer_active_object_get(view_layer);
2169 return (ob && ELEM(ob->type, OB_GREASE_PENCIL, OB_CURVES) && BKE_object_is_in_editmode(ob));
2170}
2171
2173 bContext *C,
2174 blender::FunctionRef<void(const CurvesDataPanelState &modified_state,
2175 const blender::IndexMask &selection,
2176 blender::bke::CurvesGeometry &curves)> curves_geometry_handler)
2177{
2178 using namespace blender;
2179
2180 const Scene *scene = CTX_data_scene(C);
2181 ViewLayer *view_layer = CTX_data_view_layer(C);
2182 BKE_view_layer_synced_ensure(scene, view_layer);
2183 Object *ob = BKE_view_layer_active_object_get(view_layer);
2184
2185 View3D *v3d = CTX_wm_view3d(C);
2187 const CurvesDataPanelState &modified = tfp.modified;
2188
2189 if (ob->type == OB_GREASE_PENCIL) {
2190 using namespace ed::greasepencil;
2191 Scene &scene = *CTX_data_scene(C);
2192 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
2193 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
2194
2195 threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
2196 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
2197 IndexMaskMemory memory;
2198 const IndexMask selection = ed::curves::retrieve_selected_curves(curves, memory);
2199 if (selection.is_empty()) {
2200 return;
2201 }
2202
2203 curves_geometry_handler(modified, selection, curves);
2204 info.drawing.tag_topology_changed();
2205 });
2206 }
2207 else {
2208 Curves &curves_id = *static_cast<Curves *>(ob->data);
2209 bke::CurvesGeometry &curves = curves_id.geometry.wrap();
2210 IndexMaskMemory memory;
2211 const IndexMask selection = ed::curves::retrieve_selected_curves(curves, memory);
2212
2213 if (!selection.is_empty()) {
2214 curves_geometry_handler(modified, selection, curves);
2215 curves.tag_topology_changed();
2216 }
2217 }
2218
2219 DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_GEOMETRY);
2221}
2222
2223static void handle_curves_cyclic(bContext *C, void *, void *)
2224{
2225 using namespace blender;
2226
2228 [](const CurvesDataPanelState &modified_state,
2229 const IndexMask &selection,
2230 bke::CurvesGeometry &curves) {
2232 curves.cyclic_for_write(), bool(modified_state.cyclic), selection);
2233 });
2234}
2235
2236static void update_custom_knots(const blender::OffsetIndices<int> &src_custom_knots_by_curve,
2237 const blender::Span<int8_t> src_knot_modes,
2238 const blender::Span<float> src_custom_knots,
2240{
2241 using namespace blender;
2243 IndexMaskMemory memory;
2244 const IndexMask custom_knot_curves = curves.nurbs_custom_knot_curves(memory);
2245 if (!custom_knot_curves.is_empty()) {
2246 const OffsetIndices points_by_curve = curves.points_by_curve();
2247 const OffsetIndices<int> custom_knots_by_curve = curves.nurbs_custom_knots_by_curve();
2248 const VArray<int8_t> orders = curves.nurbs_orders();
2249 const VArray<bool> cyclic = curves.cyclic();
2250 MutableSpan<float> custom_knots = curves.nurbs_custom_knots_for_write();
2251
2252 custom_knot_curves.foreach_index(GrainSize(512), [&](const int curve) {
2253 const IndexRange dst_knots = custom_knots_by_curve[curve];
2254 const IndexRange src_knots = src_custom_knots_by_curve[curve];
2255 if (src_knots.is_empty()) {
2256 const int points_num = points_by_curve[curve].size();
2257 const int order = orders[curve];
2258 const bool is_cyclic = cyclic[curve];
2259 Array<float> knots_buffer(bke::curves::nurbs::knots_num(points_num, order, is_cyclic));
2261 points_num, KnotsMode(src_knot_modes[curve]), order, is_cyclic, knots_buffer);
2262 custom_knots.slice(dst_knots).copy_from(
2263 knots_buffer.as_span().take_front(dst_knots.size()));
2264 }
2265 else {
2266 custom_knots.slice(dst_knots).copy_from(src_custom_knots.slice(src_knots));
2267 }
2268 });
2269 }
2270}
2271
2272static void handle_curves_knot_mode(bContext *C, void *, void *)
2273{
2274 using namespace blender;
2275
2277 C,
2278 [](const CurvesDataPanelState &modified_state,
2279 const IndexMask &selection,
2280 bke::CurvesGeometry &curves) {
2281 const OffsetIndices<int> src_custom_knots_by_curve = curves.nurbs_custom_knots_by_curve();
2282 /* Ensure `src_custom_knots_by_curve` will not get deleted. */
2283 const SharedCache<Vector<int>> custom_knot_offsets_cache =
2284 curves.runtime->custom_knot_offsets_cache;
2285 const Span<float> src_custom_knots = curves.nurbs_custom_knots();
2286 const ImplicitSharingInfo *knots_sharing_info = curves.runtime->custom_knots_sharing_info;
2287 if (knots_sharing_info != nullptr) {
2288 knots_sharing_info->add_weak_user();
2289 }
2290
2291 Array<int8_t> src_knot_modes;
2292 if (!src_custom_knots.is_empty() ||
2293 modified_state.nurbs_knot_mode == NURBS_KNOT_MODE_CUSTOM) {
2294 src_knot_modes.reinitialize(curves.curves_num());
2295 curves.nurbs_knots_modes().materialize(src_knot_modes);
2296 }
2297
2298 const MutableSpan<int8_t> nurbs_knot_modes = curves.nurbs_knots_modes_for_write();
2299
2301 nurbs_knot_modes, int8_t(modified_state.nurbs_knot_mode), selection);
2307 update_custom_knots(src_custom_knots_by_curve, src_knot_modes, src_custom_knots, curves);
2308
2309 if (knots_sharing_info != nullptr) {
2310 knots_sharing_info->remove_weak_user_and_delete_if_last();
2311 }
2312 });
2313}
2314
2315static void handle_curves_order(bContext *C, void *, void *)
2316{
2317 using namespace blender;
2318
2320 C,
2321 [](const CurvesDataPanelState &modified_state,
2322 const IndexMask &selection,
2323 bke::CurvesGeometry &curves) {
2324 const MutableSpan<int8_t> nurbs_knot_modes = curves.nurbs_knots_modes_for_write();
2325 const MutableSpan<int8_t> orders = curves.nurbs_orders_for_write();
2326
2327 const OffsetIndices<int> src_custom_knots_by_curve = curves.nurbs_custom_knots_by_curve();
2328 /* Ensure `src_custom_knots_by_curve` will not get deleted. */
2329 const SharedCache<Vector<int>> custom_knot_offsets_cache =
2330 curves.runtime->custom_knot_offsets_cache;
2331 const Span<float> src_custom_knots = curves.nurbs_custom_knots();
2332 const ImplicitSharingInfo *knots_sharing_info = curves.runtime->custom_knots_sharing_info;
2333 if (knots_sharing_info != nullptr) {
2334 knots_sharing_info->add_weak_user();
2335 }
2336
2337 bool knot_modes_changed = false;
2338
2339 selection.foreach_index(GrainSize(512), [&](const int curve) {
2340 if (orders[curve] != modified_state.order &&
2341 nurbs_knot_modes[curve] == NURBS_KNOT_MODE_CUSTOM)
2342 {
2343 nurbs_knot_modes[curve] = NURBS_KNOT_MODE_NORMAL;
2344 knot_modes_changed = true;
2345 }
2346 orders[curve] = modified_state.order;
2347 });
2348
2352 if (knot_modes_changed) {
2353 update_custom_knots(src_custom_knots_by_curve, {}, src_custom_knots, curves);
2354 }
2355
2356 if (knots_sharing_info != nullptr) {
2357 knots_sharing_info->remove_weak_user_and_delete_if_last();
2358 }
2359 });
2360}
2361
2362static void handle_curves_resolution(bContext *C, void *, void *)
2363{
2364 using namespace blender;
2365
2367 [](const CurvesDataPanelState &modified_state,
2368 const IndexMask &selection,
2369 bke::CurvesGeometry &curves) {
2371 modified_state.resolution,
2372 selection);
2373 });
2374}
2375
2376constexpr std::array<EnumPropertyItem, 5> enum_curve_knot_mode_items{{
2377 {NURBS_KNOT_MODE_NORMAL, "NORMAL", ICON_NONE, "Normal", ""},
2378 {NURBS_KNOT_MODE_ENDPOINT, "ENDPOINT", ICON_NONE, "Endpoint", ""},
2379 {NURBS_KNOT_MODE_BEZIER, "BEZIER", ICON_NONE, "Bezier", ""},
2380 {NURBS_KNOT_MODE_ENDPOINT_BEZIER, "ENDPOINT_BEZIER", ICON_NONE, "Endpoint Bezier", ""},
2381 {NURBS_KNOT_MODE_CUSTOM, "CUSTOM", ICON_NONE, "Custom", ""},
2382}};
2383
2384static void knot_modes_menu(bContext * /*C*/, uiLayout *layout, void *knot_mode_p)
2385{
2386 uiBlock *block = layout->block();
2388 layout->column(false);
2389
2390 for (const EnumPropertyItem &item : enum_curve_knot_mode_items) {
2391 uiDefButI(block,
2393 0,
2394 IFACE_(item.name),
2395 0,
2396 0,
2397 UI_UNIT_X * 5,
2398 UI_UNIT_Y,
2399 reinterpret_cast<int *>(knot_mode_p),
2400 item.value,
2401 0.0,
2402 "");
2403 }
2404}
2405
2406static void view3d_panel_curve_data(const bContext *C, Panel *panel)
2407{
2408 using namespace blender;
2409 using namespace ed::curves;
2410
2411 const Scene *scene = CTX_data_scene(C);
2412 ViewLayer *view_layer = CTX_data_view_layer(C);
2413 BKE_view_layer_synced_ensure(scene, view_layer);
2414 Object *ob = BKE_view_layer_active_object_get(view_layer);
2415 uiBlock *block = panel->layout->block();
2416
2418
2419 if (ob->type == OB_GREASE_PENCIL) {
2420 using namespace ed::greasepencil;
2421 Scene &scene = *CTX_data_scene(C);
2422 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob->data);
2423 Vector<MutableDrawingInfo> drawings = retrieve_editable_drawings(scene, grease_pencil);
2424
2426 drawings.index_range(),
2427 1L,
2429 [&](const IndexRange range, const CurvesSelectionStatus &acc) {
2430 CurvesSelectionStatus value = acc;
2431 for (const int drawing : range) {
2433 value, init_curves_selection_status(drawings[drawing].drawing.strokes()));
2434 }
2435 return value;
2436 },
2438 }
2439 else {
2440 const Curves &curves_id = *static_cast<Curves *>(ob->data);
2441 status = init_curves_selection_status(curves_id.geometry.wrap());
2442 }
2443
2444 if (status.curve_count == 0) {
2445 uiDefBut(
2446 block, ButType::Label, 0, IFACE_("Nothing selected"), 0, 130, 200, 20, nullptr, 0, 0, "");
2447 return;
2448 }
2449
2450 View3D *v3d = CTX_wm_view3d(C);
2452 CurvesDataPanelState &modified = tfp.modified;
2453 CurvesDataPanelState &current = tfp.current;
2454
2455 current.cyclic = status.cyclic_count > 0;
2456 current.nurbs_knot_mode = KnotsMode(
2457 math::safe_divide(status.nurbs_knot_mode_sum, status.nurbs_count));
2458 current.order = math::safe_divide(status.order_sum, status.nurbs_count);
2459 current.resolution = math::safe_divide(status.resolution_sum, status.curve_count);
2460
2461 modified = current;
2462
2463 panel->layout->use_property_split_set(true);
2464 uiLayout &bcol = panel->layout->column(false);
2465
2466 auto add_labeled_field =
2467 [&](const StringRef label, const bool active, FunctionRef<uiBut *()> add_button) {
2468 uiLayout &row = bcol.row(true);
2469 uiLayout &split = row.split(0.4, true);
2470 uiLayout &col = split.column(true);
2471 col.alignment_set(ui::LayoutAlign::Right);
2472 col.label(label, ICON_NONE);
2473 split.column(false);
2474 uiBut *but = add_button();
2475 if (active) {
2477 }
2478 else {
2480 }
2481 };
2482
2483 const int butw = 10 * UI_UNIT_X;
2484 const int buth = 20 * UI_SCALE_FAC;
2485
2486 add_labeled_field(
2487 IFACE_("Cyclic"),
2488 status.cyclic_count == 0 || status.cyclic_count == status.curve_count,
2489 [&]() {
2490 uiBut *but = uiDefButC(
2491 block, ButType::Checkbox, 0, "", 0, 0, butw, buth, &modified.cyclic, 0, 1, "");
2492 UI_but_func_set(but, handle_curves_cyclic, nullptr, nullptr);
2493 return but;
2494 });
2495
2496 if (status.nurbs_count == status.curve_count) {
2497 add_labeled_field(
2498 IFACE_("Knot Mode"),
2499 status.nurbs_knot_mode_max * status.nurbs_count == status.nurbs_knot_mode_sum,
2500 [&]() {
2501 uiBut *but = uiDefMenuBut(block,
2502 knot_modes_menu,
2503 &modified.nurbs_knot_mode,
2504 enum_curve_knot_mode_items[modified.nurbs_knot_mode].name,
2505 0,
2506 0,
2507 butw,
2508 buth,
2509 "");
2510 UI_but_type_set_menu_from_pulldown(but);
2511 UI_but_func_set(but, handle_curves_knot_mode, nullptr, nullptr);
2512 return but;
2513 });
2514
2515 add_labeled_field(
2516 IFACE_("Order"), status.order_max * status.nurbs_count == status.order_sum, [&]() {
2517 uiBut *but = uiDefButI(
2518 block, ButType::Num, 0, "", 0, 0, butw, buth, &modified.order, 2, 6, "");
2519 UI_but_number_step_size_set(but, 1);
2520 UI_but_number_precision_set(but, -1);
2521 UI_but_func_set(but, handle_curves_order, nullptr, nullptr);
2522 return but;
2523 });
2524 }
2525
2526 if (status.poly_count == 0) {
2527 add_labeled_field(
2528 IFACE_("Resolution"),
2529 status.resolution_max * status.curve_count == status.resolution_sum,
2530 [&]() {
2531 uiBut *but = uiDefButI(
2532 block, ButType::Num, 0, "", 0, 0, butw, buth, &modified.resolution, 1, 64, "");
2533 UI_but_number_step_size_set(but, 1);
2534 UI_but_number_precision_set(but, -1);
2535 UI_but_func_set(but, handle_curves_resolution, nullptr, nullptr);
2536 return but;
2537 });
2538 }
2539}
2540
2542{
2543 PanelType *pt;
2544
2545 pt = MEM_callocN<PanelType>("spacetype view3d panel object");
2546 STRNCPY_UTF8(pt->idname, "VIEW3D_PT_transform");
2547 STRNCPY_UTF8(pt->label, N_("Transform")); /* XXX C panels unavailable through RNA bpy.types! */
2548 STRNCPY_UTF8(pt->category, "Item");
2552 BLI_addtail(&art->paneltypes, pt);
2553
2554 pt = MEM_callocN<PanelType>("spacetype view3d panel vgroup");
2555 STRNCPY_UTF8(pt->idname, "VIEW3D_PT_vgroup");
2556 STRNCPY_UTF8(pt->label,
2557 N_("Vertex Weights")); /* XXX C panels unavailable through RNA bpy.types! */
2558 STRNCPY_UTF8(pt->category, "Item");
2562 BLI_addtail(&art->paneltypes, pt);
2563
2564 pt = MEM_callocN<PanelType>("spacetype view3d panel curves");
2565 STRNCPY_UTF8(pt->idname, "VIEW3D_PT_curves");
2566 STRNCPY_UTF8(pt->label, N_("Curve Data")); /* XXX C panels unavailable through RNA bpy.types! */
2567 STRNCPY_UTF8(pt->category, "Item");
2571 BLI_addtail(&art->paneltypes, pt);
2572}
2573
2575{
2577 if (ob == nullptr) {
2578 BKE_report(op->reports, RPT_WARNING, "No active object found");
2579 return OPERATOR_CANCELLED;
2580 }
2581 if (((ob->mode & OB_MODE_EDIT) == 0) && ELEM(ob->type, OB_ARMATURE)) {
2583 return OPERATOR_CANCELLED;
2584 }
2585
2586 UI_pie_menu_invoke(C, "VIEW3D_MT_object_mode_pie", CTX_wm_window(C)->eventstate);
2587 return OPERATOR_CANCELLED;
2588}
2589
2591{
2592 ot->name = "Object Mode Menu";
2593 ot->idname = "VIEW3D_OT_object_mode_pie_or_toggle";
2594
2597
2598 /* flags */
2599 ot->flag = 0;
2600}
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
bool ANIM_bonecoll_is_visible_editbone(const bArmature *armature, const EditBone *ebone)
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_active_if_bonecoll_visible(Object *ob) ATTR_WARN_UNUSED_RESULT
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ NURB_HANDLE_TEST_EACH
Definition BKE_curve.hh:61
void BKE_nurb_project_2d(Nurb *nu)
Definition curve.cc:684
#define CU_IS_2D(cu)
Definition BKE_curve.hh:89
void BKE_nurb_handles_test(Nurb *nu, eNurbHandleTest_Mode handle_mode, bool use_around_local)
Definition curve.cc:4084
ListBase * BKE_curve_editNurbs_get(Curve *cu)
Definition curve.cc:419
Low-level operations for curves.
Low-level operations for curves.
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
bool CustomData_has_layer_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
int CustomData_get_offset_named(const CustomData *data, eCustomDataType type, blender::StringRef name)
support for deformation groups and hooks.
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:607
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:585
MDeformWeight * BKE_defvert_find_index(const MDeformVert *dv, int defgroup)
Definition deform.cc:806
void BKE_editmesh_looptris_and_normals_calc_with_partial(BMEditMesh *em, BMPartialUpdate *bmpinfo)
Definition editmesh.cc:122
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Base * BKE_view_layer_active_base_get(ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
General operations, lookup, etc. for blender objects.
bool BKE_object_is_in_editmode(const Object *ob)
void BKE_object_dimensions_eval_cached_get(const Object *ob, float r_vec[3])
void BKE_object_dimensions_set_ex(Object *ob, const float value[3], int axis_mask, const float ob_scale_orig[3], const float ob_obmat_orig[4][4])
bool BKE_object_is_in_wpaint_select_vert(const Object *ob)
bool BKE_object_is_in_editmode_vgroup(const Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
bool * BKE_object_defgroup_subset_from_select_type(struct Object *ob, enum eVGroupSelect subset_type, int *r_defgroup_tot, int *r_subset_count)
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
Generic array manipulation API.
#define BLI_array_findindex(arr, arr_len, p)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
#define DEG2RADF(_deg)
void mul_m4_v3(const float M[4][4], float r[3])
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE float len_squared_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_fl(float r[3], float f)
void sub_vn_vnvn(float *array_tar, const float *array_src_a, const float *array_src_b, int size)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
#define STRNCPY_UTF8(dst, src)
unsigned int uint
#define CLAMP(a, b, c)
#define POINTER_FROM_INT(i)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define TIP_(msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_DEFAULT_BPYRNA
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ ROT_MODE_QUAT
@ ROT_MODE_AXISANGLE
@ BONE_CONNECTED
@ CU_BEZIER
KnotsMode
@ NURBS_KNOT_MODE_ENDPOINT
@ NURBS_KNOT_MODE_NORMAL
@ NURBS_KNOT_MODE_BEZIER
@ NURBS_KNOT_MODE_ENDPOINT_BEZIER
@ NURBS_KNOT_MODE_CUSTOM
@ CD_MVERT_SKIN
@ CD_PROP_FLOAT
@ MB_PLANE
@ MB_ELIPSOID
@ MB_TUBE
@ MB_CUBE
@ MB_BALL
@ OB_MODE_EDIT
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ DG_LOCK_WEIGHT
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
#define OB_TYPE_SUPPORT_EDITMODE(_type)
eVGroupSelect
#define OBEDIT_FROM_OBACT(ob)
#define UI_SCALE_FAC
@ V3D_GLOBAL_STATS
@ OPERATOR_CANCELLED
MDeformVert * ED_mesh_active_dvert_get_only(Object *ob)
Definition meshtools.cc:893
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:693
bool ED_operator_view3d_active(bContext *C)
static void split(const char *text, const char *seps, char ***str, int *count)
Read Guarded memory(de)allocation.
@ PROP_UNIT_ROTATION
Definition RNA_types.hh:178
@ PROP_UNIT_LENGTH
Definition RNA_types.hh:174
#define RNA_TRANSLATION_PREC_DEFAULT
Definition RNA_types.hh:224
#define C
Definition RandGen.cpp:29
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
uiBut * uiDefButF(uiBlock *block, ButType type, int retval, blender::StringRef str, int x, int y, short width, short height, float *poin, float min, float max, std::optional< blender::StringRef > tip)
uiBut * uiDefButI(uiBlock *block, ButType type, int retval, blender::StringRef str, int x, int y, short width, short height, int *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_disable(uiBut *but, const char *disabled_hint)
#define UI_UNIT_Y
uiBut * uiDefButR(uiBlock *block, ButType type, int retval, std::optional< blender::StringRef > str, int x, int y, short width, short height, PointerRNA *ptr, blender::StringRefNull propname, int index, float min, float max, std::optional< blender::StringRef > tip)
void UI_block_interaction_set(uiBlock *block, uiBlockInteraction_CallbackData *callbacks)
wmOperatorStatus UI_pie_menu_invoke(bContext *C, const char *idname, const wmEvent *event)
@ UI_BUT_DISABLED
@ UI_BUT_INACTIVE
void UI_but_drawflag_enable(uiBut *but, int flag)
void UI_but_number_step_size_set(uiBut *but, float step_size)
void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg)
PointerRNA * UI_but_operator_ptr_ensure(uiBut *but)
void UI_but_drawflag_disable(uiBut *but, int flag)
uiBut * uiDefButBitS(uiBlock *block, ButType type, int bit, int retval, blender::StringRef str, int x, int y, short width, short height, short *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_block_align_begin(uiBlock *block)
void UI_but_number_precision_set(uiBut *but, float precision)
uiBut * uiDefButO_ptr(uiBlock *block, ButType type, wmOperatorType *ot, blender::wm::OpCallContext opcontext, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
#define UI_UNIT_X
@ UI_BUT_TEXT_RIGHT
@ UI_BUT_INDETERMINATE
@ UI_BUT_TEXT_LEFT
void UI_but_unit_type_set(uiBut *but, int unit_type)
uiBut * uiDefBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
void UI_block_align_end(uiBlock *block)
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_ICON_ONLY
#define UI_ITEM_NONE
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
#define ND_SPACE_VIEW3D
Definition WM_types.hh:528
#define NC_SPACE
Definition WM_types.hh:392
#define BM_ELEM_CD_GET_FLOAT(ele, offset)
@ BM_ELEM_SELECT
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_flag_test(ele, hflag)
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const StringRef name)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
BMesh * bm
BMPartialUpdate * BM_mesh_partial_create_from_verts_group_single(BMesh &bm, const BMPartialUpdate_Params &params, const BitSpan verts_mask, const int verts_mask_count)
void BM_mesh_partial_destroy(BMPartialUpdate *bmpinfo)
Span< T > as_span() const
Definition BLI_array.hh:243
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
void remove_weak_user_and_delete_if_last() const
IndexMask slice_content(IndexRange range) const
int64_t size() const
bool is_empty() const
void foreach_index(Fn &&fn) const
constexpr int64_t size() const
constexpr bool is_empty() const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr bool is_empty() const
Definition BLI_span.hh:260
IndexRange index_range() const
void resize(const int64_t new_size)
constexpr void copy_from(Span< T > values) const
Definition BLI_span.hh:739
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
void materialize(MutableSpan< T > r_span) const
MutableSpan< float3 > positions_for_write()
MutableSpan< float > nurbs_custom_knots_for_write()
OffsetIndices< int > points_by_curve() const
IndexRange curves_range() const
MutableSpan< int > resolution_for_write()
MutableSpan< int8_t > nurbs_knots_modes_for_write()
MutableSpan< float > tilt_for_write()
VArray< float > radius() const
VArray< float > tilt() const
std::optional< Span< float > > nurbs_weights() const
MutableSpan< int8_t > nurbs_orders_for_write()
Span< float > nurbs_custom_knots() const
VArray< int > resolution() const
VArray< int8_t > nurbs_knots_modes() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
MutableSpan< float > radius_for_write()
bool has_curve_with_type(CurveType type) const
std::optional< Span< float3 > > handle_positions_right() const
MutableSpan< float > nurbs_weights_for_write()
IndexMask nurbs_custom_knot_curves(IndexMaskMemory &memory) const
OffsetIndices< int > nurbs_custom_knots_by_curve() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
MutableSpan< bool > cyclic_for_write()
VArray< int8_t > nurbs_orders() const
void foreach_index(Fn &&fn) const
nullptr float
#define SELECT
static bool is_cyclic(const Nurb *nu)
#define B_REDR
uint col
#define active
VecBase< float, 3 > float3
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
void calculate_knots(int points_num, KnotsMode mode, int8_t order, bool cyclic, MutableSpan< float > knots)
int knots_num(int points_num, int8_t order, bool cyclic)
IndexMask curve_type_point_selection(const bke::CurvesGeometry &curves, CurveType curve_type, IndexMaskMemory &memory)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
bool mode_set(bContext *C, eObjectMode mode)
void vgroup_vert_active_mirror(Object *ob, int def_nr)
void masked_fill(MutableSpan< T > data, const T &value, const IndexMask &mask)
T safe_divide(const T &a, const T &b)
T length_manhattan(const VecBase< T, Size > &a)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
Value parallel_reduce(IndexRange range, int64_t grain_size, const Value &identity, const Function &function, const Reduction &reduction)
Definition BLI_task.hh:151
void block_layout_set_current(uiBlock *block, uiLayout *layout)
const int status
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_id_pointer_create(ID *id)
static const float tilt_limit
Definition rna_curve.cc:882
#define FLT_MAX
Definition stdcycles.h:14
ListBase paneltypes
float co[3]
int totvert
uint8_t f1
float vec[4]
float vec[3][3]
struct Bone * parent
CurvesGeometryRuntimeHandle * runtime
static CurvesPointSelectionStatus sum(const CurvesPointSelectionStatus &a, const CurvesPointSelectionStatus &b)
TransformMedian_Curves median
static CurvesSelectionStatus sum(const CurvesSelectionStatus &a, const CurvesSelectionStatus &b)
CurvesGeometry geometry
EditBone * parent
struct Lattice * latt
Definition DNA_ID.h:414
struct EditLatt * editlatt
struct BPoint * def
void * first
MeshRuntimeHandle * runtime
MetaElem * lastelem
ObjectRuntimeHandle * runtime
float scale[3]
void(* draw)(const bContext *C, Panel *panel)
char idname[BKE_ST_MAXNAME]
bool(* poll)(const bContext *C, PanelType *pt)
char translation_context[BKE_ST_MAXNAME]
char category[BKE_ST_MAXNAME]
char label[BKE_ST_MAXNAME]
struct uiLayout * layout
void * data
Definition RNA_types.hh:53
struct ToolSettings * toolsettings
CurvesDataPanelState current
TransformMedian ve_median
CurvesDataPanelState modified
blender::Vector< float > vertex_weights
TransformMedian median
void(* properties_storage_free)(void *properties_storage)
View3D_Runtime runtime
struct EditBone * act_edbone
struct bDeformGroup * next
uiBlockInteractionBeginFn begin_fn
uiBlockInteractionEndFn end_fn
uiBlockInteractionUpdateFn update_fn
uiBlock * absolute_block()
uiBlock * block() const
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
void enabled_set(bool enabled)
uiLayout & row(bool align)
uiLayout & split(float percentage, bool align)
uiLayout & absolute(bool align)
void emboss_set(blender::ui::EmbossType emboss)
PointerRNA op(wmOperatorType *ot, std::optional< blender::StringRef > name, int icon, blender::wm::OpCallContext context, eUI_Item_Flag flag)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
struct ReportList * reports
i
Definition text_draw.cc:230
TransformMedian_Mesh mesh
TransformMedian_Lattice lattice
TransformMedian_Curves curves
TransformMedian_Generic generic
TransformMedian_Curve curve
ParamHandle ** handles
#define N_(msgid)
static void apply_raw_diff_v3(float val[3], const int tot, const float ve_median[3], const float median[3])
constexpr std::array< EnumPropertyItem, 5 > enum_curve_knot_mode_items
static void do_view3d_vgroup_buttons(bContext *C, void *, int event)
static void v3d_editarmature_buts(uiLayout *layout, Object *ob)
static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
@ B_TRANSFORM_PANEL_DIMS
@ B_TRANSFORM_PANEL_MEDIAN
static void handle_curves_knot_mode(bContext *C, void *, void *)
static void handle_curves_cyclic(bContext *C, void *, void *)
#define TRANSFORM_MEDIAN_ARRAY_LEN
static void v3d_transform_butsR(uiLayout *layout, PointerRNA *ptr)
static void view3d_panel_transform(const bContext *C, Panel *panel)
static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d, Object *ob)
static void do_view3d_region_buttons(bContext *C, void *, int event)
static void apply_to_active_object(bContext *C, blender::FunctionRef< void(const CurvesDataPanelState &modified_state, const blender::IndexMask &selection, blender::bke::CurvesGeometry &curves)> curves_geometry_handler)
static void editmesh_partial_update_update_fn(bContext *C, const uiBlockInteraction_Params *, void *arg1, void *user_data)
static CurvesPointSelectionStatus init_curves_point_selection_status(const blender::bke::CurvesGeometry &curves)
static bool view3d_panel_curve_data_poll(const bContext *C, PanelType *)
static void * editmesh_partial_update_begin_fn(bContext *, const uiBlockInteraction_Params *params, void *arg1)
static void update_custom_knots(const blender::OffsetIndices< int > &src_custom_knots_by_curve, const blender::Span< int8_t > src_knot_modes, const blender::Span< float > src_custom_knots, blender::bke::CurvesGeometry &curves)
static void apply_scale_factor_clamp(float *val, const int tot, const float ve_median, const float sca)
void view3d_buttons_register(ARegionType *art)
static float compute_scale_factor(const float ve_median, const float median)
static bool apply_to_curves_point_selection(const int tot, const TransformMedian_Curves &median, const TransformMedian_Curves &ve_median, blender::bke::CurvesGeometry &curves)
static wmOperatorStatus view3d_object_mode_menu_exec(bContext *C, wmOperator *op)
static void handle_curves_order(bContext *C, void *, void *)
static void editmesh_partial_update_end_fn(bContext *, const uiBlockInteraction_Params *, void *, void *user_data)
static void update_active_vertex_weight(bContext *C, void *arg1, void *)
void VIEW3D_OT_object_mode_pie_or_toggle(wmOperatorType *ot)
#define B_VGRP_PNL_EDIT_SINGLE
static bool view3d_panel_transform_poll(const bContext *C, PanelType *)
static CurvesSelectionStatus init_curves_selection_status(const blender::bke::CurvesGeometry &curves)
static void v3d_editmetaball_buts(uiLayout *layout, Object *ob)
static void handle_curves_resolution(bContext *C, void *, void *)
static void v3d_posearmature_buts(uiLayout *layout, Object *ob)
static void view3d_panel_curve_data(const bContext *C, Panel *panel)
static void view3d_panel_vgroup(const bContext *C, Panel *panel)
static bool view3d_panel_vgroup_poll(const bContext *C, PanelType *)
static void knot_modes_menu(bContext *, uiLayout *layout, void *knot_mode_p)
static TransformProperties * v3d_transform_props_ensure(View3D *v3d)
static void apply_scale_factor(float *val, const int tot, const float ve_median, const float median, const float sca)
static void v3d_editvertex_buts(const bContext *C, uiLayout *layout, View3D *v3d, Object *ob, float lim)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4238
wmOperatorType * ot
Definition wm_files.cc:4237
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)