Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh.cc
- This file was moved from source/blender/blenkernel/intern/mesh.c.
| Show First 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int flag) | ||||
| CustomData_MeshMasks mask = CD_MASK_MESH; | CustomData_MeshMasks mask = CD_MASK_MESH; | ||||
| if (mesh_src->id.tag & LIB_TAG_NO_MAIN) { | if (mesh_src->id.tag & LIB_TAG_NO_MAIN) { | ||||
| /* For copies in depsgraph, keep data like origindex and orco. */ | /* For copies in depsgraph, keep data like origindex and orco. */ | ||||
| CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); | CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); | ||||
| } | } | ||||
| mesh_dst->mat = MEM_dupallocN(mesh_src->mat); | mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat); | ||||
| BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); | BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); | ||||
| const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; | const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; | ||||
| CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); | CustomData_copy(&mesh_src->vdata, &mesh_dst->vdata, mask.vmask, alloc_type, mesh_dst->totvert); | ||||
| CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); | CustomData_copy(&mesh_src->edata, &mesh_dst->edata, mask.emask, alloc_type, mesh_dst->totedge); | ||||
| CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop); | CustomData_copy(&mesh_src->ldata, &mesh_dst->ldata, mask.lmask, alloc_type, mesh_dst->totloop); | ||||
| CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly); | CustomData_copy(&mesh_src->pdata, &mesh_dst->pdata, mask.pmask, alloc_type, mesh_dst->totpoly); | ||||
| if (do_tessface) { | if (do_tessface) { | ||||
| CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, alloc_type, mesh_dst->totface); | CustomData_copy(&mesh_src->fdata, &mesh_dst->fdata, mask.fmask, alloc_type, mesh_dst->totface); | ||||
| } | } | ||||
| else { | else { | ||||
| mesh_tessface_clear_intern(mesh_dst, false); | mesh_tessface_clear_intern(mesh_dst, false); | ||||
| } | } | ||||
| BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); | BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); | ||||
| mesh_dst->edit_mesh = NULL; | mesh_dst->edit_mesh = nullptr; | ||||
| mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect); | mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect); | ||||
| /* TODO: Do we want to add flag to prevent this? */ | /* TODO: Do we want to add flag to prevent this? */ | ||||
| if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { | if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { | ||||
| BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag); | BKE_id_copy_ex(bmain, &mesh_src->key->id, (ID **)&mesh_dst->key, flag); | ||||
| /* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */ | /* XXX This is not nice, we need to make BKE_id_copy_ex fully re-entrant... */ | ||||
| mesh_dst->key->from = &mesh_dst->id; | mesh_dst->key->from = &mesh_dst->id; | ||||
| } | } | ||||
| } | } | ||||
| static void mesh_free_data(ID *id) | static void mesh_free_data(ID *id) | ||||
| { | { | ||||
| Mesh *mesh = (Mesh *)id; | Mesh *mesh = (Mesh *)id; | ||||
| BLI_freelistN(&mesh->vertex_group_names); | BLI_freelistN(&mesh->vertex_group_names); | ||||
| if (mesh->edit_mesh) { | if (mesh->edit_mesh) { | ||||
| if (mesh->edit_mesh->is_shallow_copy == false) { | if (mesh->edit_mesh->is_shallow_copy == false) { | ||||
| BKE_editmesh_free_data(mesh->edit_mesh); | BKE_editmesh_free_data(mesh->edit_mesh); | ||||
| } | } | ||||
| MEM_freeN(mesh->edit_mesh); | MEM_freeN(mesh->edit_mesh); | ||||
| mesh->edit_mesh = NULL; | mesh->edit_mesh = nullptr; | ||||
| } | } | ||||
| BKE_mesh_runtime_clear_cache(mesh); | BKE_mesh_runtime_clear_cache(mesh); | ||||
| mesh_clear_geometry(mesh); | mesh_clear_geometry(mesh); | ||||
| MEM_SAFE_FREE(mesh->mat); | MEM_SAFE_FREE(mesh->mat); | ||||
| } | } | ||||
| static void mesh_foreach_id(ID *id, LibraryForeachIDData *data) | static void mesh_foreach_id(ID *id, LibraryForeachIDData *data) | ||||
| { | { | ||||
| Mesh *mesh = (Mesh *)id; | Mesh *mesh = (Mesh *)id; | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->texcomesh, IDWALK_CB_NEVER_SELF); | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->key, IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->key, IDWALK_CB_USER); | ||||
| for (int i = 0; i < mesh->totcol; i++) { | for (int i = 0; i < mesh->totcol; i++) { | ||||
| BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->mat[i], IDWALK_CB_USER); | BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, mesh->mat[i], IDWALK_CB_USER); | ||||
| } | } | ||||
| } | } | ||||
| static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) | static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address) | ||||
| { | { | ||||
| Mesh *mesh = (Mesh *)id; | Mesh *mesh = (Mesh *)id; | ||||
| const bool is_undo = BLO_write_is_undo(writer); | const bool is_undo = BLO_write_is_undo(writer); | ||||
| CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; | CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE]; | ||||
| CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; | CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE]; | ||||
| CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; | CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE]; | ||||
| CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; | CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE]; | ||||
| CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; | CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; | ||||
| /* cache only - don't write */ | /* cache only - don't write */ | ||||
| mesh->mface = NULL; | mesh->mface = nullptr; | ||||
| mesh->totface = 0; | mesh->totface = 0; | ||||
| memset(&mesh->fdata, 0, sizeof(mesh->fdata)); | memset(&mesh->fdata, 0, sizeof(mesh->fdata)); | ||||
| memset(&mesh->runtime, 0, sizeof(mesh->runtime)); | memset(&mesh->runtime, 0, sizeof(mesh->runtime)); | ||||
| flayers = flayers_buff; | flayers = flayers_buff; | ||||
| /* Do not store actual geometry data in case this is a library override ID. */ | /* Do not store actual geometry data in case this is a library override ID. */ | ||||
| if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { | if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { | ||||
| mesh->mvert = NULL; | mesh->mvert = nullptr; | ||||
| mesh->totvert = 0; | mesh->totvert = 0; | ||||
| memset(&mesh->vdata, 0, sizeof(mesh->vdata)); | memset(&mesh->vdata, 0, sizeof(mesh->vdata)); | ||||
| vlayers = vlayers_buff; | vlayers = vlayers_buff; | ||||
| mesh->medge = NULL; | mesh->medge = nullptr; | ||||
| mesh->totedge = 0; | mesh->totedge = 0; | ||||
| memset(&mesh->edata, 0, sizeof(mesh->edata)); | memset(&mesh->edata, 0, sizeof(mesh->edata)); | ||||
| elayers = elayers_buff; | elayers = elayers_buff; | ||||
| mesh->mloop = NULL; | mesh->mloop = nullptr; | ||||
| mesh->totloop = 0; | mesh->totloop = 0; | ||||
| memset(&mesh->ldata, 0, sizeof(mesh->ldata)); | memset(&mesh->ldata, 0, sizeof(mesh->ldata)); | ||||
| llayers = llayers_buff; | llayers = llayers_buff; | ||||
| mesh->mpoly = NULL; | mesh->mpoly = nullptr; | ||||
| mesh->totpoly = 0; | mesh->totpoly = 0; | ||||
| memset(&mesh->pdata, 0, sizeof(mesh->pdata)); | memset(&mesh->pdata, 0, sizeof(mesh->pdata)); | ||||
| players = players_buff; | players = players_buff; | ||||
| } | } | ||||
| else { | else { | ||||
| CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); | CustomData_blend_write_prepare(&mesh->vdata, &vlayers, vlayers_buff, ARRAY_SIZE(vlayers_buff)); | ||||
| CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); | CustomData_blend_write_prepare(&mesh->edata, &elayers, elayers_buff, ARRAY_SIZE(elayers_buff)); | ||||
| CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); | CustomData_blend_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); | ||||
| ▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | static void mesh_blend_read_data(BlendDataReader *reader, ID *id) | ||||
| CustomData_blend_read(reader, &mesh->vdata, mesh->totvert); | CustomData_blend_read(reader, &mesh->vdata, mesh->totvert); | ||||
| CustomData_blend_read(reader, &mesh->edata, mesh->totedge); | CustomData_blend_read(reader, &mesh->edata, mesh->totedge); | ||||
| CustomData_blend_read(reader, &mesh->fdata, mesh->totface); | CustomData_blend_read(reader, &mesh->fdata, mesh->totface); | ||||
| CustomData_blend_read(reader, &mesh->ldata, mesh->totloop); | CustomData_blend_read(reader, &mesh->ldata, mesh->totloop); | ||||
| CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); | CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); | ||||
| mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; | mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; | ||||
| mesh->edit_mesh = NULL; | mesh->edit_mesh = nullptr; | ||||
| BKE_mesh_runtime_reset(mesh); | BKE_mesh_runtime_reset(mesh); | ||||
| /* happens with old files */ | /* happens with old files */ | ||||
| if (mesh->mselect == NULL) { | if (mesh->mselect == nullptr) { | ||||
| mesh->totselect = 0; | mesh->totselect = 0; | ||||
| } | } | ||||
| if (BLO_read_requires_endian_switch(reader) && mesh->tface) { | if (BLO_read_requires_endian_switch(reader) && mesh->tface) { | ||||
| TFace *tf = mesh->tface; | TFace *tf = mesh->tface; | ||||
| for (int i = 0; i < mesh->totface; i++, tf++) { | for (int i = 0; i < mesh->totface; i++, tf++) { | ||||
| BLI_endian_switch_uint32_array(tf->col, 4); | BLI_endian_switch_uint32_array(tf->col, 4); | ||||
| } | } | ||||
| Show All 25 Lines | for (int a = 0; a < me->totcol; a++) { | ||||
| BLO_expand(expander, me->mat[a]); | BLO_expand(expander, me->mat[a]); | ||||
| } | } | ||||
| BLO_expand(expander, me->key); | BLO_expand(expander, me->key); | ||||
| BLO_expand(expander, me->texcomesh); | BLO_expand(expander, me->texcomesh); | ||||
| } | } | ||||
| IDTypeInfo IDType_ID_ME = { | IDTypeInfo IDType_ID_ME = { | ||||
| .id_code = ID_ME, | ID_ME, | ||||
| .id_filter = FILTER_ID_ME, | FILTER_ID_ME, | ||||
| .main_listbase_index = INDEX_ID_ME, | INDEX_ID_ME, | ||||
| .struct_size = sizeof(Mesh), | sizeof(Mesh), | ||||
| .name = "Mesh", | "Mesh", | ||||
| .name_plural = "meshes", | "meshes", | ||||
| .translation_context = BLT_I18NCONTEXT_ID_MESH, | BLT_I18NCONTEXT_ID_MESH, | ||||
| .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, | IDTYPE_FLAGS_APPEND_IS_REUSABLE, | ||||
| .init_data = mesh_init_data, | mesh_init_data, | ||||
| .copy_data = mesh_copy_data, | mesh_copy_data, | ||||
| .free_data = mesh_free_data, | mesh_free_data, | ||||
| .make_local = NULL, | nullptr, | ||||
| .foreach_id = mesh_foreach_id, | mesh_foreach_id, | ||||
| .foreach_cache = NULL, | nullptr, | ||||
| .owner_get = NULL, | nullptr, | ||||
| mesh_blend_write, | |||||
| .blend_write = mesh_blend_write, | mesh_blend_read_data, | ||||
| .blend_read_data = mesh_blend_read_data, | mesh_blend_read_lib, | ||||
| .blend_read_lib = mesh_blend_read_lib, | mesh_read_expand, | ||||
| .blend_read_expand = mesh_read_expand, | nullptr, | ||||
| nullptr, | |||||
| .blend_read_undo_preserve = NULL, | |||||
| .lib_override_apply_post = NULL, | |||||
| }; | }; | ||||
mont29: In the future, please keep named fields info, even though cpp does not support it in its syntax… | |||||
Not Done Inline ActionsSure, will do, sorry about that. HooglyBoogly: Sure, will do, sorry about that. | |||||
| enum { | enum { | ||||
| MESHCMP_DVERT_WEIGHTMISMATCH = 1, | MESHCMP_DVERT_WEIGHTMISMATCH = 1, | ||||
| MESHCMP_DVERT_GROUPMISMATCH, | MESHCMP_DVERT_GROUPMISMATCH, | ||||
| MESHCMP_DVERT_TOTGROUPMISMATCH, | MESHCMP_DVERT_TOTGROUPMISMATCH, | ||||
| MESHCMP_LOOPCOLMISMATCH, | MESHCMP_LOOPCOLMISMATCH, | ||||
| MESHCMP_LOOPUVMISMATCH, | MESHCMP_LOOPUVMISMATCH, | ||||
| MESHCMP_LOOPMISMATCH, | MESHCMP_LOOPMISMATCH, | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | for (int i2 = 0; i2 < c2->totlayer; i2++) { | ||||
| if (l1->type != l2->type || !STREQ(l1->name, l2->name)) { | if (l1->type != l2->type || !STREQ(l1->name, l2->name)) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* At this point `l1` and `l2` have the same name and type, so they should be compared. */ | /* At this point `l1` and `l2` have the same name and type, so they should be compared. */ | ||||
| switch (l1->type) { | switch (l1->type) { | ||||
| case CD_MVERT: { | case CD_MVERT: { | ||||
| MVert *v1 = l1->data; | MVert *v1 = (MVert *)l1->data; | ||||
| MVert *v2 = l2->data; | MVert *v2 = (MVert *)l2->data; | ||||
| int vtot = m1->totvert; | int vtot = m1->totvert; | ||||
| for (j = 0; j < vtot; j++, v1++, v2++) { | for (j = 0; j < vtot; j++, v1++, v2++) { | ||||
| for (int k = 0; k < 3; k++) { | for (int k = 0; k < 3; k++) { | ||||
| if (compare_threshold_relative(v1->co[k], v2->co[k], thresh)) { | if (compare_threshold_relative(v1->co[k], v2->co[k], thresh)) { | ||||
| return MESHCMP_VERTCOMISMATCH; | return MESHCMP_VERTCOMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| /* I don't care about normals, let's just do coordinates. */ | /* I don't care about normals, let's just do coordinates. */ | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| /* We're order-agnostic for edges here. */ | /* We're order-agnostic for edges here. */ | ||||
| case CD_MEDGE: { | case CD_MEDGE: { | ||||
| MEdge *e1 = l1->data; | MEdge *e1 = (MEdge *)l1->data; | ||||
| MEdge *e2 = l2->data; | MEdge *e2 = (MEdge *)l2->data; | ||||
| int etot = m1->totedge; | int etot = m1->totedge; | ||||
| EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); | EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); | ||||
| for (j = 0; j < etot; j++, e1++) { | for (j = 0; j < etot; j++, e1++) { | ||||
| BLI_edgehash_insert(eh, e1->v1, e1->v2, e1); | BLI_edgehash_insert(eh, e1->v1, e1->v2, e1); | ||||
| } | } | ||||
| for (j = 0; j < etot; j++, e2++) { | for (j = 0; j < etot; j++, e2++) { | ||||
| if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) { | if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) { | ||||
| return MESHCMP_EDGEUNKNOWN; | return MESHCMP_EDGEUNKNOWN; | ||||
| } | } | ||||
| } | } | ||||
| BLI_edgehash_free(eh, NULL); | BLI_edgehash_free(eh, nullptr); | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_MPOLY: { | case CD_MPOLY: { | ||||
| MPoly *p1 = l1->data; | MPoly *p1 = (MPoly *)l1->data; | ||||
| MPoly *p2 = l2->data; | MPoly *p2 = (MPoly *)l2->data; | ||||
| int ptot = m1->totpoly; | int ptot = m1->totpoly; | ||||
| for (j = 0; j < ptot; j++, p1++, p2++) { | for (j = 0; j < ptot; j++, p1++, p2++) { | ||||
| MLoop *lp1, *lp2; | MLoop *lp1, *lp2; | ||||
| int k; | int k; | ||||
| if (p1->totloop != p2->totloop) { | if (p1->totloop != p2->totloop) { | ||||
| return MESHCMP_POLYMISMATCH; | return MESHCMP_POLYMISMATCH; | ||||
| } | } | ||||
| lp1 = m1->mloop + p1->loopstart; | lp1 = m1->mloop + p1->loopstart; | ||||
| lp2 = m2->mloop + p2->loopstart; | lp2 = m2->mloop + p2->loopstart; | ||||
| for (k = 0; k < p1->totloop; k++, lp1++, lp2++) { | for (k = 0; k < p1->totloop; k++, lp1++, lp2++) { | ||||
| if (lp1->v != lp2->v) { | if (lp1->v != lp2->v) { | ||||
| return MESHCMP_POLYVERTMISMATCH; | return MESHCMP_POLYVERTMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_MLOOP: { | case CD_MLOOP: { | ||||
| MLoop *lp1 = l1->data; | MLoop *lp1 = (MLoop *)l1->data; | ||||
| MLoop *lp2 = l2->data; | MLoop *lp2 = (MLoop *)l2->data; | ||||
| int ltot = m1->totloop; | int ltot = m1->totloop; | ||||
| for (j = 0; j < ltot; j++, lp1++, lp2++) { | for (j = 0; j < ltot; j++, lp1++, lp2++) { | ||||
| if (lp1->v != lp2->v) { | if (lp1->v != lp2->v) { | ||||
| return MESHCMP_LOOPMISMATCH; | return MESHCMP_LOOPMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_MLOOPUV: { | case CD_MLOOPUV: { | ||||
| MLoopUV *lp1 = l1->data; | MLoopUV *lp1 = (MLoopUV *)l1->data; | ||||
| MLoopUV *lp2 = l2->data; | MLoopUV *lp2 = (MLoopUV *)l2->data; | ||||
| int ltot = m1->totloop; | int ltot = m1->totloop; | ||||
| for (j = 0; j < ltot; j++, lp1++, lp2++) { | for (j = 0; j < ltot; j++, lp1++, lp2++) { | ||||
| if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) { | if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) { | ||||
| return MESHCMP_LOOPUVMISMATCH; | return MESHCMP_LOOPUVMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_MLOOPCOL: { | case CD_MLOOPCOL: { | ||||
| MLoopCol *lp1 = l1->data; | MLoopCol *lp1 = (MLoopCol *)l1->data; | ||||
| MLoopCol *lp2 = l2->data; | MLoopCol *lp2 = (MLoopCol *)l2->data; | ||||
| int ltot = m1->totloop; | int ltot = m1->totloop; | ||||
| for (j = 0; j < ltot; j++, lp1++, lp2++) { | for (j = 0; j < ltot; j++, lp1++, lp2++) { | ||||
| if (lp1->r != lp2->r || lp1->g != lp2->g || lp1->b != lp2->b || lp1->a != lp2->a) { | if (lp1->r != lp2->r || lp1->g != lp2->g || lp1->b != lp2->b || lp1->a != lp2->a) { | ||||
| return MESHCMP_LOOPCOLMISMATCH; | return MESHCMP_LOOPCOLMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_MDEFORMVERT: { | case CD_MDEFORMVERT: { | ||||
| MDeformVert *dv1 = l1->data; | MDeformVert *dv1 = (MDeformVert *)l1->data; | ||||
| MDeformVert *dv2 = l2->data; | MDeformVert *dv2 = (MDeformVert *)l2->data; | ||||
| int dvtot = m1->totvert; | int dvtot = m1->totvert; | ||||
| for (j = 0; j < dvtot; j++, dv1++, dv2++) { | for (j = 0; j < dvtot; j++, dv1++, dv2++) { | ||||
| int k; | int k; | ||||
| MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw; | MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw; | ||||
| if (dv1->totweight != dv2->totweight) { | if (dv1->totweight != dv2->totweight) { | ||||
| return MESHCMP_DVERT_TOTGROUPMISMATCH; | return MESHCMP_DVERT_TOTGROUPMISMATCH; | ||||
| } | } | ||||
| for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) { | for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) { | ||||
| if (dw1->def_nr != dw2->def_nr) { | if (dw1->def_nr != dw2->def_nr) { | ||||
| return MESHCMP_DVERT_GROUPMISMATCH; | return MESHCMP_DVERT_GROUPMISMATCH; | ||||
| } | } | ||||
| if (fabsf(dw1->weight - dw2->weight) > thresh) { | if (fabsf(dw1->weight - dw2->weight) > thresh) { | ||||
| return MESHCMP_DVERT_WEIGHTMISMATCH; | return MESHCMP_DVERT_WEIGHTMISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_FLOAT: { | case CD_PROP_FLOAT: { | ||||
| const float *l1_data = l1->data; | const float *l1_data = (float *)l1->data; | ||||
| const float *l2_data = l2->data; | const float *l2_data = (float *)l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { | if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_FLOAT2: { | case CD_PROP_FLOAT2: { | ||||
| const float(*l1_data)[2] = l1->data; | const float(*l1_data)[2] = (float(*)[2])l1->data; | ||||
| const float(*l2_data)[2] = l2->data; | const float(*l2_data)[2] = (float(*)[2])l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { | if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { | if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_FLOAT3: { | case CD_PROP_FLOAT3: { | ||||
| const float(*l1_data)[3] = l1->data; | const float(*l1_data)[3] = (float(*)[3])l1->data; | ||||
| const float(*l2_data)[3] = l2->data; | const float(*l2_data)[3] = (float(*)[3])l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { | if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { | if (compare_threshold_relative(l1_data[i][1], l2_data[i][1], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| if (compare_threshold_relative(l1_data[i][2], l2_data[i][2], thresh)) { | if (compare_threshold_relative(l1_data[i][2], l2_data[i][2], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_INT32: { | case CD_PROP_INT32: { | ||||
| const int *l1_data = l1->data; | const int *l1_data = (int *)l1->data; | ||||
| const int *l2_data = l2->data; | const int *l2_data = (int *)l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| if (l1_data[i] != l2_data[i]) { | if (l1_data[i] != l2_data[i]) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_BOOL: { | case CD_PROP_BOOL: { | ||||
| const bool *l1_data = l1->data; | const bool *l1_data = (bool *)l1->data; | ||||
| const bool *l2_data = l2->data; | const bool *l2_data = (bool *)l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| if (l1_data[i] != l2_data[i]) { | if (l1_data[i] != l2_data[i]) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case CD_PROP_COLOR: { | case CD_PROP_COLOR: { | ||||
| const MPropCol *l1_data = l1->data; | const MPropCol *l1_data = (MPropCol *)l1->data; | ||||
| const MPropCol *l2_data = l2->data; | const MPropCol *l2_data = (MPropCol *)l2->data; | ||||
| for (int i = 0; i < total_length; i++) { | for (int i = 0; i < total_length; i++) { | ||||
| for (j = 0; j < 4; j++) { | for (j = 0; j < 4; j++) { | ||||
| if (compare_threshold_relative(l1_data[i].color[j], l2_data[i].color[j], thresh)) { | if (compare_threshold_relative(l1_data[i].color[j], l2_data[i].color[j], thresh)) { | ||||
| return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | return MESHCMP_ATTRIBUTE_VALUE_MISMATCH; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) | ||||
| if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1->totloop, me1, me2, thresh))) { | if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1->totloop, me1, me2, thresh))) { | ||||
| return cmpcode_to_str(c); | return cmpcode_to_str(c); | ||||
| } | } | ||||
| if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1->totpoly, me1, me2, thresh))) { | if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1->totpoly, me1, me2, thresh))) { | ||||
| return cmpcode_to_str(c); | return cmpcode_to_str(c); | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| static void mesh_ensure_tessellation_customdata(Mesh *me) | static void mesh_ensure_tessellation_customdata(Mesh *me) | ||||
| { | { | ||||
| if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) { | if (UNLIKELY((me->totface != 0) && (me->totpoly == 0))) { | ||||
| /* Pass, otherwise this function clears 'mface' before | /* Pass, otherwise this function clears 'mface' before | ||||
| * versioning 'mface -> mpoly' code kicks in T30583. | * versioning 'mface -> mpoly' code kicks in T30583. | ||||
| * | * | ||||
| Show All 28 Lines | if (tottex_tessface != tottex_original || totcol_tessface != totcol_original) { | ||||
| totcol_original); | totcol_original); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_ensure_skin_customdata(Mesh *me) | void BKE_mesh_ensure_skin_customdata(Mesh *me) | ||||
| { | { | ||||
| BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; | BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; | ||||
| MVertSkin *vs; | MVertSkin *vs; | ||||
| if (bm) { | if (bm) { | ||||
| if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { | if (!CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN)) { | ||||
| BMVert *v; | BMVert *v; | ||||
| BMIter iter; | BMIter iter; | ||||
| BM_data_layer_add(bm, &bm->vdata, CD_MVERT_SKIN); | BM_data_layer_add(bm, &bm->vdata, CD_MVERT_SKIN); | ||||
| /* Mark an arbitrary vertex as root */ | /* Mark an arbitrary vertex as root */ | ||||
| BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | ||||
| vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); | vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); | ||||
| vs->flag |= MVERT_SKIN_ROOT; | vs->flag |= MVERT_SKIN_ROOT; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { | if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { | ||||
| vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert); | vs = (MVertSkin *)CustomData_add_layer( | ||||
| &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); | |||||
| /* Mark an arbitrary vertex as root */ | /* Mark an arbitrary vertex as root */ | ||||
| if (vs) { | if (vs) { | ||||
| vs->flag |= MVERT_SKIN_ROOT; | vs->flag |= MVERT_SKIN_ROOT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) | bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) | ||||
| { | { | ||||
| BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; | BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; | ||||
| bool changed = false; | bool changed = false; | ||||
| if (bm) { | if (bm) { | ||||
| if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { | if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { | ||||
| BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP); | BM_data_layer_add(bm, &bm->pdata, CD_FACEMAP); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { | if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { | ||||
| CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); | CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) | bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) | ||||
| { | { | ||||
| BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; | BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; | ||||
| bool changed = false; | bool changed = false; | ||||
| if (bm) { | if (bm) { | ||||
| if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { | if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { | ||||
| BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP); | BM_data_layer_free(bm, &bm->pdata, CD_FACEMAP); | ||||
| changed = true; | changed = true; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 21 Lines | static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) | ||||
| CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata); | CustomData_bmesh_update_active_layers(&me->fdata, &me->ldata); | ||||
| } | } | ||||
| void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) | void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) | ||||
| { | { | ||||
| mesh_update_linked_customdata(me, do_ensure_tess_cd); | mesh_update_linked_customdata(me, do_ensure_tess_cd); | ||||
| me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); | me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT); | ||||
| me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); | me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); | ||||
| me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); | me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE); | ||||
| me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); | me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE); | ||||
| me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); | me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL); | ||||
| me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); | me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE); | ||||
| me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); | me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY); | ||||
| me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); | me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP); | ||||
| me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); | me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL); | ||||
| me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); | me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV); | ||||
| } | } | ||||
| bool BKE_mesh_has_custom_loop_normals(Mesh *me) | bool BKE_mesh_has_custom_loop_normals(Mesh *me) | ||||
| { | { | ||||
| if (me->edit_mesh) { | if (me->edit_mesh) { | ||||
| return CustomData_has_layer(&me->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL); | return CustomData_has_layer(&me->edit_mesh->bm->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| } | } | ||||
| return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL); | return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| } | } | ||||
| /** | /** | ||||
| * Free (or release) any data used by this mesh (does not free the mesh itself). | * Free (or release) any data used by this mesh (does not free the mesh itself). | ||||
| * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used. | * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used. | ||||
| */ | */ | ||||
| void BKE_mesh_free_data_for_undo(Mesh *me) | void BKE_mesh_free_data_for_undo(Mesh *me) | ||||
| { | { | ||||
| mesh_free_data(&me->id); | mesh_free_data(&me->id); | ||||
| } | } | ||||
| /** | /** | ||||
| * \note on data that this function intentionally doesn't free: | * \note on data that this function intentionally doesn't free: | ||||
| Show All 39 Lines | |||||
| { | { | ||||
| if (free_customdata) { | if (free_customdata) { | ||||
| CustomData_free(&mesh->fdata, mesh->totface); | CustomData_free(&mesh->fdata, mesh->totface); | ||||
| } | } | ||||
| else { | else { | ||||
| CustomData_reset(&mesh->fdata); | CustomData_reset(&mesh->fdata); | ||||
| } | } | ||||
| mesh->mface = NULL; | mesh->mface = nullptr; | ||||
| mesh->mtface = NULL; | mesh->mtface = nullptr; | ||||
| mesh->mcol = NULL; | mesh->mcol = nullptr; | ||||
| mesh->totface = 0; | mesh->totface = 0; | ||||
| } | } | ||||
| Mesh *BKE_mesh_add(Main *bmain, const char *name) | Mesh *BKE_mesh_add(Main *bmain, const char *name) | ||||
| { | { | ||||
| Mesh *me = BKE_id_new(bmain, ID_ME, name); | Mesh *me = (Mesh *)BKE_id_new(bmain, ID_ME, name); | ||||
| return me; | return me; | ||||
| } | } | ||||
| /* Custom data layer functions; those assume that totXXX are set correctly. */ | /* Custom data layer functions; those assume that totXXX are set correctly. */ | ||||
| static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) | static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) | ||||
| { | { | ||||
| if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { | if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { | ||||
| CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); | CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); | ||||
| } | } | ||||
| if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { | if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { | ||||
| CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); | CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); | ||||
| } | } | ||||
| if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { | if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { | ||||
| CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); | CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); | ||||
| } | } | ||||
| if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { | if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { | ||||
| CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); | CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); | ||||
| } | } | ||||
| if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { | if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { | ||||
| CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); | CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); | ||||
| } | } | ||||
| } | } | ||||
| Mesh *BKE_mesh_new_nomain( | Mesh *BKE_mesh_new_nomain( | ||||
| int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) | int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) | ||||
| { | { | ||||
| Mesh *mesh = BKE_libblock_alloc( | Mesh *mesh = (Mesh *)BKE_libblock_alloc( | ||||
| NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); | nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); | ||||
| BKE_libblock_init_empty(&mesh->id); | BKE_libblock_init_empty(&mesh->id); | ||||
| /* Don't use #CustomData_reset because we don't want to touch custom-data. */ | /* Don't use #CustomData_reset because we don't want to touch custom-data. */ | ||||
| copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); | copy_vn_i(mesh->vdata.typemap, CD_NUMTYPES, -1); | ||||
| copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); | copy_vn_i(mesh->edata.typemap, CD_NUMTYPES, -1); | ||||
| copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); | copy_vn_i(mesh->fdata.typemap, CD_NUMTYPES, -1); | ||||
| copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); | copy_vn_i(mesh->ldata.typemap, CD_NUMTYPES, -1); | ||||
| copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); | copy_vn_i(mesh->pdata.typemap, CD_NUMTYPES, -1); | ||||
| ▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) | ||||
| BKE_mesh_copy_parameters(me_dst, me_src); | BKE_mesh_copy_parameters(me_dst, me_src); | ||||
| /* Copy vertex group names. */ | /* Copy vertex group names. */ | ||||
| BLI_assert(BLI_listbase_is_empty(&me_dst->vertex_group_names)); | BLI_assert(BLI_listbase_is_empty(&me_dst->vertex_group_names)); | ||||
| BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); | BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); | ||||
| /* Copy materials. */ | /* Copy materials. */ | ||||
| if (me_dst->mat != NULL) { | if (me_dst->mat != nullptr) { | ||||
| MEM_freeN(me_dst->mat); | MEM_freeN(me_dst->mat); | ||||
| } | } | ||||
| me_dst->mat = MEM_dupallocN(me_src->mat); | me_dst->mat = (Material **)MEM_dupallocN(me_src->mat); | ||||
| me_dst->totcol = me_src->totcol; | me_dst->totcol = me_src->totcol; | ||||
| } | } | ||||
| Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, | Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, | ||||
| int verts_len, | int verts_len, | ||||
| int edges_len, | int edges_len, | ||||
| int tessface_len, | int tessface_len, | ||||
| int loops_len, | int loops_len, | ||||
| int polys_len, | int polys_len, | ||||
| CustomData_MeshMasks mask) | CustomData_MeshMasks mask) | ||||
| { | { | ||||
| /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ | /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ | ||||
| const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); | const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); | ||||
| Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); | Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); | ||||
| me_dst->mselect = MEM_dupallocN(me_src->mselect); | me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); | ||||
| me_dst->totvert = verts_len; | me_dst->totvert = verts_len; | ||||
| me_dst->totedge = edges_len; | me_dst->totedge = edges_len; | ||||
| me_dst->totface = tessface_len; | me_dst->totface = tessface_len; | ||||
| me_dst->totloop = loops_len; | me_dst->totloop = loops_len; | ||||
| me_dst->totpoly = polys_len; | me_dst->totpoly = polys_len; | ||||
| me_dst->cd_flag = me_src->cd_flag; | me_dst->cd_flag = me_src->cd_flag; | ||||
| Show All 27 Lines | |||||
| { | { | ||||
| return BKE_mesh_new_nomain_from_template_ex( | return BKE_mesh_new_nomain_from_template_ex( | ||||
| me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING); | me_src, verts_len, edges_len, tessface_len, loops_len, polys_len, CD_MASK_EVERYTHING); | ||||
| } | } | ||||
| void BKE_mesh_eval_delete(struct Mesh *mesh_eval) | void BKE_mesh_eval_delete(struct Mesh *mesh_eval) | ||||
| { | { | ||||
| /* Evaluated mesh may point to edit mesh, but never owns it. */ | /* Evaluated mesh may point to edit mesh, but never owns it. */ | ||||
| mesh_eval->edit_mesh = NULL; | mesh_eval->edit_mesh = nullptr; | ||||
| mesh_free_data(&mesh_eval->id); | mesh_free_data(&mesh_eval->id); | ||||
| BKE_libblock_free_data(&mesh_eval->id, false); | BKE_libblock_free_data(&mesh_eval->id, false); | ||||
| MEM_freeN(mesh_eval); | MEM_freeN(mesh_eval); | ||||
| } | } | ||||
| Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) | Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) | ||||
| { | { | ||||
| int flags = LIB_ID_COPY_LOCALIZE; | int flags = LIB_ID_COPY_LOCALIZE; | ||||
| if (reference) { | if (reference) { | ||||
| flags |= LIB_ID_COPY_CD_REFERENCE; | flags |= LIB_ID_COPY_CD_REFERENCE; | ||||
| } | } | ||||
| Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags); | Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); | ||||
| return result; | return result; | ||||
| } | } | ||||
| BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me, | BMesh *BKE_mesh_to_bmesh_ex(const Mesh *me, | ||||
| const struct BMeshCreateParams *create_params, | const struct BMeshCreateParams *create_params, | ||||
| const struct BMeshFromMeshParams *convert_params) | const struct BMeshFromMeshParams *convert_params) | ||||
| { | { | ||||
| const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); | const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); | ||||
| BMesh *bm = BM_mesh_create(&allocsize, create_params); | BMesh *bm = BM_mesh_create(&allocsize, create_params); | ||||
| BM_mesh_bm_from_me(bm, me, convert_params); | BM_mesh_bm_from_me(bm, me, convert_params); | ||||
| return bm; | return bm; | ||||
| } | } | ||||
| BMesh *BKE_mesh_to_bmesh(Mesh *me, | BMesh *BKE_mesh_to_bmesh(Mesh *me, | ||||
| Object *ob, | Object *ob, | ||||
| const bool add_key_index, | const bool add_key_index, | ||||
| const struct BMeshCreateParams *params) | const struct BMeshCreateParams *params) | ||||
| { | { | ||||
| return BKE_mesh_to_bmesh_ex(me, | struct BMeshFromMeshParams bmfmp = {false, add_key_index, true, ob->shapenr}; | ||||
| params, | return BKE_mesh_to_bmesh_ex(me, params, &bmfmp); | ||||
| &(struct BMeshFromMeshParams){ | |||||
| .calc_face_normal = false, | |||||
| .add_key_index = add_key_index, | |||||
| .use_shapekey = true, | |||||
| .active_shapekey = ob->shapenr, | |||||
| }); | |||||
| } | } | ||||
| Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, | Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, | ||||
| const struct BMeshToMeshParams *params, | const struct BMeshToMeshParams *params, | ||||
| const Mesh *me_settings) | const Mesh *me_settings) | ||||
| { | { | ||||
| BLI_assert(params->calc_object_remap == false); | BLI_assert(params->calc_object_remap == false); | ||||
| Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); | Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); | ||||
| BM_mesh_bm_to_me(NULL, bm, mesh, params); | BM_mesh_bm_to_me(nullptr, bm, mesh, params); | ||||
| BKE_mesh_copy_parameters_for_eval(mesh, me_settings); | BKE_mesh_copy_parameters_for_eval(mesh, me_settings); | ||||
| return mesh; | return mesh; | ||||
| } | } | ||||
| Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, | Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, | ||||
| const CustomData_MeshMasks *cd_mask_extra, | const CustomData_MeshMasks *cd_mask_extra, | ||||
| const Mesh *me_settings) | const Mesh *me_settings) | ||||
| { | { | ||||
| Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); | Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); | ||||
| BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); | BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); | ||||
| BKE_mesh_copy_parameters_for_eval(mesh, me_settings); | BKE_mesh_copy_parameters_for_eval(mesh, me_settings); | ||||
| return mesh; | return mesh; | ||||
| } | } | ||||
| BoundBox *BKE_mesh_boundbox_get(Object *ob) | BoundBox *BKE_mesh_boundbox_get(Object *ob) | ||||
| { | { | ||||
| /* This is Object-level data access, | /* This is Object-level data access, | ||||
| * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ | * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ | ||||
| if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { | if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { | ||||
| Mesh *me = ob->data; | Mesh *me = (Mesh *)ob->data; | ||||
| float min[3], max[3]; | float min[3], max[3]; | ||||
| INIT_MINMAX(min, max); | INIT_MINMAX(min, max); | ||||
| if (!BKE_mesh_wrapper_minmax(me, min, max)) { | if (!BKE_mesh_wrapper_minmax(me, min, max)) { | ||||
| min[0] = min[1] = min[2] = -1.0f; | min[0] = min[1] = min[2] = -1.0f; | ||||
| max[0] = max[1] = max[2] = 1.0f; | max[0] = max[1] = max[2] = 1.0f; | ||||
| } | } | ||||
| if (ob->runtime.bb == NULL) { | if (ob->runtime.bb == nullptr) { | ||||
| ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); | ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__); | ||||
| } | } | ||||
| BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); | BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); | ||||
| ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; | ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; | ||||
| } | } | ||||
| return ob->runtime.bb; | return ob->runtime.bb; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | if (r_size) { | ||||
| copy_v3_v3(r_size, me->size); | copy_v3_v3(r_size, me->size); | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size) | void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, float **r_size) | ||||
| { | { | ||||
| BKE_mesh_texspace_ensure(me); | BKE_mesh_texspace_ensure(me); | ||||
| if (r_texflag != NULL) { | if (r_texflag != nullptr) { | ||||
| *r_texflag = &me->texflag; | *r_texflag = &me->texflag; | ||||
| } | } | ||||
| if (r_loc != NULL) { | if (r_loc != nullptr) { | ||||
| *r_loc = me->loc; | *r_loc = me->loc; | ||||
| } | } | ||||
| if (r_size != NULL) { | if (r_size != nullptr) { | ||||
| *r_size = me->size; | *r_size = me->size; | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) | void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) | ||||
| { | { | ||||
| float *texloc, *texsize; | float *texloc, *texsize; | ||||
| short *texflag; | short *texflag; | ||||
| if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) { | if (BKE_object_obdata_texspace_get(ob, &texflag, &texloc, &texsize)) { | ||||
| me->texflag = *texflag; | me->texflag = *texflag; | ||||
| copy_v3_v3(me->loc, texloc); | copy_v3_v3(me->loc, texloc); | ||||
| copy_v3_v3(me->size, texsize); | copy_v3_v3(me->size, texsize); | ||||
| } | } | ||||
| } | } | ||||
| float (*BKE_mesh_orco_verts_get(Object *ob))[3] | float (*BKE_mesh_orco_verts_get(Object *ob))[3] | ||||
| { | { | ||||
| Mesh *me = ob->data; | Mesh *me = (Mesh *)ob->data; | ||||
| Mesh *tme = me->texcomesh ? me->texcomesh : me; | Mesh *tme = me->texcomesh ? me->texcomesh : me; | ||||
| /* Get appropriate vertex coordinates */ | /* Get appropriate vertex coordinates */ | ||||
| float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); | float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); | ||||
| MVert *mvert = tme->mvert; | MVert *mvert = tme->mvert; | ||||
| int totvert = min_ii(tme->totvert, me->totvert); | int totvert = min_ii(tme->totvert, me->totvert); | ||||
| for (int a = 0; a < totvert; a++, mvert++) { | for (int a = 0; a < totvert; a++, mvert++) { | ||||
| copy_v3_v3(vcos[a], mvert->co); | copy_v3_v3(vcos[a], mvert->co); | ||||
| } | } | ||||
| return vcos; | return vcos; | ||||
| ▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | else if (nr == 4) { | ||||
| } | } | ||||
| } | } | ||||
| return nr; | return nr; | ||||
| } | } | ||||
| Mesh *BKE_mesh_from_object(Object *ob) | Mesh *BKE_mesh_from_object(Object *ob) | ||||
| { | { | ||||
| if (ob == NULL) { | if (ob == nullptr) { | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| return ob->data; | return (Mesh *)ob->data; | ||||
| } | } | ||||
| return NULL; | return nullptr; | ||||
| } | } | ||||
| void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) | void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) | ||||
| { | { | ||||
| Mesh *old = NULL; | Mesh *old = nullptr; | ||||
| if (ob == NULL) { | if (ob == nullptr) { | ||||
| return; | return; | ||||
| } | } | ||||
| multires_force_sculpt_rebuild(ob); | multires_force_sculpt_rebuild(ob); | ||||
| if (ob->type == OB_MESH) { | if (ob->type == OB_MESH) { | ||||
| old = ob->data; | old = (Mesh *)ob->data; | ||||
| if (old) { | if (old) { | ||||
| id_us_min(&old->id); | id_us_min(&old->id); | ||||
| } | } | ||||
| ob->data = me; | ob->data = me; | ||||
| id_us_plus((ID *)me); | id_us_plus((ID *)me); | ||||
| } | } | ||||
| BKE_object_materials_test(bmain, ob, (ID *)me); | BKE_object_materials_test(bmain, ob, (ID *)me); | ||||
| ▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) | ||||
| } | } | ||||
| return (me->totvert != 0); | return (me->totvert != 0); | ||||
| } | } | ||||
| void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) | void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) | ||||
| { | { | ||||
| int i; | int i; | ||||
| MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); | MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); | ||||
| float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop); | float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( | ||||
| &me->ldata, CD_NORMAL, me->totloop); | |||||
| /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ | /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ | ||||
| BKE_mesh_update_customdata_pointers(me, false); | BKE_mesh_update_customdata_pointers(me, false); | ||||
| for (i = 0; i < me->totvert; i++, mvert++) { | for (i = 0; i < me->totvert; i++, mvert++) { | ||||
| mul_m4_v3(mat, mvert->co); | mul_m4_v3(mat, mvert->co); | ||||
| } | } | ||||
| if (do_keys && me->key) { | if (do_keys && me->key) { | ||||
| KeyBlock *kb; | LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { | ||||
| for (kb = me->key->block.first; kb; kb = kb->next) { | float *fp = (float *)kb->data; | ||||
| float *fp = kb->data; | |||||
| for (i = kb->totelem; i--; fp += 3) { | for (i = kb->totelem; i--; fp += 3) { | ||||
| mul_m4_v3(mat, fp); | mul_m4_v3(mat, fp); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* don't update normals, caller can do this explicitly. | /* don't update normals, caller can do this explicitly. | ||||
| * We do update loop normals though, those may not be auto-generated | * We do update loop normals though, those may not be auto-generated | ||||
| Show All 16 Lines | void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) | ||||
| BKE_mesh_update_customdata_pointers(me, false); | BKE_mesh_update_customdata_pointers(me, false); | ||||
| int i = me->totvert; | int i = me->totvert; | ||||
| for (MVert *mvert = me->mvert; i--; mvert++) { | for (MVert *mvert = me->mvert; i--; mvert++) { | ||||
| add_v3_v3(mvert->co, offset); | add_v3_v3(mvert->co, offset); | ||||
| } | } | ||||
| if (do_keys && me->key) { | if (do_keys && me->key) { | ||||
| KeyBlock *kb; | LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { | ||||
| for (kb = me->key->block.first; kb; kb = kb->next) { | float *fp = (float *)kb->data; | ||||
| float *fp = kb->data; | |||||
| for (i = kb->totelem; i--; fp += 3) { | for (i = kb->totelem; i--; fp += 3) { | ||||
| add_v3_v3(fp, offset); | add_v3_v3(fp, offset); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void BKE_mesh_tessface_ensure(Mesh *mesh) | void BKE_mesh_tessface_ensure(Mesh *mesh) | ||||
| ▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | void BKE_mesh_mselect_validate(Mesh *me) | ||||
| MSelect *mselect_src, *mselect_dst; | MSelect *mselect_src, *mselect_dst; | ||||
| int i_src, i_dst; | int i_src, i_dst; | ||||
| if (me->totselect == 0) { | if (me->totselect == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| mselect_src = me->mselect; | mselect_src = me->mselect; | ||||
| mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history"); | mselect_dst = (MSelect *)MEM_malloc_arrayN( | ||||
| (me->totselect), sizeof(MSelect), "Mesh selection history"); | |||||
| for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { | for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { | ||||
| int index = mselect_src[i_src].index; | int index = mselect_src[i_src].index; | ||||
| switch (mselect_src[i_src].type) { | switch (mselect_src[i_src].type) { | ||||
| case ME_VSEL: { | case ME_VSEL: { | ||||
| if (me->mvert[index].flag & SELECT) { | if (me->mvert[index].flag & SELECT) { | ||||
| mselect_dst[i_dst] = mselect_src[i_src]; | mselect_dst[i_dst] = mselect_src[i_src]; | ||||
| i_dst++; | i_dst++; | ||||
| Show All 20 Lines | switch (mselect_src[i_src].type) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(mselect_src); | MEM_freeN(mselect_src); | ||||
| if (i_dst == 0) { | if (i_dst == 0) { | ||||
| MEM_freeN(mselect_dst); | MEM_freeN(mselect_dst); | ||||
| mselect_dst = NULL; | mselect_dst = nullptr; | ||||
| } | } | ||||
| else if (i_dst != me->totselect) { | else if (i_dst != me->totselect) { | ||||
| mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); | mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); | ||||
| } | } | ||||
| me->totselect = i_dst; | me->totselect = i_dst; | ||||
| me->mselect = mselect_dst; | me->mselect = mselect_dst; | ||||
| } | } | ||||
| /** | /** | ||||
| * Return the index within me->mselect, or -1 | * Return the index within me->mselect, or -1 | ||||
| Show All 27 Lines | |||||
| } | } | ||||
| void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) | void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) | ||||
| { | { | ||||
| const int msel_index = BKE_mesh_mselect_find(me, index, type); | const int msel_index = BKE_mesh_mselect_find(me, index, type); | ||||
| if (msel_index == -1) { | if (msel_index == -1) { | ||||
| /* add to the end */ | /* add to the end */ | ||||
| me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); | me->mselect = (MSelect *)MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); | ||||
| me->mselect[me->totselect].index = index; | me->mselect[me->totselect].index = index; | ||||
| me->mselect[me->totselect].type = type; | me->mselect[me->totselect].type = type; | ||||
| me->totselect++; | me->totselect++; | ||||
| } | } | ||||
| else if (msel_index != me->totselect - 1) { | else if (msel_index != me->totselect - 1) { | ||||
| /* move to the end */ | /* move to the end */ | ||||
| SWAP(MSelect, me->mselect[msel_index], me->mselect[me->totselect - 1]); | SWAP(MSelect, me->mselect[msel_index], me->mselect[me->totselect - 1]); | ||||
| } | } | ||||
| Show All 19 Lines | void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) | ||||
| const MVert *mv = mesh->mvert; | const MVert *mv = mesh->mvert; | ||||
| for (int i = 0; i < mesh->totvert; i++, mv++) { | for (int i = 0; i < mesh->totvert; i++, mv++) { | ||||
| copy_v3_v3(vert_coords[i], mv->co); | copy_v3_v3(vert_coords[i], mv->co); | ||||
| } | } | ||||
| } | } | ||||
| float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] | float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] | ||||
| { | { | ||||
| float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); | float(*vert_coords)[3] = (float(*)[3])MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); | ||||
| BKE_mesh_vert_coords_get(mesh, vert_coords); | BKE_mesh_vert_coords_get(mesh, vert_coords); | ||||
| if (r_vert_len) { | if (r_vert_len) { | ||||
| *r_vert_len = mesh->totvert; | *r_vert_len = mesh->totvert; | ||||
| } | } | ||||
| return vert_coords; | return vert_coords; | ||||
| } | } | ||||
| void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) | void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) | ||||
| { | { | ||||
| /* This will just return the pointer if it wasn't a referenced layer. */ | /* This will just return the pointer if it wasn't a referenced layer. */ | ||||
| MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); | MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( | ||||
| &mesh->vdata, CD_MVERT, mesh->totvert); | |||||
| mesh->mvert = mv; | mesh->mvert = mv; | ||||
| for (int i = 0; i < mesh->totvert; i++, mv++) { | for (int i = 0; i < mesh->totvert; i++, mv++) { | ||||
| copy_v3_v3(mv->co, vert_coords[i]); | copy_v3_v3(mv->co, vert_coords[i]); | ||||
| } | } | ||||
| BKE_mesh_normals_tag_dirty(mesh); | BKE_mesh_normals_tag_dirty(mesh); | ||||
| } | } | ||||
| void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, | void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, | ||||
| const float (*vert_coords)[3], | const float (*vert_coords)[3], | ||||
| const float mat[4][4]) | const float mat[4][4]) | ||||
| { | { | ||||
| /* This will just return the pointer if it wasn't a referenced layer. */ | /* This will just return the pointer if it wasn't a referenced layer. */ | ||||
| MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); | MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( | ||||
| &mesh->vdata, CD_MVERT, mesh->totvert); | |||||
| mesh->mvert = mv; | mesh->mvert = mv; | ||||
| for (int i = 0; i < mesh->totvert; i++, mv++) { | for (int i = 0; i < mesh->totvert; i++, mv++) { | ||||
| mul_v3_m4v3(mv->co, mat, vert_coords[i]); | mul_v3_m4v3(mv->co, mat, vert_coords[i]); | ||||
| } | } | ||||
| BKE_mesh_normals_tag_dirty(mesh); | BKE_mesh_normals_tag_dirty(mesh); | ||||
| } | } | ||||
| void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3]) | void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3]) | ||||
| { | { | ||||
| /* This will just return the pointer if it wasn't a referenced layer. */ | /* This will just return the pointer if it wasn't a referenced layer. */ | ||||
| MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); | MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( | ||||
| &mesh->vdata, CD_MVERT, mesh->totvert); | |||||
| mesh->mvert = mv; | mesh->mvert = mv; | ||||
| for (int i = 0; i < mesh->totvert; i++, mv++) { | for (int i = 0; i < mesh->totvert; i++, mv++) { | ||||
| copy_v3_v3_short(mv->no, vert_normals[i]); | copy_v3_v3_short(mv->no, vert_normals[i]); | ||||
| } | } | ||||
| mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; | mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; | ||||
| } | } | ||||
| /** | /** | ||||
| * Compute 'split' (aka loop, or per face corner's) normals. | * Compute 'split' (aka loop, or per face corner's) normals. | ||||
| * | * | ||||
| * \param r_lnors_spacearr: Allows to get computed loop normal space array. | * \param r_lnors_spacearr: Allows to get computed loop normal space array. | ||||
| * That data, among other things, contains 'smooth fan' info, useful e.g. | * That data, among other things, contains 'smooth fan' info, useful e.g. | ||||
| * to split geometry along sharp edges... | * to split geometry along sharp edges... | ||||
| */ | */ | ||||
| void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) | void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr) | ||||
| { | { | ||||
| float(*r_loopnors)[3]; | float(*r_loopnors)[3]; | ||||
| float(*polynors)[3]; | float(*polynors)[3]; | ||||
| short(*clnors)[2] = NULL; | short(*clnors)[2] = nullptr; | ||||
| bool free_polynors = false; | bool free_polynors = false; | ||||
| /* Note that we enforce computing clnors when the clnor space array is requested by caller here. | /* Note that we enforce computing clnors when the clnor space array is requested by caller here. | ||||
| * However, we obviously only use the autosmooth angle threshold | * However, we obviously only use the autosmooth angle threshold | ||||
| * only in case autosmooth is enabled. */ | * only in case autosmooth is enabled. */ | ||||
| const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); | const bool use_split_normals = (r_lnors_spacearr != nullptr) || | ||||
| ((mesh->flag & ME_AUTOSMOOTH) != 0); | |||||
| const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; | const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; | ||||
| if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { | if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { | ||||
| r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); | r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL); | ||||
| memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); | memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); | ||||
| } | } | ||||
| else { | else { | ||||
| r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); | r_loopnors = (float(*)[3])CustomData_add_layer( | ||||
| &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop); | |||||
| CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); | CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); | ||||
| } | } | ||||
| /* may be NULL */ | /* may be nullptr */ | ||||
| clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); | clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); | ||||
| if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { | if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { | ||||
| /* This assume that layer is always up to date, not sure this is the case | /* This assume that layer is always up to date, not sure this is the case | ||||
| * (esp. in Edit mode?)... */ | * (esp. in Edit mode?)... */ | ||||
| polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); | polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); | ||||
| free_polynors = false; | free_polynors = false; | ||||
| } | } | ||||
| else { | else { | ||||
| polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); | polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); | ||||
| BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, | BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, | ||||
| mesh->totvert, | mesh->totvert, | ||||
| mesh->mloop, | mesh->mloop, | ||||
| mesh->totloop, | mesh->totloop, | ||||
| mesh->mpoly, | mesh->mpoly, | ||||
| mesh->totpoly, | mesh->totpoly, | ||||
| polynors, | polynors, | ||||
| NULL); | nullptr); | ||||
| free_polynors = true; | free_polynors = true; | ||||
| } | } | ||||
| BKE_mesh_normals_loop_split(mesh->mvert, | BKE_mesh_normals_loop_split(mesh->mvert, | ||||
| mesh->totvert, | mesh->totvert, | ||||
| mesh->medge, | mesh->medge, | ||||
| mesh->totedge, | mesh->totedge, | ||||
| mesh->mloop, | mesh->mloop, | ||||
| r_loopnors, | r_loopnors, | ||||
| mesh->totloop, | mesh->totloop, | ||||
| mesh->mpoly, | mesh->mpoly, | ||||
| (const float(*)[3])polynors, | (const float(*)[3])polynors, | ||||
| mesh->totpoly, | mesh->totpoly, | ||||
| use_split_normals, | use_split_normals, | ||||
| split_angle, | split_angle, | ||||
| r_lnors_spacearr, | r_lnors_spacearr, | ||||
| clnors, | clnors, | ||||
| NULL); | nullptr); | ||||
| if (free_polynors) { | if (free_polynors) { | ||||
| MEM_freeN(polynors); | MEM_freeN(polynors); | ||||
| } | } | ||||
| mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; | mesh->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL; | ||||
| mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; | mesh->runtime.cd_dirty_poly &= ~CD_MASK_NORMAL; | ||||
| mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL; | mesh->runtime.cd_dirty_loop &= ~CD_MASK_NORMAL; | ||||
| } | } | ||||
| void BKE_mesh_calc_normals_split(Mesh *mesh) | void BKE_mesh_calc_normals_split(Mesh *mesh) | ||||
| { | { | ||||
| BKE_mesh_calc_normals_split_ex(mesh, NULL); | BKE_mesh_calc_normals_split_ex(mesh, nullptr); | ||||
| } | } | ||||
| /* Split faces helper functions. */ | /* Split faces helper functions. */ | ||||
| typedef struct SplitFaceNewVert { | typedef struct SplitFaceNewVert { | ||||
| struct SplitFaceNewVert *next; | struct SplitFaceNewVert *next; | ||||
| int new_index; | int new_index; | ||||
| int orig_index; | int orig_index; | ||||
| Show All 13 Lines | |||||
| static int split_faces_prepare_new_verts(const Mesh *mesh, | static int split_faces_prepare_new_verts(const Mesh *mesh, | ||||
| MLoopNorSpaceArray *lnors_spacearr, | MLoopNorSpaceArray *lnors_spacearr, | ||||
| SplitFaceNewVert **new_verts, | SplitFaceNewVert **new_verts, | ||||
| MemArena *memarena) | MemArena *memarena) | ||||
| { | { | ||||
| /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, | /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, | ||||
| * even when only dealing with smooth/flat faces one can find cases that no simple algorithm | * even when only dealing with smooth/flat faces one can find cases that no simple algorithm | ||||
| * can handle properly. */ | * can handle properly. */ | ||||
| BLI_assert(lnors_spacearr != NULL); | BLI_assert(lnors_spacearr != nullptr); | ||||
| const int loops_len = mesh->totloop; | const int loops_len = mesh->totloop; | ||||
| int verts_len = mesh->totvert; | int verts_len = mesh->totvert; | ||||
| MVert *mvert = mesh->mvert; | MVert *mvert = mesh->mvert; | ||||
| MLoop *mloop = mesh->mloop; | MLoop *mloop = mesh->mloop; | ||||
| BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__); | BLI_bitmap *verts_used = BLI_BITMAP_NEW(verts_len, __func__); | ||||
| BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__); | BLI_bitmap *done_loops = BLI_BITMAP_NEW(loops_len, __func__); | ||||
| Show All 36 Lines | if (!BLI_BITMAP_TEST(done_loops, loop_idx)) { | ||||
| /* This is important! *DO NOT* set vnor to final computed lnor, | /* This is important! *DO NOT* set vnor to final computed lnor, | ||||
| * vnor should always be defined to 'automatic normal' value computed from its polys, | * vnor should always be defined to 'automatic normal' value computed from its polys, | ||||
| * not some custom normal. | * not some custom normal. | ||||
| * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */ | * Fortunately, that's the loop normal space's 'lnor' reference vector. ;) */ | ||||
| normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); | normal_float_to_short_v3(mvert[vert_idx].no, (*lnor_space)->vec_lnor); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Add new vert to list. */ | /* Add new vert to list. */ | ||||
| SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); | SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena, | ||||
| sizeof(*new_vert)); | |||||
| new_vert->orig_index = vert_idx; | new_vert->orig_index = vert_idx; | ||||
| new_vert->new_index = new_vert_idx; | new_vert->new_index = new_vert_idx; | ||||
| new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ | new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ | ||||
| new_vert->next = *new_verts; | new_vert->next = *new_verts; | ||||
| *new_verts = new_vert; | *new_verts = new_vert; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| Show All 30 Lines | for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) { | ||||
| /* That edge has not been encountered yet, define it. */ | /* That edge has not been encountered yet, define it. */ | ||||
| if (BLI_BITMAP_TEST(edges_used, edge_idx)) { | if (BLI_BITMAP_TEST(edges_used, edge_idx)) { | ||||
| /* Original edge has already been used, we need to define a new one. */ | /* Original edge has already been used, we need to define a new one. */ | ||||
| const int new_edge_idx = num_edges++; | const int new_edge_idx = num_edges++; | ||||
| *eval = POINTER_FROM_INT(new_edge_idx); | *eval = POINTER_FROM_INT(new_edge_idx); | ||||
| ml_prev->e = new_edge_idx; | ml_prev->e = new_edge_idx; | ||||
| SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge)); | SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena, | ||||
| sizeof(*new_edge)); | |||||
| new_edge->orig_index = edge_idx; | new_edge->orig_index = edge_idx; | ||||
| new_edge->new_index = new_edge_idx; | new_edge->new_index = new_edge_idx; | ||||
| new_edge->v1 = ml_prev->v; | new_edge->v1 = ml_prev->v; | ||||
| new_edge->v2 = ml->v; | new_edge->v2 = ml->v; | ||||
| new_edge->next = *new_edges; | new_edge->next = *new_edges; | ||||
| *new_edges = new_edge; | *new_edges = new_edge; | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 9 Lines | for (int loop_idx = 0; loop_idx < mp->totloop; loop_idx++, ml++) { | ||||
| ml_prev->e = POINTER_AS_INT(*eval); | ml_prev->e = POINTER_AS_INT(*eval); | ||||
| } | } | ||||
| ml_prev = ml; | ml_prev = ml; | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(edges_used); | MEM_freeN(edges_used); | ||||
| BLI_edgehash_free(edges_hash, NULL); | BLI_edgehash_free(edges_hash, nullptr); | ||||
| return num_edges - mesh->totedge; | return num_edges - mesh->totedge; | ||||
| } | } | ||||
| /* Perform actual split of vertices. */ | /* Perform actual split of vertices. */ | ||||
| static void split_faces_split_new_verts(Mesh *mesh, | static void split_faces_split_new_verts(Mesh *mesh, | ||||
| SplitFaceNewVert *new_verts, | SplitFaceNewVert *new_verts, | ||||
| const int num_new_verts) | const int num_new_verts) | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| const int num_polys = mesh->totpoly; | const int num_polys = mesh->totpoly; | ||||
| if (num_polys == 0) { | if (num_polys == 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| BKE_mesh_tessface_clear(mesh); | BKE_mesh_tessface_clear(mesh); | ||||
| MLoopNorSpaceArray lnors_spacearr = {NULL}; | MLoopNorSpaceArray lnors_spacearr = {nullptr}; | ||||
| /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ | /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ | ||||
| BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); | BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); | ||||
| /* Stealing memarena from loop normals space array. */ | /* Stealing memarena from loop normals space array. */ | ||||
| MemArena *memarena = lnors_spacearr.mem; | MemArena *memarena = lnors_spacearr.mem; | ||||
| SplitFaceNewVert *new_verts = NULL; | SplitFaceNewVert *new_verts = nullptr; | ||||
| SplitFaceNewEdge *new_edges = NULL; | SplitFaceNewEdge *new_edges = nullptr; | ||||
| /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will | /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will | ||||
| * directly assign new indices to existing edges and loops. */ | * directly assign new indices to existing edges and loops. */ | ||||
| CustomData_duplicate_referenced_layers(&mesh->vdata, mesh->totvert); | CustomData_duplicate_referenced_layers(&mesh->vdata, mesh->totvert); | ||||
| CustomData_duplicate_referenced_layers(&mesh->edata, mesh->totedge); | CustomData_duplicate_referenced_layers(&mesh->edata, mesh->totedge); | ||||
| CustomData_duplicate_referenced_layers(&mesh->ldata, mesh->totloop); | CustomData_duplicate_referenced_layers(&mesh->ldata, mesh->totloop); | ||||
| /* Update pointers in case we duplicated referenced layers. */ | /* Update pointers in case we duplicated referenced layers. */ | ||||
| BKE_mesh_update_customdata_pointers(mesh, false); | BKE_mesh_update_customdata_pointers(mesh, false); | ||||
| ▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | |||||
| void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) | void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) | ||||
| { | { | ||||
| DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh); | DEG_debug_print_eval(depsgraph, __func__, mesh->id.name, mesh); | ||||
| BKE_mesh_texspace_calc(mesh); | BKE_mesh_texspace_calc(mesh); | ||||
| /* We are here because something did change in the mesh. This means we can not trust the existing | /* We are here because something did change in the mesh. This means we can not trust the existing | ||||
| * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the | * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the | ||||
| * evaluated mesh and let objects to re-create it with updated settings. */ | * evaluated mesh and let objects to re-create it with updated settings. */ | ||||
| if (mesh->runtime.mesh_eval != NULL) { | if (mesh->runtime.mesh_eval != nullptr) { | ||||
| mesh->runtime.mesh_eval->edit_mesh = NULL; | mesh->runtime.mesh_eval->edit_mesh = nullptr; | ||||
| BKE_id_free(NULL, mesh->runtime.mesh_eval); | BKE_id_free(nullptr, mesh->runtime.mesh_eval); | ||||
| mesh->runtime.mesh_eval = NULL; | mesh->runtime.mesh_eval = nullptr; | ||||
| } | } | ||||
| if (DEG_is_active(depsgraph)) { | if (DEG_is_active(depsgraph)) { | ||||
| Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); | Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); | ||||
| if (mesh->texflag & ME_AUTOSPACE_EVALUATED) { | if (mesh->texflag & ME_AUTOSPACE_EVALUATED) { | ||||
| mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED; | mesh_orig->texflag |= ME_AUTOSPACE_EVALUATED; | ||||
| copy_v3_v3(mesh_orig->loc, mesh->loc); | copy_v3_v3(mesh_orig->loc, mesh->loc); | ||||
| copy_v3_v3(mesh_orig->size, mesh->size); | copy_v3_v3(mesh_orig->size, mesh->size); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
In the future, please keep named fields info, even though cpp does not support it in its syntax, as done in all other cpp ID files, using comments: /* id_code */ ID_ME,, etc.
This info is critical, especially for nullptr members, and to also quickly see where to add new entries, or if some are missing, etc.