35 for (const int64_t vert : range) {
36 const Span<int> vert_faces = vert_to_face_map[vert];
38 attribute_math::DefaultMixer<T> mixer({&r_dst[vert], 1});
39 for (const int face : vert_faces) {
40 const int corner = mesh::face_find_corner_from_vert(faces[face], corner_verts, int(vert));
41 mixer.mix_in(0, src[corner]);
59 for (const int corner : range) {
60 const int vert = corner_verts[corner];
68 const LooseVertCache &loose_verts = mesh.verts_no_face();
69 if (loose_verts.count > 0) {
72 for (const int vert_index : range) {
73 if (bits[vert_index]) {
74 r_dst[vert_index] = false;
85 using T = decltype(dummy);
86 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
89 adapt_mesh_domain_corner_to_point_impl<T>(
90 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
105 using T = decltype(dummy);
106 new_varray = VArray<T>::from_func(
107 mesh.corners_num, [corner_verts, varray = varray.typed<T>()](const int64_t corner) {
108 return varray[corner_verts[corner]];
120 using T = decltype(dummy);
121 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
122 if constexpr (std::is_same_v<T, bool>) {
123 new_varray = VArray<T>::from_func(
124 faces.size(), [faces, varray = varray.typed<bool>()](const int face_index) {
126 for (const int corner : faces[face_index]) {
127 if (!varray[corner]) {
135 new_varray = VArray<T>::from_func(
136 faces.size(), [faces, varray = varray.typed<T>()](const int face_index) {
138 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
139 for (const int corner : faces[face_index]) {
140 const T value = varray[corner];
141 mixer.mix_in(0, value);
163 for (
const int face_index :
faces.index_range()) {
167 for (
const int corner : face) {
169 const int edge_index = corner_edges[corner];
170 mixer.mix_in(edge_index, old_values[corner]);
171 mixer.mix_in(edge_index, old_values[next_corner]);
189 for (
const int face_index :
faces.index_range()) {
192 for (
const int corner : face) {
194 const int edge_index = corner_edges[corner];
195 if (!old_values[corner] || !old_values[next_corner]) {
196 r_values[edge_index] =
false;
202 if (loose_edges.
count > 0) {
205 for (const int edge_index : range) {
206 if (loose_edges.is_loose_bits[edge_index]) {
207 r_values[edge_index] = false;
218 using T = decltype(dummy);
219 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
220 adapt_mesh_domain_corner_to_edge_impl<T>(
221 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
231 using T = decltype(dummy);
232 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
233 VArray<T> src = varray.typed<T>();
234 const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
235 if constexpr (std::is_same_v<T, bool>) {
236 new_varray = VArray<T>::from_func(
237 mesh.verts_num, [vert_to_face_map, src](const int point_i) {
238 const Span<int> vert_faces = vert_to_face_map[point_i];
241 vert_faces.begin(), vert_faces.end(), [&](const int face) { return src[face]; });
245 new_varray = VArray<T>::from_func(
246 mesh.verts_num, [vert_to_face_map, src](const int point_i) {
247 const Span<int> vert_faces = vert_to_face_map[point_i];
249 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
250 for (const int face : vert_faces) {
251 mixer.mix_in(0, src[face]);
272 for (const int face_index : range) {
273 MutableSpan<T> face_corner_values = r_values.slice(faces[face_index]);
274 face_corner_values.fill(old_values[face_index]);
283 using T = decltype(dummy);
284 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
285 adapt_mesh_domain_face_to_corner_impl<T>(
286 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
303 for (
const int face_index :
faces.index_range()) {
304 const T value = old_values[face_index];
305 for (
const int edge : corner_edges.
slice(
faces[face_index])) {
306 mixer.mix_in(edge, value);
322 r_values.
fill(
false);
324 for (const int face_index : range) {
325 if (old_values[face_index]) {
326 for (const int edge : corner_edges.slice(faces[face_index])) {
327 r_values[edge] = true;
338 using T = decltype(dummy);
339 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
340 adapt_mesh_domain_face_to_edge_impl<T>(
341 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
354 using T = decltype(dummy);
355 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
356 if constexpr (std::is_same_v<T, bool>) {
357 new_varray = VArray<T>::from_func(
359 [corner_verts, faces, varray = varray.typed<bool>()](const int face_index) {
361 for (const int vert : corner_verts.slice(faces[face_index])) {
370 new_varray = VArray<T>::from_func(
372 [corner_verts, faces, varray = varray.typed<T>()](const int face_index) {
374 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
375 for (const int vert : corner_verts.slice(faces[face_index])) {
376 mixer.mix_in(0, varray[vert]);
393 using T = decltype(dummy);
394 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
395 if constexpr (std::is_same_v<T, bool>) {
397 new_varray = VArray<bool>::from_func(
398 edges.size(), [edges, varray = varray.typed<bool>()](const int edge_index) {
399 const int2 &edge = edges[edge_index];
400 return varray[edge[0]] && varray[edge[1]];
404 new_varray = VArray<T>::from_func(
405 edges.size(), [edges, varray = varray.typed<T>()](const int edge_index) {
406 const int2 &edge = edges[edge_index];
407 return attribute_math::mix2(0.5f, varray[edge[0]], varray[edge[1]]);
426 for (
const int face_index :
faces.index_range()) {
430 for (
const int corner : face) {
432 const int edge = corner_edges[corner];
433 const int edge_prev = corner_edges[corner_prev];
434 mixer.mix_in(corner, old_values[edge]);
435 mixer.mix_in(corner, old_values[edge_prev]);
452 r_values.
fill(
false);
455 for (const int face_index : range) {
456 const IndexRange face = faces[face_index];
457 for (const int corner : face) {
458 const int corner_prev = mesh::face_corner_prev(face, corner);
459 const int edge = corner_edges[corner];
460 const int edge_prev = corner_edges[corner_prev];
461 if (old_values[edge] && old_values[edge_prev]) {
462 r_values[corner] = true;
473 using T = decltype(dummy);
474 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
475 adapt_mesh_domain_edge_to_corner_impl<T>(
476 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
493 const int2 &edge = edges[edge_index];
494 const T value = old_values[edge_index];
495 mixer.mix_in(edge[0], value);
496 mixer.mix_in(edge[1], value);
513 r_values.
fill(
false);
515 for (const int edge_index : range) {
516 if (old_values[edge_index]) {
517 const int2 &edge = edges[edge_index];
518 r_values[edge[0]] = true;
519 r_values[edge[1]] = true;
529 using T = decltype(dummy);
530 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
531 adapt_mesh_domain_edge_to_point_impl<T>(
532 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
545 using T = decltype(dummy);
546 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
547 if constexpr (std::is_same_v<T, bool>) {
549 new_varray = VArray<bool>::from_func(
550 faces.size(), [corner_edges, faces, varray = varray.typed<T>()](const int face_index) {
551 for (const int edge : corner_edges.slice(faces[face_index])) {
560 new_varray = VArray<T>::from_func(
561 faces.size(), [corner_edges, faces, varray = varray.typed<T>()](const int face_index) {
563 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
564 for (const int edge : corner_edges.slice(faces[face_index])) {
565 mixer.mix_in(0, varray[edge]);
583 switch (from_domain) {
589 return mesh.loose_verts().count == 0;
594 return mesh.verts_no_face().count == 0;
597 return mesh.loose_edges().count == 0;
602 return mesh.verts_no_face().count == 0;
605 return mesh.loose_edges().count == 0;
625 if (from_domain == to_domain) {
636 switch (from_domain) {
699 if (
mesh !=
nullptr) {
700 mesh->tag_positions_changed();
707 mesh->tag_sharpness_changed();
714 mesh->tag_material_index_changed();
726 if (
mesh ==
nullptr) {
731 if (vertex_group_index < 0) {
740 const int vertex_group_index)
const
752 if (
mesh ==
nullptr) {
758 if (vertex_group_index < 0) {
768 if (
mesh ==
nullptr) {
779 if (
mesh->deform_verts().is_empty()) {
792 if (
mesh ==
nullptr) {
800 const auto get_fn = [&]() {
823 if (
name.startswith(
".hide")) {
824 return [owner]() { (
static_cast<Mesh *
>(owner))->tag_visibility_changed(); };
826 if (
name ==
"custom_normal") {
827 return [owner]() { (
static_cast<Mesh *
>(owner))->tag_custom_normals_changed(); };
838#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
839 [](void *owner) -> CustomData * { \
840 Mesh *mesh = static_cast<Mesh *>(owner); \
841 return &mesh->NAME; \
843#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
844 [](const void *owner) -> const CustomData * { \
845 const Mesh *mesh = static_cast<const Mesh *>(owner); \
846 return &mesh->NAME; \
848#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \
849 [](const void *owner) -> int { \
850 const Mesh *mesh = static_cast<const Mesh *>(owner); \
871#undef MAKE_CONST_CUSTOM_DATA_GETTER
872#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
881 static const auto material_index_clamp = mf::build::SI1_SO<int, int>(
882 "Material Index Validate",
885 return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
887 mf::build::exec_presets::AllSpanOrSingle());
896 static const auto int2_index_clamp = mf::build::SI1_SO<int2, int2>(
899 mf::build::exec_presets::AllSpanOrSingle());
910 static const auto int_index_clamp = mf::build::SI1_SO<int, int>(
912 [](
int value) {
return std::max(value, 0); },
913 mf::build::exec_presets::AllSpanOrSingle());
956 {&corner_custom_data,
968 fn.domain_size = [](
const void *owner,
const AttrDomain domain) {
969 if (owner ==
nullptr) {
975 return mesh.verts_num;
977 return mesh.edges_num;
979 return mesh.faces_num;
981 return mesh.corners_num;
986 fn.domain_supported = [](
const void * ,
const AttrDomain domain) {
989 fn.adapt_domain = [](
const void *owner,
993 if (owner ==
nullptr) {
#define BLI_assert_unreachable()
#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Object is a sort of wrapper for general info.
static VArray from_single(T value, const int64_t size)
const CPPType & type() const
void get_internal_single(void *r_value) const
static GVArray from_garray(GArray<> array)
static GVArray from_single(const CPPType &type, int64_t size, const void *value)
constexpr int64_t size() const
constexpr void fill(const T &value) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
const AttributeAccessor * accessor
GAttributeReader get_for_vertex_group_index(const Mesh &mesh, const Span< MDeformVert > dverts, const int vertex_group_index) const
GAttributeReader try_get_for_read(const void *owner, const StringRef attribute_id) const final
bool foreach_attribute(const void *owner, const FunctionRef< void(const AttributeIter &)> fn) const final
void foreach_domain(const FunctionRef< void(AttrDomain)> callback) const final
GAttributeWriter try_get_for_write(void *owner, const StringRef attribute_id) const final
bool try_delete(void *owner, const StringRef name) const final
void MEM_freeN(void *vmemh)
#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME)
#define MAKE_GET_ELEMENT_NUM_GETTER(NAME)
#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME)
AttributeAccessorFunctions accessor_functions_for_providers()
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
typename DefaultMixerStruct< T >::type DefaultMixer
int face_corner_prev(const IndexRange face, const int corner)
int face_corner_next(const IndexRange face, const int corner)
static std::function< void()> get_tag_modified_function(void *owner, const StringRef name)
static AttributeAccessorFunctions get_mesh_accessor_functions()
static void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray)
static bool can_simple_adapt_for_single(const Mesh &mesh, const AttrDomain from_domain, const AttrDomain to_domain)
static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray)
const AttributeAccessorFunctions & mesh_attribute_accessor_functions()
static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray)
static void tag_component_sharpness_changed(void *owner)
static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray)
static void tag_component_positions_changed(void *owner)
static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, const VArray< T > &src, MutableSpan< T > r_dst)
void remove_defgroup_index(MutableSpan< MDeformVert > dverts, int defgroup_index)
static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static GeometryAttributeProviders create_attribute_providers_for_mesh()
static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
static void tag_material_index_changed(void *owner)
static void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray)
static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static GVArray adapt_mesh_attribute_domain(const Mesh &mesh, const GVArray &varray, const AttrDomain from_domain, const AttrDomain to_domain)
static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray)
static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray)
static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray)
void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray)
VMutableArray< float > varray_for_mutable_deform_verts(MutableSpan< MDeformVert > dverts, int defgroup_index)
VArray< float > varray_for_deform_verts(Span< MDeformVert > dverts, int defgroup_index)
T max(const T &a, const T &b)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< int32_t, 2 > int2
IndexRange index_range() const