89 const bool ensure_keys_exist,
97 Mesh &active_mesh = *
static_cast<Mesh *
>(active_object.
data);
104 auto topology_count_matches = [](
const Mesh &a,
const Mesh &
b) {
108 bool found_object =
false;
109 bool found_non_equal_count =
false;
112 if (ob_iter == &active_object) {
115 if (ob_iter->type !=
OB_MESH) {
124 if (topology_count_matches(*mesh, active_mesh)) {
130 const Mesh &mesh_orig = *
static_cast<const Mesh *
>(ob_iter->data);
131 if (topology_count_matches(mesh_orig, active_mesh)) {
135 found_non_equal_count =
true;
144 if (found_non_equal_count) {
149 if (compatible_objects.
is_empty()) {
151 reports,
RPT_WARNING,
"No additional selected meshes with equal vertex count to join");
155 if (!active_mesh.
key) {
164 for (
const ObjectInfo &info : compatible_objects) {
165 if (!info.name.endswith(
".L") && !info.name.endswith(
".R")) {
172 int mirror_count = 0;
173 int mirror_fail_count = 0;
174 int keys_changed = 0;
175 bool any_keys_added =
false;
176 for (
const ObjectInfo &info : compatible_objects) {
178 if (ensure_keys_exist) {
181 any_keys_added =
true;
195 if (!ensure_keys_exist) {
196 if (keys_changed == 0) {
210 if (any_keys_added && bmain) {
228 Mesh **r_mesh_mirror,
231 Mesh *mesh_mirror =
nullptr;
235 if (mesh_eval !=
nullptr) {
236 mesh_mirror = mesh_eval;
245 *r_mesh_mirror = mesh_mirror;
246 *r_em_mirror = em_mirror;
282 const Span<float3> positions = mesh_eval ? mesh_eval->vert_positions() : mesh->vert_positions();
286 vec[0] = -positions[index][0];
287 vec[1] = positions[index][1];
288 vec[2] = positions[index][2];
316 if ((isfinite(co[0]) ==
false) || (isfinite(co[1]) ==
false) || (isfinite(co[2]) ==
false)) {
358 return (
BMVert *)(poinval);
393static float *editmesh_get_mirror_uv(
394 BMEditMesh *em,
int axis,
float *uv,
float *mirrCent,
float *face_cent)
401 if (
isnan(uv[0]) || !isfinite(uv[0]) ||
isnan(uv[1]) || !isfinite(uv[1])) {
407 vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
409 cent_vec[0] = face_cent[0];
410 cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
413 vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
416 cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
417 cent_vec[1] = face_cent[1];
428 if ((
fabsf(cent[0] - cent_vec[0]) < 0.001f) && (
fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
434 if ((
fabsf(luv[0] - vec[0]) < 0.001f) && (
fabsf(luv[1] - vec[1]) < 0.001f)) {
453 v0 = std::min({mf->
v1, mf->
v2, mf->
v3, mf->
v4});
454 v1 = std::max({mf->
v1, mf->
v2, mf->
v3, mf->
v4});
457 v0 = std::min({mf->
v1, mf->
v2, mf->
v3});
458 v1 = std::min({mf->
v1, mf->
v2, mf->
v3});
461 return ((v0 * 39) ^ (v1 * 31));
467 if (a->
v1 ==
b->v1 && a->
v2 ==
b->v2 && a->
v3 ==
b->v3 && a->
v4 ==
b->v4) {
470 if (a->
v4 ==
b->v1 && a->
v1 ==
b->v2 && a->
v2 ==
b->v3 && a->
v3 ==
b->v4) {
473 if (a->
v3 ==
b->v1 && a->
v4 ==
b->v2 && a->
v1 ==
b->v3 && a->
v2 ==
b->v4) {
476 if (a->
v2 ==
b->v1 && a->
v3 ==
b->v2 && a->
v4 ==
b->v3 && a->
v1 ==
b->v4) {
481 if (a->
v1 ==
b->v1 && a->
v2 ==
b->v2 && a->
v3 ==
b->v3) {
484 if (a->
v3 ==
b->v1 && a->
v1 ==
b->v2 && a->
v2 ==
b->v3) {
487 if (a->
v2 ==
b->v1 && a->
v3 ==
b->v2 && a->
v1 ==
b->v3) {
504 const MFace *mf, *hashmf;
506 int *mirrorverts, *mirrorfaces;
518 const Span<float3> vert_positions = mesh_eval ? mesh_eval->vert_positions() :
519 mesh->vert_positions();
521 &(mesh_eval ? mesh_eval : mesh)->fdata_legacy,
CD_MFACE);
533 for (a = 0, mf = mface; a < totface; a++, mf++) {
537 for (a = 0, mf = mface; a < totface; a++, mf++) {
538 mirrormf.
v1 = mirrorverts[mf->
v3];
539 mirrormf.
v2 = mirrorverts[mf->
v2];
540 mirrormf.
v3 = mirrorverts[mf->
v1];
541 mirrormf.
v4 = (mf->
v4) ? mirrorverts[mf->
v4] : 0;
544 if (mf->
v4 && mirrormf.
v4 == 0) {
545 std::swap(mirrormf.
v1, mirrormf.
v3);
546 std::swap(mirrormf.
v2, mirrormf.
v4);
551 mirrorfaces[a * 2] = hashmf - mface;
555 mirrorfaces[a * 2] = -1;
608 const int *corner_verts,
613 for (
int j = face.
size(); j--;) {
615 const int v_idx = corner_verts[face[j]];
620 if (len_test < *r_len_best) {
621 *r_len_best = len_test;
622 *r_v_idx_best = v_idx;
647 const float mval_f[2] = {
float(mval[0]),
float(mval[1])};
650 const Span<float3> vert_positions = mesh_eval->vert_positions();
652 const Span<int> corner_verts = mesh_eval->corner_verts();
658 if (index_mp_to_orig) {
659 for (
const int i :
faces.index_range()) {
660 if (index_mp_to_orig[
i] == face_index) {
672 if (face_index <
faces.size()) {
687 if (index_mv_to_orig) {
688 v_idx_best = index_mv_to_orig[v_idx_best];
692 if ((v_idx_best !=
ORIGINDEX_NONE) && (v_idx_best < mesh->verts_num)) {
693 *r_index = v_idx_best;
730 if (edge_idx_best == 0 || edge_idx_best >
uint(mesh->
edges_num)) {
737 *r_index = edge_idx_best;
766 if (!
data->hide_vert.is_empty() &&
data->hide_vert[index]) {
776 data->v_idx_best = index;
821 const float mval_f[2] = {
float(mval[0]),
float(mval[1])};
827 if (mesh_eval ==
nullptr) {
834 data.region = region;
835 data.mval_f = mval_f;
837 data.v_idx_best = -1;
842 if (
data.v_idx_best == -1) {
846 *r_index =
data.v_idx_best;
860 if (cd_dvert_offset != -1) {
886 if (index == -1 || mesh->deform_verts().is_empty()) {
890 return &dverts[index];
917 for (
Object *obedit : objects) {
921 totelem[0] +=
bm->totvert;
922 totelem[1] +=
bm->totedge;
923 totelem[2] +=
bm->totface;
926 totelem_sel[0] +=
bm->totvertsel;
927 totelem_sel[1] +=
bm->totedgesel;
928 totelem_sel[2] +=
bm->totfacesel;
935 int elem_offset[4] = {0, 0, 0, 0};
936 for (
Object *obedit : objects) {
989 ot->name =
"Reorder Mesh Spatially";
990 ot->idname =
"MESH_OT_reorder_vertices_spatial";
992 "Reorder mesh faces and vertices based on their spatial position for better BVH building "
993 "and sculpting performance.";
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Key * BKE_key_add(Main *bmain, ID *id)
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
void BKE_keyblock_update_from_mesh(const Mesh *mesh, KeyBlock *kb)
void BKE_keyblock_convert_from_mesh(const Mesh *mesh, const Key *key, KeyBlock *kb)
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for materials.
int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
void BKE_mesh_foreach_mapped_vert(const Mesh *mesh, void(*func)(void *user_data, int index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
A BVH for high poly meshes.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
void BLI_ghash_insert(GHash *gh, void *key, void *val)
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ME_SCULPT_DYNAMIC_TOPOLOGY
Object is a sort of wrapper for general info.
void DRW_select_buffer_context_create(Depsgraph *depsgraph, blender::Span< Base * > bases, short select_mode)
uint DRW_select_buffer_sample_point(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const int center[2])
uint DRW_select_buffer_find_nearest_to_point(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const int center[2], uint id_min, uint id_max, uint *dist)
int ED_mesh_mirror_spatial_table_lookup(Object *ob, BMEditMesh *em, Mesh *mesh_eval, const float co[3])
void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
void ED_mesh_report_mirror_ex(ReportList &reports, int totmirr, int totfail, char selectmode)
void ED_mesh_mirror_spatial_table_end(Object *ob)
bool ED_mesh_mirrtopo_recalc_check(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirrtopo_init(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store, bool skip_em_vert_array_init)
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
void ED_view3d_select_id_validate(const ViewContext *vc)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
#define V3D_PROJ_TEST_CLIP_DEFAULT
Read Guarded memory(de)allocation.
#define BM_ELEM_CD_GET_FLOAT_P(ele, offset)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
BMesh const char void * data
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
BPy_StructRNA * depsgraph
void append(const T &value)
constexpr int64_t size() const
constexpr const T * data() const
constexpr IndexRange index_range() const
constexpr bool endswith(StringRef suffix) const
constexpr StringRef drop_suffix(int64_t n) const
GAttributeReader lookup(const StringRef attribute_id) const
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
void mesh_apply_spatial_organization(Mesh &mesh)
Object * context_active_object(const bContext *C)
void shape_key_mirror(Object *ob, KeyBlock *kb, bool use_topology, int &totmirr, int &totfail)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
void geometry_end(Object &ob)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
MeshRuntimeHandle * runtime
ListBase vertex_group_names
blender::VArraySpan< bool > hide_vert
struct ReportList * reports
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)