Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_convert.c
| Show All 32 Lines | |||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_edgehash.h" | #include "BLI_edgehash.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_DerivedMesh.h" | #include "BKE_DerivedMesh.h" | ||||
| #include "BKE_key.h" | #include "BKE_key.h" | ||||
| #include "BKE_library_query.h" | |||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| #include "BKE_mesh_runtime.h" | #include "BKE_mesh_runtime.h" | ||||
| #include "BKE_modifier.h" | #include "BKE_modifier.h" | ||||
| #include "BKE_displist.h" | #include "BKE_displist.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_material.h" | #include "BKE_material.h" | ||||
| #include "BKE_mball.h" | #include "BKE_mball.h" | ||||
| /* these 2 are only used by conversion functions */ | /* these 2 are only used by conversion functions */ | ||||
| ▲ Show 20 Lines • Show All 558 Lines • ▼ Show 20 Lines | if (BKE_mesh_nurbs_displist_to_mdata(ob, | ||||
| (use_orco_uv) ? &alluv : NULL, | (use_orco_uv) ? &alluv : NULL, | ||||
| &totloop, | &totloop, | ||||
| &totpoly) != 0) { | &totpoly) != 0) { | ||||
| /* Error initializing */ | /* Error initializing */ | ||||
| return; | return; | ||||
| } | } | ||||
| /* make mesh */ | /* make mesh */ | ||||
| if (bmain != NULL) { | |||||
| me = BKE_mesh_add(bmain, obdata_name); | me = BKE_mesh_add(bmain, obdata_name); | ||||
| } | |||||
| else { | |||||
| me = BKE_id_new_nomain(ID_ME, obdata_name); | |||||
| } | |||||
| me->totvert = totvert; | me->totvert = totvert; | ||||
| me->totedge = totedge; | me->totedge = totedge; | ||||
| me->totloop = totloop; | me->totloop = totloop; | ||||
| me->totpoly = totpoly; | me->totpoly = totpoly; | ||||
| me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert); | me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert); | ||||
| me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge); | me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge); | ||||
| me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop); | me->mloop = CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop); | ||||
| me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); | me->mpoly = CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly); | ||||
| if (alluv) { | if (alluv) { | ||||
| const char *uvname = "Orco"; | const char *uvname = "Orco"; | ||||
| me->mloopuv = CustomData_add_layer_named( | me->mloopuv = CustomData_add_layer_named( | ||||
| &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); | &me->ldata, CD_MLOOPUV, CD_ASSIGN, alluv, me->totloop, uvname); | ||||
| } | } | ||||
| BKE_mesh_calc_normals(me); | BKE_mesh_calc_normals(me); | ||||
| } | } | ||||
| else { | else { | ||||
| if (bmain != NULL) { | |||||
| me = BKE_mesh_add(bmain, obdata_name); | me = BKE_mesh_add(bmain, obdata_name); | ||||
| } | |||||
| else { | |||||
| me = BKE_id_new_nomain(ID_ME, obdata_name); | |||||
| } | |||||
| ob->runtime.mesh_eval = NULL; | ob->runtime.mesh_eval = NULL; | ||||
| BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); | BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); | ||||
| } | } | ||||
| me->totcol = cu->totcol; | me->totcol = cu->totcol; | ||||
| me->mat = cu->mat; | me->mat = cu->mat; | ||||
| /* Copy evaluated texture space from curve to mesh. | /* Copy evaluated texture space from curve to mesh. | ||||
| Show All 13 Lines | void BKE_mesh_from_nurbs_displist(Main *bmain, | ||||
| cu->totcol = 0; | cu->totcol = 0; | ||||
| /* Do not decrement ob->data usercount here, | /* Do not decrement ob->data usercount here, | ||||
| * it's done at end of func with BKE_id_free_us() call. */ | * it's done at end of func with BKE_id_free_us() call. */ | ||||
| ob->data = me; | ob->data = me; | ||||
| ob->type = OB_MESH; | ob->type = OB_MESH; | ||||
| /* other users */ | /* other users */ | ||||
| if (bmain != NULL) { | |||||
| ob1 = bmain->objects.first; | ob1 = bmain->objects.first; | ||||
| while (ob1) { | while (ob1) { | ||||
| if (ob1->data == cu) { | if (ob1->data == cu) { | ||||
| ob1->type = OB_MESH; | ob1->type = OB_MESH; | ||||
| id_us_min((ID *)ob1->data); | id_us_min((ID *)ob1->data); | ||||
| ob1->data = ob->data; | ob1->data = ob->data; | ||||
| id_us_plus((ID *)ob1->data); | id_us_plus((ID *)ob1->data); | ||||
| } | } | ||||
| ob1 = ob1->id.next; | ob1 = ob1->id.next; | ||||
| } | } | ||||
| } | |||||
| if (temporary) { | if (temporary) { | ||||
| /* For temporary objects in BKE_mesh_new_from_object don't remap | /* For temporary objects in BKE_mesh_new_from_object don't remap | ||||
| * the entire scene with associated depsgraph updates, which are | * the entire scene with associated depsgraph updates, which are | ||||
| * problematic for renderers exporting data. */ | * problematic for renderers exporting data. */ | ||||
| BKE_id_free(NULL, cu); | BKE_id_free(NULL, cu); | ||||
| } | } | ||||
| else { | else { | ||||
| ▲ Show 20 Lines • Show All 306 Lines • ▼ Show 20 Lines | BKE_displist_make_curveTypes_forRender(NULL, | ||||
| &remapped_object.runtime.mesh_eval, | &remapped_object.runtime.mesh_eval, | ||||
| false, | false, | ||||
| NULL); | NULL); | ||||
| BKE_object_free_curve_cache(&bevel_object); | BKE_object_free_curve_cache(&bevel_object); | ||||
| BKE_object_free_curve_cache(&taper_object); | BKE_object_free_curve_cache(&taper_object); | ||||
| } | } | ||||
| static Mesh *mesh_new_from_curve_type_object(Main *bmain, Object *object) | static Mesh *mesh_new_from_curve_type_object(Object *object) | ||||
| { | { | ||||
| Curve *curve = object->data; | Curve *curve = object->data; | ||||
| const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; | const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; | ||||
| Object *temp_object = object_for_curve_to_mesh_create(object); | Object *temp_object = object_for_curve_to_mesh_create(object); | ||||
| Curve *temp_curve = (Curve *)temp_object->data; | Curve *temp_curve = (Curve *)temp_object->data; | ||||
| /* When input object is an original one, we don't have evaluated curve cache yet, so need to | /* When input object is an original one, we don't have evaluated curve cache yet, so need to | ||||
| * create it in the temporary object. */ | * create it in the temporary object. */ | ||||
| if (!DEG_is_evaluated_object(object)) { | if (!DEG_is_evaluated_object(object)) { | ||||
| curve_to_mesh_eval_ensure(temp_object); | curve_to_mesh_eval_ensure(temp_object); | ||||
| } | } | ||||
| /* Reset pointers before conversion. */ | /* Reset pointers before conversion. */ | ||||
| temp_curve->editfont = NULL; | temp_curve->editfont = NULL; | ||||
| temp_curve->editnurb = NULL; | temp_curve->editnurb = NULL; | ||||
| /* Convert to mesh. */ | /* Convert to mesh. */ | ||||
| BKE_mesh_from_nurbs_displist(bmain, | BKE_mesh_from_nurbs_displist(NULL, | ||||
| temp_object, | temp_object, | ||||
| &temp_object->runtime.curve_cache->disp, | &temp_object->runtime.curve_cache->disp, | ||||
| uv_from_orco, | uv_from_orco, | ||||
| curve->id.name + 2, | curve->id.name + 2, | ||||
| true); | true); | ||||
| /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did | /* BKE_mesh_from_nurbs changes the type to a mesh, check it worked. If it didn't the curve did | ||||
| * not have any segments or otherwise would have generated an empty mesh. */ | * not have any segments or otherwise would have generated an empty mesh. */ | ||||
| if (temp_object->type != OB_MESH) { | if (temp_object->type != OB_MESH) { | ||||
| BKE_id_free(NULL, temp_object); | BKE_id_free(NULL, temp_object); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| Mesh *mesh_result = temp_object->data; | Mesh *mesh_result = temp_object->data; | ||||
| BKE_id_free(NULL, temp_object); | BKE_id_free(NULL, temp_object); | ||||
| /* NOTE: Materials are copied in BKE_mesh_from_nurbs_displist(). */ | /* NOTE: Materials are copied in BKE_mesh_from_nurbs_displist(). */ | ||||
| return mesh_result; | return mesh_result; | ||||
| } | } | ||||
| static Mesh *mesh_new_from_mball_object(Main *bmain, Object *object) | static Mesh *mesh_new_from_mball_object(Object *object) | ||||
| { | { | ||||
| MetaBall *mball = (MetaBall *)object->data; | MetaBall *mball = (MetaBall *)object->data; | ||||
| /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta | /* NOTE: We can only create mesh for a polygonized meta ball. This figures out all original meta | ||||
| * balls and all evaluated child meta balls (since polygonization is only stored in the mother | * balls and all evaluated child meta balls (since polygonization is only stored in the mother | ||||
| * ball). | * ball). | ||||
| * | * | ||||
| * We create empty mesh so scripters don't run into None objects. */ | * We create empty mesh so scripters don't run into None objects. */ | ||||
| if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL || | if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL || | ||||
| BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { | BLI_listbase_is_empty(&object->runtime.curve_cache->disp)) { | ||||
| return BKE_mesh_add(bmain, mball->id.name + 2); | return BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); | ||||
| } | } | ||||
| Mesh *mesh_result = BKE_mesh_add(bmain, ((ID *)object->data)->name + 2); | Mesh *mesh_result = BKE_id_new_nomain(ID_ME, ((ID *)object->data)->name + 2); | ||||
| BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); | BKE_mesh_from_metaball(&object->runtime.curve_cache->disp, mesh_result); | ||||
| /* Copy materials. */ | /* Copy materials. */ | ||||
| mesh_result->totcol = mball->totcol; | mesh_result->totcol = mball->totcol; | ||||
| mesh_result->mat = MEM_dupallocN(mball->mat); | mesh_result->mat = MEM_dupallocN(mball->mat); | ||||
| if (mball->mat != NULL) { | if (mball->mat != NULL) { | ||||
| for (int i = mball->totcol; i-- > 0;) { | for (int i = mball->totcol; i-- > 0;) { | ||||
| mesh_result->mat[i] = give_current_material(object, i + 1); | mesh_result->mat[i] = give_current_material(object, i + 1); | ||||
| } | } | ||||
| } | } | ||||
| return mesh_result; | return mesh_result; | ||||
| } | } | ||||
| static Mesh *mesh_new_from_mesh_object(Main *bmain, Object *object) | static Mesh *mesh_new_from_mesh_object(Object *object) | ||||
| { | { | ||||
| Mesh *mesh_input = object->data; | Mesh *mesh_input = object->data; | ||||
| Mesh *mesh_result = NULL; | Mesh *mesh_result = NULL; | ||||
| BKE_id_copy_ex(bmain, &mesh_input->id, (ID **)&mesh_result, 0); | BKE_id_copy_ex(NULL, | ||||
| &mesh_input->id, | |||||
| (ID **)&mesh_result, | |||||
| LIB_ID_CREATE_NO_MAIN | LIB_ID_CREATE_NO_USER_REFCOUNT); | |||||
| /* NOTE: Materials should already be copied. */ | /* NOTE: Materials should already be copied. */ | ||||
| return mesh_result; | return mesh_result; | ||||
| } | } | ||||
| Mesh *BKE_mesh_new_from_object(Main *bmain, Object *object) | Mesh *BKE_mesh_new_from_object(Object *object) | ||||
| { | { | ||||
| Mesh *new_mesh = NULL; | Mesh *new_mesh = NULL; | ||||
| switch (object->type) { | switch (object->type) { | ||||
| case OB_FONT: | case OB_FONT: | ||||
| case OB_CURVE: | case OB_CURVE: | ||||
| case OB_SURF: | case OB_SURF: | ||||
| new_mesh = mesh_new_from_curve_type_object(bmain, object); | new_mesh = mesh_new_from_curve_type_object(object); | ||||
| break; | break; | ||||
| case OB_MBALL: | case OB_MBALL: | ||||
| new_mesh = mesh_new_from_mball_object(bmain, object); | new_mesh = mesh_new_from_mball_object(object); | ||||
| break; | break; | ||||
| case OB_MESH: | case OB_MESH: | ||||
| new_mesh = mesh_new_from_mesh_object(bmain, object); | new_mesh = mesh_new_from_mesh_object(object); | ||||
| break; | break; | ||||
| default: | default: | ||||
| /* Object does not have geometry data. */ | /* Object does not have geometry data. */ | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| if (new_mesh == NULL) { | if (new_mesh == NULL) { | ||||
| /* Happens in special cases like request of mesh for non-mother meta ball. */ | /* Happens in special cases like request of mesh for non-mother meta ball. */ | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /* The result must have 0 users, since it's just a mesh which is free-dangling in the main | /* The result must have 0 users, since it's just a mesh which is free-dangling data-block. | ||||
| * database. All the copy and allocation functions to manipulate new Mesh datablock are ensuring | * All the conversion functions are supposed to ensure mesh is not counted. */ | ||||
| * an user. | BLI_assert(new_mesh->id.us == 0); | ||||
| * Here we control that user management went the way it's expected, and cancel out the user. */ | |||||
| BLI_assert(new_mesh->id.us == 1); | |||||
| id_us_min(&new_mesh->id); | |||||
| return new_mesh; | return new_mesh; | ||||
| } | } | ||||
| static int foreach_libblock_make_original_and_usercount_callback(void *user_data_v, | |||||
| ID *id_self, | |||||
| ID **id_p, | |||||
| int cb_flag) | |||||
| { | |||||
| UNUSED_VARS(user_data_v, id_self, cb_flag); | |||||
| if (*id_p == NULL) { | |||||
| return IDWALK_RET_NOP; | |||||
| } | |||||
| *id_p = DEG_get_original_id(*id_p); | |||||
| id_us_plus(*id_p); | |||||
| return IDWALK_RET_NOP; | |||||
| } | |||||
| Mesh *BKE_mesh_new_from_object_to_bmain(Main *bmain, Object *object) | |||||
| { | |||||
| Mesh *mesh = BKE_mesh_new_from_object(object); | |||||
| /* Make sure mesh only points original datablocks, also increase users of materials and other | |||||
| * possibly referenced data-blocks. | |||||
| * | |||||
| * Going to original data-blocks is required to have bmain in a consistent state, where | |||||
| * everything is only allowed to reference original data-blocks. | |||||
| * | |||||
| * user-count is required is because so far mesh was in a limbo, where library management does | |||||
| * not perform any user management (i.e. copy of a mesh will not increase users of materials). */ | |||||
| BKE_library_foreach_ID_link( | |||||
| NULL, &mesh->id, foreach_libblock_make_original_and_usercount_callback, NULL, IDWALK_NOP); | |||||
| /* Append the mesh to bmain. | |||||
| * We do it a bit longer way since there is no simple and clear way of adding existing datablock | |||||
| * to the bmain. So we allocate new empty mesh in the bmain (which guarantess all the naming and | |||||
| * orders and flags) and move the temporary mesh in place there. */ | |||||
| Mesh *mesh_in_bmain = BKE_mesh_add(bmain, mesh->id.name + 2); | |||||
| BKE_mesh_nomain_to_mesh(mesh, mesh_in_bmain, NULL, &CD_MASK_MESH, true); | |||||
| /* Make sure user count from BKE_mesh_add() is the one we expect here and bring it down to 0. */ | |||||
| BLI_assert(mesh_in_bmain->id.us == 1); | |||||
| id_us_min(&mesh_in_bmain->id); | |||||
| return mesh_in_bmain; | |||||
| } | |||||
| static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) | static void add_shapekey_layers(Mesh *mesh_dest, Mesh *mesh_src) | ||||
| { | { | ||||
| KeyBlock *kb; | KeyBlock *kb; | ||||
| Key *key = mesh_src->key; | Key *key = mesh_src->key; | ||||
| int i; | int i; | ||||
| if (!mesh_src->key) { | if (!mesh_src->key) { | ||||
| return; | return; | ||||
| ▲ Show 20 Lines • Show All 342 Lines • Show Last 20 Lines | |||||