78 const float imat[4][4],
79 float3 **vert_positions_pp,
81 int **corner_verts_pp,
82 int **corner_edges_pp,
83 int *all_face_offsets,
103 float3 *vert_positions = *vert_positions_pp;
105 int *corner_verts = *corner_verts_pp;
106 int *corner_edges = *corner_edges_pp;
125 int *vgroup_index_map;
126 int vgroup_index_map_len;
128 ob_src, ob_dst, &vgroup_index_map_len);
130 dvert, mesh->
verts_num, vgroup_index_map, vgroup_index_map_len);
131 if (vgroup_index_map !=
nullptr) {
137 if (ob_src != ob_dst) {
141 mul_m4_m4m4(cmat, imat, ob_src->object_to_world().ptr());
158 float(*
cos)[3] = ((float(*)[3])kb->data) + *vertofs;
165 float(*ocos)[3] =
static_cast<float(*)[3]
>(okb->
data);
188 float(*
cos)[3] = ((float(*)[3])kb->data) + *vertofs;
194 float(*ocos)[3] =
static_cast<float(*)[3]
>(okb->
data);
215 for (a = 0; a < mesh->
edges_num; a++, edge++) {
221 if (ob_src != ob_dst) {
237 corner_verts[a] += *vertofs;
238 corner_edges[a] += *edgeofs;
244 const int totcol = std::max(ob_src->
totcol, 1);
247 for (a = 1; a <= totcol; a++) {
252 for (;
b < matar.
size();
b++) {
253 if (ma == matar[
b]) {
259 if (
b == matar.
size()) {
266 matmap[a - 1] = matar.
size();
283 if (!material_indices && matar.
size() > 1) {
287 if (material_indices) {
290 const int mat_index = std::clamp(material_indices[a + *polyofs], 0, totcol - 1);
291 material_indices[a + *polyofs] = matmap[mat_index];
295 const Span<int> src_face_offsets = mesh->face_offsets();
296 int *face_offsets = all_face_offsets + *polyofs;
298 face_offsets[
i] = src_face_offsets[
i] + *loopofs;
326 int max_face_set = 0;
327 for (
const int i : face_sets.
span.index_range()) {
330 if (face_sets.
span[
i] <= *face_set_offset) {
331 face_sets.
span[
i] += *face_set_offset;
333 max_face_set =
max_ii(max_face_set, face_sets.
span[
i]);
335 *face_set_offset = max_face_set;
347 Key *key, *nkey =
nullptr;
349 int a, totedge = 0, totvert = 0;
350 int totloop = 0, faces_num = 0, vertofs;
351 int i, haskey = 0, edgeofs, loopofs, polyofs;
352 bool ok =
false, join_parent =
false;
353 CustomData vert_data, edge_data, ldata, face_data;
370 if (ob_iter->type ==
OB_MESH) {
371 mesh =
static_cast<Mesh *
>(ob_iter->data);
382 if ((ob->
parent !=
nullptr) && (ob_iter == ob->
parent)) {
420 "Joining results in %d vertices, limit is %ld",
428 for (a = 0; a < ob->
totcol; a++) {
448 kb->data =
MEM_callocN(
sizeof(
float[3]) * totvert,
"join_shapekey");
449 kb->totelem = totvert;
461 int face_set_id_offset = 0;
467 if ((ob != ob_iter) && (ob_iter->type ==
OB_MESH)) {
468 mesh =
static_cast<Mesh *
>(ob_iter->data);
490 if (mesh->
key && key) {
511 kbn->
data =
MEM_callocN(
sizeof(
float[3]) * totvert,
"joined_shapekey");
522 kb_map[
i]->
relative = index_map[kb->relative];
549 face_offsets[faces_num] = totloop;
597 if (ob_iter->type ==
OB_MESH) {
634 mesh =
static_cast<Mesh *
>(ob->
data);
655 for (a = 1; a <= ob->
totcol; a++) {
661 for (a = 1; a <= mesh->
totcol; a++) {
662 ma = mesh->
mat[a - 1];
672 if (ob->
totcol == 0 && matar.
size() == 1 && matar[0] ==
nullptr) {
676 const int totcol = matar.
size();
679 std::copy_n(matar.
data(), totcol, mesh->
mat);
721 const bool ensure_keys_exist,
728 Mesh &active_mesh = *
static_cast<Mesh *
>(active_object.
data);
735 auto topology_count_matches = [](
const Mesh &a,
const Mesh &
b) {
739 bool found_object =
false;
740 bool found_non_equal_count =
false;
743 if (ob_iter == &active_object) {
746 if (ob_iter->type !=
OB_MESH) {
755 if (topology_count_matches(*mesh, active_mesh)) {
761 const Mesh &mesh_orig = *
static_cast<const Mesh *
>(ob_iter->data);
762 if (topology_count_matches(mesh_orig, active_mesh)) {
766 found_non_equal_count =
true;
775 if (found_non_equal_count) {
780 if (compatible_objects.
is_empty()) {
782 reports,
RPT_WARNING,
"No additional selected meshes with equal vertex count to join");
786 if (!active_mesh.
key) {
794 int keys_changed = 0;
795 bool any_keys_added =
false;
796 for (
const ObjectInfo &info : compatible_objects) {
797 if (ensure_keys_exist) {
800 any_keys_added =
true;
808 if (!ensure_keys_exist) {
809 if (keys_changed == 0) {
819 if (any_keys_added && bmain) {
837 Mesh **r_mesh_mirror,
840 Mesh *mesh_mirror =
nullptr;
844 if (mesh_eval !=
nullptr) {
845 mesh_mirror = mesh_eval;
854 *r_mesh_mirror = mesh_mirror;
855 *r_em_mirror = em_mirror;
891 const Span<float3> positions = mesh_eval ? mesh_eval->vert_positions() : mesh->vert_positions();
895 vec[0] = -positions[index][0];
896 vec[1] = positions[index][1];
897 vec[2] = positions[index][2];
925 if ((isfinite(co[0]) ==
false) || (isfinite(co[1]) ==
false) || (isfinite(co[2]) ==
false)) {
967 return (
BMVert *)(poinval);
1002static float *editmesh_get_mirror_uv(
1003 BMEditMesh *em,
int axis,
float *uv,
float *mirrCent,
float *face_cent)
1010 if (
isnan(uv[0]) || !isfinite(uv[0]) ||
isnan(uv[1]) || !isfinite(uv[1])) {
1016 vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
1018 cent_vec[0] = face_cent[0];
1019 cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
1022 vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
1025 cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
1026 cent_vec[1] = face_cent[1];
1037 if ((
fabsf(cent[0] - cent_vec[0]) < 0.001f) && (
fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
1043 if ((
fabsf(luv[0] - vec[0]) < 0.001f) && (
fabsf(luv[1] - vec[1]) < 0.001f)) {
1062 v0 = std::min({mf->
v1, mf->
v2, mf->
v3, mf->
v4});
1063 v1 = std::max({mf->
v1, mf->
v2, mf->
v3, mf->
v4});
1066 v0 = std::min({mf->
v1, mf->
v2, mf->
v3});
1067 v1 = std::min({mf->
v1, mf->
v2, mf->
v3});
1070 return ((v0 * 39) ^ (v1 * 31));
1076 if (a->
v1 ==
b->v1 && a->
v2 ==
b->v2 && a->
v3 ==
b->v3 && a->
v4 ==
b->v4) {
1079 if (a->
v4 ==
b->v1 && a->
v1 ==
b->v2 && a->
v2 ==
b->v3 && a->
v3 ==
b->v4) {
1082 if (a->
v3 ==
b->v1 && a->
v4 ==
b->v2 && a->
v1 ==
b->v3 && a->
v2 ==
b->v4) {
1085 if (a->
v2 ==
b->v1 && a->
v3 ==
b->v2 && a->
v4 ==
b->v3 && a->
v1 ==
b->v4) {
1090 if (a->
v1 ==
b->v1 && a->
v2 ==
b->v2 && a->
v3 ==
b->v3) {
1093 if (a->
v3 ==
b->v1 && a->
v1 ==
b->v2 && a->
v2 ==
b->v3) {
1096 if (a->
v2 ==
b->v1 && a->
v3 ==
b->v2 && a->
v1 ==
b->v3) {
1113 const MFace *mf, *hashmf;
1115 int *mirrorverts, *mirrorfaces;
1127 const Span<float3> vert_positions = mesh_eval ? mesh_eval->vert_positions() :
1128 mesh->vert_positions();
1130 &(mesh_eval ? mesh_eval : mesh)->fdata_legacy,
CD_MFACE);
1142 for (a = 0, mf = mface; a < totface; a++, mf++) {
1146 for (a = 0, mf = mface; a < totface; a++, mf++) {
1147 mirrormf.
v1 = mirrorverts[mf->
v3];
1148 mirrormf.
v2 = mirrorverts[mf->
v2];
1149 mirrormf.
v3 = mirrorverts[mf->
v1];
1150 mirrormf.
v4 = (mf->
v4) ? mirrorverts[mf->
v4] : 0;
1153 if (mf->
v4 && mirrormf.
v4 == 0) {
1154 std::swap(mirrormf.
v1, mirrormf.
v3);
1155 std::swap(mirrormf.
v2, mirrormf.
v4);
1160 mirrorfaces[a * 2] = hashmf - mface;
1164 mirrorfaces[a * 2] = -1;
1201 if ((*r_index) == 0 || (*r_index) >
uint(mesh->
faces_num)) {
1213 const float mval[2],
1217 const int *corner_verts,
1222 for (
int j = face.
size(); j--;) {
1224 const int v_idx = corner_verts[face[j]];
1229 if (len_test < *r_len_best) {
1230 *r_len_best = len_test;
1231 *r_v_idx_best = v_idx;
1256 const float mval_f[2] = {float(mval[0]), float(mval[1])};
1259 const Span<float3> vert_positions = mesh_eval->vert_positions();
1261 const Span<int> corner_verts = mesh_eval->corner_verts();
1267 if (index_mp_to_orig) {
1268 for (
const int i :
faces.index_range()) {
1269 if (index_mp_to_orig[
i] == face_index) {
1274 corner_verts.
data(),
1281 if (face_index <
faces.size()) {
1286 corner_verts.
data(),
1296 if (index_mv_to_orig) {
1297 v_idx_best = index_mv_to_orig[v_idx_best];
1301 if ((v_idx_best !=
ORIGINDEX_NONE) && (v_idx_best < mesh->verts_num)) {
1302 *r_index = v_idx_best;
1339 if (edge_idx_best == 0 || edge_idx_best >
uint(mesh->
edges_num)) {
1346 *r_index = edge_idx_best;
1375 if (!
data->hide_vert.is_empty() &&
data->hide_vert[index]) {
1385 data->v_idx_best = index;
1417 if ((*r_index) == 0 || (*r_index) >
uint(mesh->
verts_num)) {
1430 const float mval_f[2] = {float(mval[0]), float(mval[1])};
1436 if (mesh_eval ==
nullptr) {
1443 data.region = region;
1444 data.mval_f = mval_f;
1446 data.v_idx_best = -1;
1451 if (
data.v_idx_best == -1) {
1455 *r_index =
data.v_idx_best;
1469 if (cd_dvert_offset != -1) {
1495 if (index == -1 || mesh->deform_verts().is_empty()) {
1499 return &dverts[index];
1526 for (
Object *obedit : objects) {
1530 totelem[0] +=
bm->totvert;
1531 totelem[1] +=
bm->totedge;
1532 totelem[2] +=
bm->totface;
1535 totelem_sel[0] +=
bm->totvertsel;
1536 totelem_sel[1] +=
bm->totedgesel;
1537 totelem_sel[2] +=
bm->totfacesel;
1544 int elem_offset[4] = {0, 0, 0, 0};
1545 for (
Object *obedit : objects) {
#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)
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_reset(CustomData *data)
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data_named(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
const CustomData_MeshMasks CD_MASK_MESH
void * CustomData_get_for_write(CustomData *data, int index, eCustomDataType type, int totelem)
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)
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
copy shape-key attributes, but not key data or name/UID.
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
void BKE_key_sort(Key *key)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
ID * BKE_id_copy(Main *bmain, const ID *id)
const char * BKE_id_name(const ID &id)
void BKE_id_free_ex(Main *bmain, void *idv, int flag_orig, bool use_flag_from_idtag)
General operations, lookup, etc. for materials.
void BKE_objects_materials_sync_length_all(Main *bmain, ID *id)
Material * BKE_object_material_get(Object *ob, short act)
int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
Mesh * BKE_mesh_from_object(Object *ob)
void BKE_mesh_clear_geometry(Mesh *mesh)
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)
void multiresModifier_prepare_join(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
MultiresModifierData * get_multires_modifier(Scene *scene, Object *ob, bool use_first)
General operations, lookup, etc. for blender objects.
void BKE_object_apply_mat4_ex(Object *ob, const float mat[4][4], Object *parent, const float parentinv[4][4], bool use_compat)
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
void BKE_object_free_derived_caches(Object *ob)
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)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
MINLINE int max_ii(int a, int b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void mul_m4_v3(const float M[4][4], float r[3])
void invert_m4_m4_safe_ortho(float inverse[4][4], const float mat[4][4])
MINLINE void copy_v3_v3(float r[3], const float a[3])
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)
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_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
void append(const T &value)
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
void * MEM_mallocN(size_t len, const char *str)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
bool iter_other(Main *bmain, Object *orig_ob, bool include_orig, bool(*callback)(Object *ob, void *callback_data), void *callback_data)
bool multires_update_totlevels(Object *ob, void *totlevel_v)
void base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
const ImplicitSharingInfo * info_for_mem_free(void *data)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
MeshRuntimeHandle * runtime
ListBase vertex_group_names
int * face_offset_indices
int vertex_group_active_index
blender::VArraySpan< bool > hide_vert
MutableVArraySpan< T > span
struct ReportList * reports
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)