44 if (mesh_ !=
nullptr) {
54 if (mesh_ !=
nullptr) {
64 return mesh_ !=
nullptr;
72 ownership_ = ownership;
100 return mesh_ ==
nullptr;
122 mesh_->count_memory(memory);
151 mask.foreach_index([&](
const int i) {
152 const int2 &edge = edges[i];
164 return mesh.attributes().adapt_domain(
184 const Span<int> corner_verts = mesh.corner_verts();
187 for (
const int corner :
IndexRange(mesh.corners_num)) {
188 mixer.mix_in(corner_verts[corner], old_values[corner]);
200 const Span<int> corner_verts = mesh.corner_verts();
203 for (
const int corner :
IndexRange(mesh.corners_num)) {
204 const int point_index = corner_verts[corner];
206 if (!old_values[corner]) {
207 r_values[point_index] =
false;
213 if (loose_verts.
count > 0) {
216 for (const int vert_index : range) {
217 if (bits[vert_index]) {
218 r_values[vert_index] = false;
228 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
229 using T = decltype(dummy);
230 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
233 adapt_mesh_domain_corner_to_point_impl<T>(
234 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
245 const Span<int> corner_verts = mesh.corner_verts();
248 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
249 using T = decltype(dummy);
250 new_varray = VArray<T>::ForFunc(
251 mesh.corners_num, [corner_verts, varray = varray.typed<T>()](const int64_t corner) {
252 return varray[corner_verts[corner]];
263 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
264 using T = decltype(dummy);
265 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
266 if constexpr (std::is_same_v<T, bool>) {
267 new_varray = VArray<T>::ForFunc(
268 faces.size(), [faces, varray = varray.typed<bool>()](const int face_index) {
270 for (const int loop_index : faces[face_index]) {
271 if (!varray[loop_index]) {
279 new_varray = VArray<T>::ForFunc(
280 faces.size(), [faces, varray = varray.typed<T>()](const int face_index) {
282 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
283 for (const int loop_index : faces[face_index]) {
284 const T value = varray[loop_index];
285 mixer.mix_in(0, value);
303 const Span<int> corner_edges = mesh.corner_edges();
307 for (
const int face_index : faces.index_range()) {
311 for (
const int corner : face) {
312 const int next_corner = mesh::face_corner_next(face, corner);
313 const int edge_index = corner_edges[corner];
314 mixer.mix_in(edge_index, old_values[corner]);
315 mixer.mix_in(edge_index, old_values[next_corner]);
330 const Span<int> corner_edges = mesh.corner_edges();
333 for (
const int face_index : faces.index_range()) {
336 for (
const int corner : face) {
337 const int next_corner = mesh::face_corner_next(face, corner);
338 const int edge_index = corner_edges[corner];
339 if (!old_values[corner] || !old_values[next_corner]) {
340 r_values[edge_index] =
false;
346 if (loose_edges.
count > 0) {
349 for (const int edge_index : range) {
350 if (loose_edges.is_loose_bits[edge_index]) {
351 r_values[edge_index] = false;
361 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
362 using T = decltype(dummy);
363 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
364 adapt_mesh_domain_corner_to_edge_impl<T>(
365 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
378 const Span<int> corner_verts = mesh.corner_verts();
382 for (
const int face_index : faces.index_range()) {
383 const T value = old_values[face_index];
384 for (
const int vert : corner_verts.
slice(faces[face_index])) {
385 mixer.mix_in(vert, value);
400 const Span<int> corner_verts = mesh.corner_verts();
402 r_values.
fill(
false);
404 for (const int face_index : range) {
405 if (old_values[face_index]) {
406 for (const int vert : corner_verts.slice(faces[face_index])) {
407 r_values[vert] = true;
417 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
418 using T = decltype(dummy);
419 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
420 adapt_mesh_domain_face_to_point_impl<T>(
421 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
437 for (const int face_index : range) {
438 MutableSpan<T> face_corner_values = r_values.slice(faces[face_index]);
439 face_corner_values.fill(old_values[face_index]);
447 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
448 using T = decltype(dummy);
449 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
450 adapt_mesh_domain_face_to_corner_impl<T>(
451 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
464 const Span<int> corner_edges = mesh.corner_edges();
468 for (
const int face_index : faces.index_range()) {
469 const T value = old_values[face_index];
470 for (
const int edge : corner_edges.
slice(faces[face_index])) {
471 mixer.mix_in(edge, value);
485 const Span<int> corner_edges = mesh.corner_edges();
487 r_values.
fill(
false);
489 for (const int face_index : range) {
490 if (old_values[face_index]) {
491 for (const int edge : corner_edges.slice(faces[face_index])) {
492 r_values[edge] = true;
502 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
503 using T = decltype(dummy);
504 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
505 adapt_mesh_domain_face_to_edge_impl<T>(
506 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
515 const Span<int> corner_verts = mesh.corner_verts();
518 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
519 using T = decltype(dummy);
520 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
521 if constexpr (std::is_same_v<T, bool>) {
522 new_varray = VArray<T>::ForFunc(
524 [corner_verts, faces, varray = varray.typed<bool>()](const int face_index) {
526 for (const int vert : corner_verts.slice(faces[face_index])) {
535 new_varray = VArray<T>::ForFunc(
537 [corner_verts, faces, varray = varray.typed<T>()](const int face_index) {
539 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
540 for (const int vert : corner_verts.slice(faces[face_index])) {
541 mixer.mix_in(0, varray[vert]);
557 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
558 using T = decltype(dummy);
559 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
560 if constexpr (std::is_same_v<T, bool>) {
562 new_varray = VArray<bool>::ForFunc(
563 edges.size(), [edges, varray = varray.typed<bool>()](const int edge_index) {
564 const int2 &edge = edges[edge_index];
565 return varray[edge[0]] && varray[edge[1]];
569 new_varray = VArray<T>::ForFunc(
570 edges.size(), [edges, varray = varray.typed<T>()](const int edge_index) {
572 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
573 const int2 &edge = edges[edge_index];
574 mixer.mix_in(0, varray[edge[0]]);
575 mixer.mix_in(0, varray[edge[1]]);
592 const Span<int> corner_edges = mesh.corner_edges();
596 for (
const int face_index : faces.index_range()) {
600 for (
const int loop_index : face) {
601 const int loop_index_prev = mesh::face_corner_prev(face, loop_index);
602 const int edge = corner_edges[loop_index];
603 const int edge_prev = corner_edges[loop_index_prev];
604 mixer.mix_in(loop_index, old_values[edge]);
605 mixer.mix_in(loop_index, old_values[edge_prev]);
620 const Span<int> corner_edges = mesh.corner_edges();
622 r_values.
fill(
false);
625 for (const int face_index : range) {
626 const IndexRange face = faces[face_index];
627 for (const int loop_index : face) {
628 const int loop_index_prev = mesh::face_corner_prev(face, loop_index);
629 const int edge = corner_edges[loop_index];
630 const int edge_prev = corner_edges[loop_index_prev];
631 if (old_values[edge] && old_values[edge_prev]) {
632 r_values[loop_index] = true;
642 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
643 using T = decltype(dummy);
644 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
645 adapt_mesh_domain_edge_to_corner_impl<T>(
646 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
662 for (
const int edge_index :
IndexRange(mesh.edges_num)) {
663 const int2 &edge = edges[edge_index];
664 const T value = old_values[edge_index];
665 mixer.mix_in(edge[0], value);
666 mixer.mix_in(edge[1], value);
683 r_values.
fill(
false);
685 for (const int edge_index : range) {
686 if (old_values[edge_index]) {
687 const int2 &edge = edges[edge_index];
688 r_values[edge[0]] = true;
689 r_values[edge[1]] = true;
698 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
699 using T = decltype(dummy);
700 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
701 adapt_mesh_domain_edge_to_point_impl<T>(
702 mesh, varray.typed<T>(), values.as_mutable_span().typed<T>());
711 const Span<int> corner_edges = mesh.corner_edges();
714 attribute_math::convert_to_static_type(varray.
type(), [&](
auto dummy) {
715 using T = decltype(dummy);
716 if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
717 if constexpr (std::is_same_v<T, bool>) {
719 new_varray = VArray<bool>::ForFunc(
720 faces.size(), [corner_edges, faces, varray = varray.typed<T>()](const int face_index) {
721 for (const int edge : corner_edges.slice(faces[face_index])) {
730 new_varray = VArray<T>::ForFunc(
731 faces.size(), [corner_edges, faces, varray = varray.typed<T>()](const int face_index) {
733 attribute_math::DefaultMixer<T> mixer({&return_value, 1});
734 for (const int edge : corner_edges.slice(faces[face_index])) {
735 mixer.mix_in(0, varray[edge]);
753 switch (from_domain) {
754 case AttrDomain::Point:
757 case AttrDomain::Edge:
758 if (to_domain == AttrDomain::Point) {
759 return mesh.loose_verts().count == 0;
762 case AttrDomain::Face:
763 if (to_domain == AttrDomain::Point) {
764 return mesh.verts_no_face().count == 0;
766 if (to_domain == AttrDomain::Edge) {
767 return mesh.loose_edges().count == 0;
770 case AttrDomain::Corner:
771 if (to_domain == AttrDomain::Point) {
772 return mesh.verts_no_face().count == 0;
774 if (to_domain == AttrDomain::Edge) {
775 return mesh.loose_edges().count == 0;
795 if (from_domain == to_domain) {
806 switch (from_domain) {
807 case AttrDomain::Corner: {
809 case AttrDomain::Point:
811 case AttrDomain::Face:
813 case AttrDomain::Edge:
820 case AttrDomain::Point: {
822 case AttrDomain::Corner:
824 case AttrDomain::Face:
826 case AttrDomain::Edge:
833 case AttrDomain::Face: {
835 case AttrDomain::Point:
837 case AttrDomain::Corner:
839 case AttrDomain::Edge:
846 case AttrDomain::Edge: {
848 case AttrDomain::Corner:
850 case AttrDomain::Point:
852 case AttrDomain::Face:
868 Mesh *mesh =
static_cast<Mesh *
>(owner);
869 if (mesh !=
nullptr) {
870 mesh->tag_positions_changed();
876 if (
Mesh *mesh =
static_cast<Mesh *
>(owner)) {
877 mesh->tag_sharpness_changed();
888 if (bke::attribute_name_is_anonymous(attribute_id)) {
891 const Mesh *mesh =
static_cast<const Mesh *
>(owner);
892 if (mesh ==
nullptr) {
897 if (vertex_group_index < 0) {
901 return this->get_for_vertex_group_index(*mesh, dverts, vertex_group_index);
906 const int vertex_group_index)
const
917 if (bke::attribute_name_is_anonymous(attribute_id)) {
920 Mesh *mesh =
static_cast<Mesh *
>(owner);
921 if (mesh ==
nullptr) {
927 if (vertex_group_index < 0) {
936 if (bke::attribute_name_is_anonymous(attribute_id)) {
939 Mesh *mesh =
static_cast<Mesh *
>(owner);
940 if (mesh ==
nullptr) {
944 const std::string name = attribute_id;
953 if (mesh->deform_verts().is_empty()) {
965 const Mesh *mesh =
static_cast<const Mesh *
>(owner);
966 if (mesh ==
nullptr) {
974 const auto get_fn = [&]() {
975 return this->get_for_vertex_group_index(*mesh, dverts, group_index);
980 if (iter.is_stopped()) {
999#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \
1000 [](void *owner) -> CustomData * { \
1001 Mesh *mesh = static_cast<Mesh *>(owner); \
1002 return &mesh->NAME; \
1004#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \
1005 [](const void *owner) -> const CustomData * { \
1006 const Mesh *mesh = static_cast<const Mesh *>(owner); \
1007 return &mesh->NAME; \
1009#define MAKE_GET_ELEMENT_NUM_GETTER(NAME) \
1010 [](const void *owner) -> int { \
1011 const Mesh *mesh = static_cast<const Mesh *>(owner); \
1012 return mesh->NAME; \
1028#undef MAKE_CONST_CUSTOM_DATA_GETTER
1029#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER
1034 BuiltinAttributeProvider::NonDeletable,
1041 BuiltinAttributeProvider::Deletable,
1045 static const auto material_index_clamp = mf::build::SI1_SO<int, int>(
1046 "Material Index Validate",
1049 return std::clamp<int>(value, 0, std::numeric_limits<short>::max());
1051 mf::build::exec_presets::AllSpanOrSingle());
1055 BuiltinAttributeProvider::Deletable,
1060 static const auto int2_index_clamp = mf::build::SI1_SO<int2, int2>(
1063 mf::build::exec_presets::AllSpanOrSingle());
1067 BuiltinAttributeProvider::NonDeletable,
1074 static const auto int_index_clamp = mf::build::SI1_SO<int, int>(
1076 [](
int value) {
return std::max(value, 0); },
1077 mf::build::exec_presets::AllSpanOrSingle());
1081 BuiltinAttributeProvider::NonDeletable,
1088 BuiltinAttributeProvider::NonDeletable,
1096 BuiltinAttributeProvider::Deletable,
1103 BuiltinAttributeProvider::Deletable,
1121 {&corner_custom_data,
1125 &face_custom_data});
1132 attribute_accessor_functions::accessor_functions_for_providers<providers>();
1134 if (owner ==
nullptr) {
1137 const Mesh &mesh = *
static_cast<const Mesh *
>(owner);
1139 case AttrDomain::Point:
1141 case AttrDomain::Edge:
1142 return mesh.edges_num;
1143 case AttrDomain::Face:
1144 return mesh.faces_num;
1145 case AttrDomain::Corner:
1146 return mesh.corners_num;
1152 return ELEM(domain, AttrDomain::Point, AttrDomain::Edge, AttrDomain::Face, AttrDomain::Corner);
1158 if (owner ==
nullptr) {
1161 const Mesh &mesh = *
static_cast<const Mesh *
>(owner);
1188std::optional<AttributeAccessor> MeshComponent::attributes()
const
1193std::optional<MutableAttributeAccessor> MeshComponent::attributes_for_write()
1195 Mesh *mesh = this->get_for_write();
void BKE_id_free(Main *bmain, void *idv)
Mesh * BKE_mesh_copy_for_eval(const Mesh &source)
#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(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Object is a sort of wrapper for general info.
const CPPType & type() const
void get_internal_single(void *r_value) const
static GVArray ForGArray(GArray<> array)
static GVArray ForSingle(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 bool is_empty() const
static VArray ForContainer(ContainerT container)
static VArray ForSpan(Span< T > values)
IndexRange index_range() const
void ensure_owns_direct_data() override
bool is_empty() const final
void replace(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GeometryComponentPtr copy() const override
bool owns_direct_data() const override
void count_memory(MemoryCounter &memory) const override
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 attribute_id) const final
DEGForeachIDComponentCallback callback
#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME)
#define MAKE_GET_ELEMENT_NUM_GETTER(NAME)
#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME)
void MEM_freeN(void *vmemh)
typename DefaultMixerStruct< T >::type DefaultMixer
void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, const VArray< T > &old_values, MutableSpan< T > r_values)
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)
ImplicitSharingPtr< GeometryComponent > GeometryComponentPtr
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)
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)
void remove_defgroup_index(MutableSpan< MDeformVert > dverts, int defgroup_index)
static const AttributeAccessorFunctions & get_mesh_accessor_functions_ref()
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 GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray)
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 void adapt_mesh_domain_corner_to_point_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)
VArray< float3 > mesh_normals_varray(const Mesh &mesh, const IndexMask &mask, AttrDomain domain)
static ComponentAttributeProviders create_attribute_providers_for_mesh()
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 interpolate(const T &a, const T &b, const FactorT &t)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
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
GVArray(* adapt_domain)(const void *owner, const GVArray &varray, AttrDomain from_domain, AttrDomain to_domain)
bool(* domain_supported)(const void *owner, AttrDomain domain)
int(* domain_size)(const void *owner, AttrDomain domain)
blender::BitVector is_loose_bits