diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/blenkernel/BKE_mesh.h | 8 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_object.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/mesh_convert.c | 114 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/object.c | 19 | ||||
-rw-r--r-- | source/blender/editors/object/object_bake_api.c | 22 | ||||
-rw-r--r-- | source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp | 5 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_object_types.h | 5 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_internal.h | 3 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_main_api.c | 4 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_object_api.c | 40 |
10 files changed, 171 insertions, 58 deletions
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 8ea54457f38..c410946f438 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -208,7 +208,13 @@ float (*BKE_mesh_vertexCos_get(const struct Mesh *me, int *r_numVerts))[3]; void BKE_mesh_split_faces(struct Mesh *mesh, bool free_loop_normals); -struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Object *object); +/* Create new mesh from the given object at its current state. + * The owner of this mesh is unknown, it is up to the caller to decide. */ +struct Mesh *BKE_mesh_new_from_object(struct Object *object); + +/* This is a version of BKE_mesh_new_from_object() which stores mesh in the given main database. */ +struct Mesh *BKE_mesh_new_from_object_to_bmain(struct Main *bmain, struct Object *object); + struct Mesh *BKE_mesh_create_derived_for_modifier(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob_eval, diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index c373fbfe478..aa4d9696527 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -396,6 +396,15 @@ bool BKE_object_empty_image_frame_is_visible_in_view3d(const struct Object *ob, bool BKE_object_empty_image_data_is_visible_in_view3d(const struct Object *ob, const struct RegionView3D *rv3d); +/* This is an utility function for Python's object.to_mesh() (the naming is not very clear though). + * The result is owned by the object. + * + * The mesh will be freed when object is re-evaluated or is destroyed. It is possible to force to + * clear memory sued by this mesh by calling BKE_object_to_mesh_clear(). */ +struct Mesh *BKE_object_to_mesh(struct Object *object); + +void BKE_object_to_mesh_clear(struct Object *object); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/mesh_convert.c b/source/blender/blenkernel/intern/mesh_convert.c index a5c97cd1182..6d0245cbc88 100644 --- a/source/blender/blenkernel/intern/mesh_convert.c +++ b/source/blender/blenkernel/intern/mesh_convert.c @@ -38,6 +38,7 @@ #include "BKE_main.h" #include "BKE_DerivedMesh.h" #include "BKE_key.h" +#include "BKE_library_query.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -612,7 +613,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, } /* make mesh */ - me = BKE_mesh_add(bmain, obdata_name); + if (bmain != NULL) { + me = BKE_mesh_add(bmain, obdata_name); + } + else { + me = BKE_id_new_nomain(ID_ME, obdata_name); + } + me->totvert = totvert; me->totedge = totedge; me->totloop = totloop; @@ -632,7 +639,13 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, BKE_mesh_calc_normals(me); } else { - me = BKE_mesh_add(bmain, obdata_name); + if (bmain != NULL) { + me = BKE_mesh_add(bmain, obdata_name); + } + else { + me = BKE_id_new_nomain(ID_ME, obdata_name); + } + ob->runtime.mesh_eval = NULL; BKE_mesh_nomain_to_mesh(me_eval, me, ob, &CD_MASK_MESH, true); } @@ -662,16 +675,18 @@ void BKE_mesh_from_nurbs_displist(Main *bmain, ob->type = OB_MESH; /* other users */ - ob1 = bmain->objects.first; - while (ob1) { - if (ob1->data == cu) { - ob1->type = OB_MESH; - - id_us_min((ID *)ob1->data); - ob1->data = ob->data; - id_us_plus((ID *)ob1->data); + if (bmain != NULL) { + ob1 = bmain->objects.first; + while (ob1) { + if (ob1->data == cu) { + ob1->type = OB_MESH; + + id_us_min((ID *)ob1->data); + ob1->data = ob->data; + id_us_plus((ID *)ob1->data); + } + ob1 = ob1->id.next; } - ob1 = ob1->id.next; } if (temporary) { @@ -995,7 +1010,7 @@ static void curve_to_mesh_eval_ensure(Object *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; const bool uv_from_orco = (curve->flag & CU_UV_ORCO) != 0; @@ -1014,7 +1029,7 @@ static Mesh *mesh_new_from_curve_type_object(Main *bmain, Object *object) temp_curve->editnurb = NULL; /* Convert to mesh. */ - BKE_mesh_from_nurbs_displist(bmain, + BKE_mesh_from_nurbs_displist(NULL, temp_object, &temp_object->runtime.curve_cache->disp, uv_from_orco, @@ -1037,7 +1052,7 @@ static Mesh *mesh_new_from_curve_type_object(Main *bmain, Object *object) 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; @@ -1048,10 +1063,10 @@ static Mesh *mesh_new_from_mball_object(Main *bmain, Object *object) * We create empty mesh so scripters don't run into None objects. */ if (!DEG_is_evaluated_object(object) || object->runtime.curve_cache == NULL || 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); /* Copy materials. */ @@ -1066,29 +1081,32 @@ static Mesh *mesh_new_from_mball_object(Main *bmain, Object *object) 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_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. */ 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; switch (object->type) { case OB_FONT: case OB_CURVE: case OB_SURF: - new_mesh = mesh_new_from_curve_type_object(bmain, object); + new_mesh = mesh_new_from_curve_type_object(object); break; case OB_MBALL: - new_mesh = mesh_new_from_mball_object(bmain, object); + new_mesh = mesh_new_from_mball_object(object); break; case OB_MESH: - new_mesh = mesh_new_from_mesh_object(bmain, object); + new_mesh = mesh_new_from_mesh_object(object); break; default: /* Object does not have geometry data. */ @@ -1098,15 +1116,55 @@ Mesh *BKE_mesh_new_from_object(Main *bmain, Object *object) /* Happens in special cases like request of mesh for non-mother meta ball. */ return NULL; } - /* The result must have 0 users, since it's just a mesh which is free-dangling in the main - * database. All the copy and allocation functions to manipulate new Mesh datablock are ensuring - * an user. - * 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); + /* The result must have 0 users, since it's just a mesh which is free-dangling data-block. + * All the conversion functions are supposed to ensure mesh is not counted. */ + BLI_assert(new_mesh->id.us == 0); 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) { KeyBlock *kb; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 78f2b10305e..95be7f8f51f 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -469,6 +469,7 @@ void BKE_object_free_derived_caches(Object *ob) ob->runtime.mesh_deform_eval = NULL; } + BKE_object_to_mesh_clear(ob); BKE_object_free_curve_cache(ob); /* clear grease pencil data */ @@ -4497,3 +4498,21 @@ void BKE_object_update_select_id(struct Main *bmain) ob = ob->id.next; } } + +Mesh *BKE_object_to_mesh(Object *object) +{ + BKE_object_to_mesh_clear(object); + + Mesh *mesh = BKE_mesh_new_from_object(object); + object->runtime.object_as_temp_mesh = mesh; + return mesh; +} + +void BKE_object_to_mesh_clear(Object *object) +{ + if (object->runtime.object_as_temp_mesh == NULL) { + return; + } + BKE_id_free(NULL, object->runtime.object_as_temp_mesh); + object->runtime.object_as_temp_mesh = NULL; +} diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 4f26ae27d9c..f87342a14ad 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -705,9 +705,9 @@ static size_t initialize_internal_images(BakeImages *bake_images, ReportList *re } /* create new mesh with edit mode changes and modifiers applied */ -static Mesh *bake_mesh_new_from_object(Main *bmain, Object *object) +static Mesh *bake_mesh_new_from_object(Object *object) { - Mesh *me = BKE_mesh_new_from_object(bmain, object); + Mesh *me = BKE_object_to_mesh(object); if (me->flag & ME_AUTOSMOOTH) { BKE_mesh_split_faces(me, true); @@ -903,7 +903,7 @@ static int bake(Render *re, ob_low_eval = DEG_get_evaluated_object(depsgraph, ob_low); /* get the mesh as it arrives in the renderer */ - me_low = bake_mesh_new_from_object(bmain, ob_low_eval); + me_low = bake_mesh_new_from_object(ob_low_eval); /* populate the pixel array with the face data */ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false) { @@ -917,7 +917,7 @@ static int bake(Render *re, /* prepare cage mesh */ if (ob_cage) { - me_cage = bake_mesh_new_from_object(bmain, ob_cage_eval); + me_cage = bake_mesh_new_from_object(ob_cage_eval); if ((me_low->totpoly != me_cage->totpoly) || (me_low->totloop != me_cage->totloop)) { BKE_report(reports, RPT_ERROR, @@ -946,7 +946,7 @@ static int bake(Render *re, md = md_next; } - me_cage = bake_mesh_new_from_object(bmain, ob_low_eval); + me_cage = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer); } @@ -965,7 +965,7 @@ static int bake(Render *re, highpoly[i].ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter); highpoly[i].ob_eval->restrictflag &= ~OB_RESTRICT_RENDER; highpoly[i].ob_eval->base_flag |= (BASE_VISIBLE | BASE_ENABLED_RENDER); - highpoly[i].me = bake_mesh_new_from_object(bmain, highpoly[i].ob_eval); + highpoly[i].me = BKE_object_to_mesh(highpoly[i].ob_eval); /* lowpoly to highpoly transformation matrix */ copy_m4_m4(highpoly[i].obmat, highpoly[i].ob->obmat); @@ -1088,7 +1088,7 @@ static int bake(Render *re, } /* Evaluate modifiers again. */ - me_nores = BKE_mesh_new_from_object(bmain, ob_low_eval); + me_nores = BKE_object_to_mesh(ob_low_eval); RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images, uv_layer); RE_bake_normal_world_to_tangent(pixel_array_low, @@ -1098,7 +1098,7 @@ static int bake(Render *re, me_nores, normal_swizzle, ob_low_eval->obmat); - BKE_id_free(bmain, me_nores); + BKE_object_to_mesh_clear(ob_low_eval); if (md) { md->mode = mode; @@ -1222,7 +1222,7 @@ cleanup: int i; for (i = 0; i < tot_highpoly; i++) { if (highpoly[i].me) { - BKE_id_free(bmain, highpoly[i].me); + BKE_object_to_mesh_clear(highpoly[i].ob_eval); } } MEM_freeN(highpoly); @@ -1253,11 +1253,11 @@ cleanup: } if (me_low) { - BKE_id_free(bmain, me_low); + BKE_object_to_mesh_clear(ob_low_eval); } if (me_cage) { - BKE_id_free(bmain, me_cage); + BKE_object_to_mesh_clear(ob_cage_eval); } DEG_graph_free(depsgraph); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index ed553c9583c..ee13583e67a 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -23,6 +23,7 @@ #include "BLI_utildefines.h" #include "BKE_global.h" +#include "BKE_object.h" #include <sstream> @@ -98,11 +99,11 @@ NodeGroup *BlenderFileLoader::Load() continue; } - Mesh *mesh = BKE_mesh_new_from_object(_re->main, ob); + Mesh *mesh = BKE_object_to_mesh(ob); if (mesh) { insertShapeNode(ob, mesh, ++id); - BKE_id_free_ex(_re->main, &mesh->id, LIB_ID_FREE_NO_UI_USER, true); + BKE_object_to_mesh_clear(ob); } } DEG_OBJECT_ITER_END; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index a73c762e3bf..0b2f3d69bd2 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -43,6 +43,7 @@ struct DerivedMesh; struct FluidsimSettings; struct GpencilBatchCache; struct Ipo; +struct Mesh; struct Material; struct Object; struct PartDeflect; @@ -160,6 +161,10 @@ typedef struct Object_Runtime { */ struct Mesh *mesh_deform_eval; + /* This is a mesh representation of corresponding object. + * It created when Python calls `object.to_mesh()`. */ + struct Mesh *object_as_temp_mesh; + /** Runtime evaluated curve-specific data, not stored in the file. */ struct CurveCache *curve_cache; diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index d93f8c4414b..64024166c50 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -548,9 +548,6 @@ PointerRNA rna_pointer_inherit_refine(struct PointerRNA *ptr, struct StructRNA * int rna_parameter_size(struct PropertyRNA *parm); -struct Mesh *rna_Main_meshes_new_from_object(struct Main *bmain, - struct ReportList *reports, - struct Object *object); /* XXX, these should not need to be defined here~! */ struct MTex *rna_mtex_texture_slots_add(struct ID *self, diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 8f48738a27e..f6fee2580b8 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -317,7 +317,7 @@ static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) } /* copied from Mesh_getFromObject and adapted to RNA interface */ -Mesh *rna_Main_meshes_new_from_object(Main *bmain, ReportList *reports, Object *object) +static Mesh *rna_Main_meshes_new_from_object(Main *bmain, ReportList *reports, Object *object) { switch (object->type) { case OB_FONT: @@ -331,7 +331,7 @@ Mesh *rna_Main_meshes_new_from_object(Main *bmain, ReportList *reports, Object * return NULL; } - return BKE_mesh_new_from_object(bmain, object); + return BKE_mesh_new_from_object_to_bmain(bmain, object); } static Light *rna_Main_lights_new(Main *bmain, const char *name, int type) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index d94abd4066a..da00e1f155d 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -375,11 +375,28 @@ static void rna_Object_camera_fit_coords( } /* copied from Mesh_getFromObject and adapted to RNA interface */ -static Mesh *rna_Object_to_mesh(Object *object, bContext *C, ReportList *reports) +static Mesh *rna_Object_to_mesh(Object *object, ReportList *reports) { - Main *bmain = CTX_data_main(C); + /* TODO(sergey): Make it more re-usable function, de-duplicate with + * rna_Main_meshes_new_from_object. */ + switch (object->type) { + case OB_FONT: + case OB_CURVE: + case OB_SURF: + case OB_MBALL: + case OB_MESH: + break; + default: + BKE_report(reports, RPT_ERROR, "Object does not have geometry data"); + return NULL; + } + + return BKE_object_to_mesh(object); +} - return rna_Main_meshes_new_from_object(bmain, reports, object); +static void rna_Object_to_mesh_clear(Object *object) +{ + BKE_object_to_mesh_clear(object); } static PointerRNA rna_Object_shape_key_add( @@ -875,16 +892,17 @@ void RNA_api_object(StructRNA *srna) /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); - RNA_def_function_ui_description(func, - "Create a Mesh data-block from the current state of the object"); - RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); - parm = RNA_def_pointer(func, - "mesh", - "Mesh", - "", - "Mesh created from object, remove it if it is only used for export"); + RNA_def_function_ui_description( + func, + "Create a Mesh data-block from the current state of the object. The object owns the " + "data-block. To force free it use to_mesh_clear()"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); + parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh created from object"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "to_mesh_clear", "rna_Object_to_mesh_clear"); + RNA_def_function_ui_description(func, "Clears mesh data-block created by to_mesh()"); + /* Armature */ func = RNA_def_function(srna, "find_armature", "modifiers_isDeformedByArmature"); RNA_def_function_ui_description( |