diff options
author | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-12 01:01:38 +0300 |
---|---|---|
committer | Bastien Montagne <montagne29@wanadoo.fr> | 2016-07-12 01:07:44 +0300 |
commit | cfbd605567f48229a923df382baf6db98fbafc61 (patch) | |
tree | d4218c49672047d6c3b37517034660b3b5dcd966 /source/blender/blenkernel | |
parent | 71a57a37b2eebbed53b5335019287b4df9c30519 (diff) | |
parent | 7212ebd09f9720883581221be923ae5e97ff5d76 (diff) |
Merge branch 'master' into blender2.8
Conflicts:
intern/cycles/blender/addon/ui.py
source/blender/blenkernel/BKE_particle.h
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenkernel/intern/particle_distribute.c
source/blender/blenkernel/intern/texture.c
source/blender/editors/object/object_add.c
source/blender/editors/object/object_relations.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_object.c
source/blender/editors/transform/transform_snap_object.c
Diffstat (limited to 'source/blender/blenkernel')
70 files changed, 1622 insertions, 1664 deletions
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index cb282b46bec..5874f95502b 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -58,13 +58,12 @@ extern "C" { struct bAction *add_empty_action(struct Main *bmain, const char name[]); /* Allocate a copy of the given Action and all its data */ -struct bAction *BKE_action_copy(struct bAction *src); +struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src); /* Deallocate all of the Action's data, but not the Action itself */ void BKE_action_free(struct bAction *act); -// XXX is this needed? -void BKE_action_make_local(struct bAction *act); +void BKE_action_make_local(struct Main *bmain, struct bAction *act); /* Action API ----------------- */ diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 772e08589c1..983f3ce22b8 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -50,7 +50,8 @@ struct AnimMapper; /* AnimData API */ /* Check if the given ID-block can have AnimData */ -bool id_type_can_have_animdata(struct ID *id); +bool id_type_can_have_animdata(const short id_type); +bool id_can_have_animdata(const struct ID *id); /* Get AnimData from the given ID-block */ struct AnimData *BKE_animdata_from_id(struct ID *id); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index cc082c084ce..326c335338f 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -76,8 +76,8 @@ struct bArmature *BKE_armature_from_object(struct Object *ob); int BKE_armature_bonelist_count(struct ListBase *lb); void BKE_armature_bonelist_free(struct ListBase *lb); void BKE_armature_free(struct bArmature *arm); -void BKE_armature_make_local(struct bArmature *arm); -struct bArmature *BKE_armature_copy(struct bArmature *arm); +void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm); +struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm); /* Bounding box. */ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index c663458963c..c7116bf2ef6 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -44,8 +44,8 @@ void BKE_brush_system_exit(void); void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); -struct Brush *BKE_brush_copy(struct Brush *brush); -void BKE_brush_make_local(struct Brush *brush); +struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush); +void BKE_brush_make_local(struct Main *bmain, struct Brush *brush); void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); void BKE_brush_free(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 7ec91b006b2..07db2217bac 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -46,8 +46,8 @@ struct MFace; typedef struct LinkNode BVHCache; /** -* struct that kepts basic information about a BVHTree build from a editmesh -*/ + * struct that kepts basic information about a BVHTree build from a editmesh + */ typedef struct BVHTreeFromEditMesh { struct BVHTree *tree; @@ -122,6 +122,14 @@ BVHTree *bvhtree_from_mesh_verts_ex( const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis); + BVHTree *bvhtree_from_mesh_edges( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index d13a711c589..97f4b30894b 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -52,8 +52,8 @@ struct GPUFXSettings; void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); -struct Camera *BKE_camera_copy(struct Camera *cam); -void BKE_camera_make_local(struct Camera *cam); +struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam); +void BKE_camera_make_local(struct Main *bmain, struct Camera *cam); void BKE_camera_free(struct Camera *ca); /* Camera Usage */ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 23b3128f328..89dbe246910 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -70,8 +70,8 @@ void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); -struct Curve *BKE_curve_copy(struct Curve *cu); -void BKE_curve_make_local(struct Curve *cu); +struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu); +void BKE_curve_make_local(struct Main *bmain, struct Curve *cu); short BKE_curve_type_get(struct Curve *cu); void BKE_curve_type_test(struct Object *ob); void BKE_curve_curve_dimension_update(struct Curve *cu); @@ -150,6 +150,16 @@ void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3 void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv); void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride); +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint); +void BKE_curve_calc_coords_axis( + const struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points); + void BKE_nurb_knot_calc_u(struct Nurb *nu); void BKE_nurb_knot_calc_v(struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 26a40597ca8..5ef5a807f63 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -178,6 +178,7 @@ enum { #define G_FILE_MESH_COMPAT (1 << 26) /* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */ #define G_FILE_SAVE_COPY (1 << 27) +#define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28) #define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 24e330d927f..6159531d8bd 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -36,6 +36,7 @@ struct bGPdata; struct bGPDlayer; struct bGPDframe; struct bGPDstroke; +struct Main; /* ------------ Grease-Pencil API ------------------ */ @@ -53,7 +54,7 @@ struct bGPdata *gpencil_data_addnew(const char name[]); struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src); -struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy); +struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy); void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index ae6e52b613b..4f2c89070cb 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -42,7 +42,7 @@ struct Scene; void BKE_group_free(struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); -struct Group *BKE_group_copy(struct Group *group); +struct Group *BKE_group_copy(struct Main *bmain, struct Group *group); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); struct Group *BKE_group_object_find(struct Group *group, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index eb98268c9f0..0895feef983 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char void BKE_image_de_interlace(struct Image *ima, int odd); -void BKE_image_make_local(struct Image *ima); +void BKE_image_make_local(struct Main *bmain, struct Image *ima); void BKE_image_tag_time(struct Image *ima); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 1edbb455ca4..f30f9eac4e8 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -39,6 +39,7 @@ struct ListBase; struct Curve; struct Object; struct Lattice; +struct Main; struct Mesh; struct WeightsArrayCache; @@ -50,9 +51,9 @@ extern "C" { void BKE_key_free(struct Key *sc); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); -struct Key *BKE_key_copy(struct Key *key); +struct Key *BKE_key_copy(struct Main *bmain, struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); -void BKE_key_make_local(struct Key *key); +void BKE_key_make_local(struct Main *bmain, struct Key *key); void BKE_key_sort(struct Key *key); void key_curve_position_weights(float t, float data[4], int type); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index d830c19651f..49b43550e67 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -44,9 +44,9 @@ struct Scene; void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; -struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; +struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; -void BKE_lamp_make_local(struct Lamp *la); +void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la); void BKE_lamp_free(struct Lamp *la); void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 828a40de1c9..606df9dcec8 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -47,9 +47,9 @@ struct MDeformVert; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); -struct Lattice *BKE_lattice_copy(struct Lattice *lt); +struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); -void BKE_lattice_make_local(struct Lattice *lt); +void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); struct LatticeDeformData; diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 2e225775af0..cb39b2e53ee 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -52,9 +52,8 @@ struct PropertyRNA; void *BKE_libblock_alloc_notest(short type); void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_init_empty(struct ID *id); -void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL(); -void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); void BKE_libblock_relink(struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); @@ -81,10 +80,11 @@ void id_us_min(struct ID *id); void id_fake_user_set(struct ID *id); void id_fake_user_clear(struct ID *id); -bool id_make_local(struct ID *id, bool test); +bool id_make_local(struct Main *bmain, struct ID *id, bool test); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); -bool id_copy(struct ID *id, struct ID **newid, bool test); +bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test); void id_sort_by_name(struct ListBase *lb, struct ID *id); +void BKE_id_expand_local(struct ID *id); bool new_id(struct ListBase *lb, struct ID *id, const char *name); void id_clear_lib_data(struct Main *bmain, struct ID *id); diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index c89dce99caa..c5f575c8c0f 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -41,6 +41,12 @@ enum { IDWALK_NEVER_SELF = (1 << 1), /** + * Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage. + * \note Object proxies are half-local, half-linked... + */ + IDWALK_INDIRECT_USAGE = (1 << 2), + + /** * Adjusts #ID.us reference-count. * \note keep in sync with 'newlibadr_us' use in readfile.c */ @@ -53,7 +59,7 @@ enum { enum { IDWALK_RET_NOP = 0, - IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */ + IDWALK_RET_STOP_ITER = 1 << 0, /* Completly stop iteration. */ IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */ }; @@ -76,4 +82,10 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used); +bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used); + +bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv); +bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv); +void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked); + #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h index e85a3e60751..e974b79ee66 100644 --- a/source/blender/blenkernel/BKE_library_remap.h +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -56,9 +56,13 @@ void BKE_libblock_remap( struct Main *bmain, void *old_idv, void *new_idv, const short remap_flags) ATTR_NONNULL(1, 2); -void BKE_libblock_unlink(struct Main *bmain, void *idv, const bool do_flag_never_null) ATTR_NONNULL(); +void BKE_libblock_unlink( + struct Main *bmain, void *idv, + const bool do_flag_never_null, const bool do_skip_indirect) ATTR_NONNULL(); -void BKE_libblock_relink_ex(void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) ATTR_NONNULL(1); +void BKE_libblock_relink_ex( + struct Main *bmain, void *idv, void *old_idv, void *new_idv, + const bool us_min_never_null) ATTR_NONNULL(1, 2); typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); @@ -73,4 +77,4 @@ void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor } #endif -#endif /* __BKE_LIBRARY_REMAP_H__ */
\ No newline at end of file +#endif /* __BKE_LIBRARY_REMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index f3d12b5a8cc..97bfd0f3f07 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -123,7 +123,7 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask /* general */ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); -struct Mask *BKE_mask_copy(struct Mask *mask); +struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask); void BKE_mask_free(struct Mask *mask); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 852564c8d90..0bc54ee4a16 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -47,17 +47,17 @@ struct Scene; void init_def_material(void); void BKE_material_free(struct Material *ma); void BKE_material_free_ex(struct Material *ma, bool do_id_user); -void test_object_materials(struct Main *bmain, struct ID *id); +void test_object_materials(struct Object *ob, struct ID *id); +void test_all_objects_materials(struct Main *bmain, struct ID *id); void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); -struct Material *BKE_material_copy(struct Material *ma); +struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma); struct Material *localize_material(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ -void BKE_material_make_local(struct Material *ma); -void extern_local_matarar(struct Material **matar, short totcol); +void BKE_material_make_local(struct Main *bmain, struct Material *ma); /* UNUSED */ // void automatname(struct Material *); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index b8258455c65..42704c1b2db 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -41,9 +41,9 @@ struct MetaElem; void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); -struct MetaBall *BKE_mball_copy(struct MetaBall *mb); +struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb); -void BKE_mball_make_local(struct MetaBall *mb); +void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 9330f41d19a..d3bb34d7a41 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -32,6 +32,7 @@ */ struct ID; +struct BMeshCreateParams; struct BoundBox; struct EdgeHash; struct ListBase; @@ -69,7 +70,9 @@ extern "C" { /* *** mesh.c *** */ -struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index); +struct BMesh *BKE_mesh_to_bmesh( + struct Mesh *me, struct Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params); int poly_find_loop_from_vert( const struct MPoly *poly, @@ -84,12 +87,11 @@ int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); -struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me); -struct Mesh *BKE_mesh_copy(struct Mesh *me); +struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); -void BKE_mesh_make_local(struct Mesh *me); +void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me); void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]); void BKE_mesh_texspace_calc(struct Mesh *me); float (*BKE_mesh_orco_verts_get(struct Object *ob))[3]; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index bf198c9b86b..b44cb226f0d 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -336,7 +336,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char /* copy/free funcs, need to manage ID users */ void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); -struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); +struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree); void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user); void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to); /* node->id user count */ @@ -346,7 +346,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree *ntreeFromID(struct ID *id); -void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist); +void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 612c758139a..2c4df9620c2 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -103,8 +103,8 @@ struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene) struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches); -struct Object *BKE_object_copy(struct Object *ob); -void BKE_object_make_local(struct Object *ob); +struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob); +void BKE_object_make_local(struct Main *bmain, struct Object *ob); bool BKE_object_is_libdata(struct Object *ob); bool BKE_object_obdata_is_libdata(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index ccb7dc8e015..03af0b7d6c9 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -98,7 +98,7 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); -struct Scene *BKE_scene_copy(struct Scene *sce, int type); +struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); struct Object *BKE_scene_camera_find(struct Scene *sc); diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 5f30df1d6e3..89b948a2126 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -33,8 +33,8 @@ struct Speaker; void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); -struct Speaker *BKE_speaker_copy(struct Speaker *spk); -void BKE_speaker_make_local(struct Speaker *spk); +struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk); +void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk); void BKE_speaker_free(struct Speaker *spk); #endif diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 43378551449..52b1906a78b 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -68,10 +68,10 @@ void colorband_update_sort(struct ColorBand *coba); void BKE_texture_free(struct Tex *tex); void BKE_texture_default(struct Tex *tex); -struct Tex *BKE_texture_copy(struct Tex *tex); +struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex); struct Tex *BKE_texture_add(struct Main *bmain, const char *name); struct Tex *BKE_texture_localize(struct Tex *tex); -void BKE_texture_make_local(struct Tex *tex); +void BKE_texture_make_local(struct Main *bmain, struct Tex *tex); void BKE_texture_type_set(struct Tex *tex, int type); void BKE_texture_mtex_default(struct MTex *mtex); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 0be61fe0229..da5cca09b27 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -39,9 +39,9 @@ struct World; void BKE_world_free(struct World *sc); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); -struct World *BKE_world_copy(struct World *wrld); +struct World *BKE_world_copy(struct Main *bmain, struct World *wrld); struct World *localize_world(struct World *wrld); -void BKE_world_make_local(struct World *wrld); +void BKE_world_make_local(struct Main *bmain, struct World *wrld); #endif diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 46ee8a4d888..f7ff1261c8a 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -59,6 +59,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_object.h" @@ -92,68 +94,34 @@ bAction *add_empty_action(Main *bmain, const char name[]) /* .................................. */ -/* temp data for BKE_action_make_local */ -typedef struct tMakeLocalActionContext { - bAction *act; /* original action */ - bAction *act_new; /* new action */ - - bool is_lib; /* some action users were libraries */ - bool is_local; /* some action users were not libraries */ -} tMakeLocalActionContext; - -/* helper function for BKE_action_make_local() - local/lib init step */ -static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr) +// does copy_fcurve... +void BKE_action_make_local(Main *bmain, bAction *act) { - tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; - - if (adt->action == mlac->act) { - if (id->lib) mlac->is_lib = true; - else mlac->is_local = true; - } -} + bool is_local = false, is_lib = false; -/* helper function for BKE_action_make_local() - change references */ -static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr) -{ - tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; - - if (adt->action == mlac->act) { - if (id->lib == NULL) { - adt->action = mlac->act_new; - - id_us_plus(&mlac->act_new->id); - id_us_min(&mlac->act->id); - } - } -} + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ -// does copy_fcurve... -void BKE_action_make_local(bAction *act) -{ - tMakeLocalActionContext mlac = {act, NULL, false, false}; - Main *bmain = G.main; - - if (act->id.lib == NULL) - return; - - /* XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default */ - if ((act->id.flag & LIB_FAKEUSER) && (act->id.us <= 1)) { - id_clear_lib_data(bmain, &act->id); + if (!ID_IS_LINKED_DATABLOCK(act)) { return; } - - BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac); - - if (mlac.is_local && mlac.is_lib == false) { - id_clear_lib_data(bmain, &act->id); - } - else if (mlac.is_local && mlac.is_lib) { - mlac.act_new = BKE_action_copy(act); - mlac.act_new->id.us = 0; - BKE_id_lib_local_paths(bmain, act->id.lib, &mlac.act_new->id); + BKE_library_ID_test_usages(bmain, act, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &act->id); + BKE_id_expand_local(&act->id); + } + else { + bAction *act_new = BKE_action_copy(bmain, act); + + act_new->id.us = 0; - BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac); + BKE_libblock_remap(bmain, act, act_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } @@ -176,7 +144,7 @@ void BKE_action_free(bAction *act) /* .................................. */ -bAction *BKE_action_copy(bAction *src) +bAction *BKE_action_copy(Main *bmain, bAction *src) { bAction *dst = NULL; bActionGroup *dgrp, *sgrp; @@ -184,7 +152,7 @@ bAction *BKE_action_copy(bAction *src) if (src == NULL) return NULL; - dst = BKE_libblock_copy(&src->id); + dst = BKE_libblock_copy(bmain, &src->id); /* duplicate the lists of groups and markers */ BLI_duplicatelist(&dst->groups, &src->groups); @@ -213,8 +181,9 @@ bAction *BKE_action_copy(bAction *src) } } - if (src->id.lib) { - BKE_id_lib_local_paths(G.main, src->id.lib, &dst->id); + if (ID_IS_LINKED_DATABLOCK(src)) { + BKE_id_expand_local(&dst->id); + BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id); } return dst; diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index b7e8bc62470..7f10f6833db 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -79,15 +79,11 @@ /* Getter/Setter -------------------------------------------- */ /* Check if ID can have AnimData */ -bool id_type_can_have_animdata(ID *id) +bool id_type_can_have_animdata(const short id_type) { - /* sanity check */ - if (id == NULL) - return false; - /* Only some ID-blocks have this info for now */ /* TODO: finish adding this for the other blocktypes */ - switch (GS(id->name)) { + switch (id_type) { /* has AnimData */ case ID_OB: case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT: @@ -100,9 +96,7 @@ bool id_type_can_have_animdata(ID *id) case ID_MC: case ID_MSK: case ID_GD: - { return true; - } /* no AnimData */ default: @@ -110,6 +104,14 @@ bool id_type_can_have_animdata(ID *id) } } +bool id_can_have_animdata(const ID *id) +{ + /* sanity check */ + if (id == NULL) + return false; + + return id_type_can_have_animdata(GS(id->name)); +} /* Get AnimData from the given ID-block. In order for this to work, we assume that * the AnimData pointer is stored immediately after the given ID-block in the struct, @@ -121,7 +123,7 @@ AnimData *BKE_animdata_from_id(ID *id) * types that do to be of type IdAdtTemplate, and extract the * AnimData that way */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; return iat->adt; } @@ -139,7 +141,7 @@ AnimData *BKE_animdata_add_id(ID *id) * types that do to be of type IdAdtTemplate, and add the AnimData * to it using the template */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; /* check if there's already AnimData, in which case, don't add */ @@ -220,7 +222,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user) /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; AnimData *adt = iat->adt; @@ -265,8 +267,8 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) /* make a copy of action - at worst, user has to delete copies... */ if (do_action) { - dadt->action = BKE_action_copy(adt->action); - dadt->tmpact = BKE_action_copy(adt->tmpact); + dadt->action = BKE_action_copy(G.main, adt->action); + dadt->tmpact = BKE_action_copy(G.main, adt->tmpact); } else { id_us_plus((ID *)dadt->action); @@ -310,11 +312,11 @@ void BKE_animdata_copy_id_action(ID *id) if (adt) { if (adt->action) { id_us_min((ID *)adt->action); - adt->action = BKE_action_copy(adt->action); + adt->action = BKE_action_copy(G.main, adt->action); } if (adt->tmpact) { id_us_min((ID *)adt->tmpact); - adt->tmpact = BKE_action_copy(adt->tmpact); + adt->tmpact = BKE_action_copy(G.main, adt->tmpact); } } } @@ -338,8 +340,8 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a /* handle actions... */ if (action_mode == ADT_MERGECOPY_SRC_COPY) { /* make a copy of the actions */ - dst->action = BKE_action_copy(src->action); - dst->tmpact = BKE_action_copy(src->tmpact); + dst->action = BKE_action_copy(G.main, src->action); + dst->tmpact = BKE_action_copy(G.main, src->tmpact); } else if (action_mode == ADT_MERGECOPY_SRC_REF) { /* make a reference to it */ @@ -397,8 +399,8 @@ static void make_local_strips(ListBase *strips) NlaStrip *strip; for (strip = strips->first; strip; strip = strip->next) { - if (strip->act) BKE_action_make_local(strip->act); - if (strip->remap && strip->remap->target) BKE_action_make_local(strip->remap->target); + if (strip->act) BKE_action_make_local(G.main, strip->act); + if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target); make_local_strips(&strip->strips); } @@ -410,10 +412,10 @@ void BKE_animdata_make_local(AnimData *adt) NlaTrack *nlt; /* Actions - Active and Temp */ - if (adt->action) BKE_action_make_local(adt->action); - if (adt->tmpact) BKE_action_make_local(adt->tmpact); + if (adt->action) BKE_action_make_local(G.main, adt->action); + if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact); /* Remaps */ - if (adt->remap && adt->remap->target) BKE_action_make_local(adt->remap->target); + if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target); /* Drivers */ /* TODO: need to remap the ID-targets too? */ @@ -1048,7 +1050,7 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix) */ NlaTrack *nlt; - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; AnimData *adt = iat->adt; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b59618f46b2..5f564e1c4d2 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -67,6 +67,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" @@ -142,46 +144,32 @@ void BKE_armature_free(bArmature *arm) } } -void BKE_armature_make_local(bArmature *arm) +void BKE_armature_make_local(Main *bmain, bArmature *arm) { - Main *bmain = G.main; bool is_local = false, is_lib = false; - Object *ob; - if (arm->id.lib == NULL) - return; - if (arm->id.us == 1) { - id_clear_lib_data(bmain, &arm->id); + /* - only lib users: do nothing + * - only local users: set flag + * - mixed: make copy + */ + + if (!ID_IS_LINKED_DATABLOCK(arm)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == arm) { - if (ob->id.lib) - is_lib = true; - else - is_local = true; - } - } + BKE_library_ID_test_usages(bmain, arm, &is_local, &is_lib); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &arm->id); - } - else if (is_local && is_lib) { - bArmature *arm_new = BKE_armature_copy(arm); - arm_new->id.us = 0; + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &arm->id); + BKE_id_expand_local(&arm->id); + } + else { + bArmature *arm_new = BKE_armature_copy(bmain, arm); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, arm->id.lib, &arm_new->id); + arm_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == arm) { - if (ob->id.lib == NULL) { - ob->data = arm_new; - id_us_plus(&arm_new->id); - id_us_min(&arm->id); - } - } + BKE_libblock_remap(bmain, arm, arm_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -208,13 +196,13 @@ static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone } } -bArmature *BKE_armature_copy(bArmature *arm) +bArmature *BKE_armature_copy(Main *bmain, bArmature *arm) { bArmature *newArm; Bone *oldBone, *newBone; Bone *newActBone = NULL; - newArm = BKE_libblock_copy(&arm->id); + newArm = BKE_libblock_copy(bmain, &arm->id); BLI_duplicatelist(&newArm->bonebase, &arm->bonebase); /* Duplicate the childrens' lists */ @@ -231,8 +219,9 @@ bArmature *BKE_armature_copy(bArmature *arm) newArm->act_edbone = NULL; newArm->sketch = NULL; - if (arm->id.lib) { - BKE_id_lib_local_paths(G.main, arm->id.lib, &newArm->id); + if (ID_IS_LINKED_DATABLOCK(arm)) { + BKE_id_expand_local(&newArm->id); + BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id); } return newArm; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 826bb12a912..ece17335fa0 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) { - BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL); + BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL); DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index e338974eca6..f3ff0f253e5 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -423,7 +423,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int { const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL; - if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) { + if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) { return; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 44cacffb71f..20621feac6c 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -38,6 +38,8 @@ #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_paint.h" #include "BKE_texture.h" @@ -170,11 +172,11 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) return NULL; } -Brush *BKE_brush_copy(Brush *brush) +Brush *BKE_brush_copy(Main *bmain, Brush *brush) { Brush *brushn; - brushn = BKE_libblock_copy(&brush->id); + brushn = BKE_libblock_copy(bmain, &brush->id); if (brush->mtex.tex) id_us_plus((ID *)brush->mtex.tex); @@ -195,8 +197,9 @@ Brush *BKE_brush_copy(Brush *brush) /* enable fake user by default */ id_fake_user_set(&brush->id); - if (brush->id.lib) { - BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id); + if (ID_IS_LINKED_DATABLOCK(brush)) { + BKE_id_expand_local(&brushn->id); + BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id); } return brushn; @@ -216,63 +219,40 @@ void BKE_brush_free(Brush *brush) BKE_previewimg_free(&(brush->preview)); } -static void extern_local_brush(Brush *brush) -{ - id_lib_extern((ID *)brush->mtex.tex); - id_lib_extern((ID *)brush->mask_mtex.tex); - id_lib_extern((ID *)brush->clone.image); - id_lib_extern((ID *)brush->toggle_brush); - id_lib_extern((ID *)brush->paint_curve); -} - -void BKE_brush_make_local(Brush *brush) +void BKE_brush_make_local(Main *bmain, Brush *brush) { + bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - Main *bmain = G.main; - Scene *scene; - bool is_local = false, is_lib = false; - - if (brush->id.lib == NULL) return; + if (!ID_IS_LINKED_DATABLOCK(brush)) { + return; + } if (brush->clone.image) { - /* special case: ima always local immediately. Clone image should only - * have one user anyway. */ - id_clear_lib_data(bmain, &brush->clone.image->id); - extern_local_brush(brush); + /* Special case: ima always local immediately. Clone image should only have one user anyway. */ + id_make_local(bmain, &brush->clone.image->id, false); } - for (scene = bmain->scene.first; scene && ELEM(0, is_lib, is_local); scene = scene->id.next) { - if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) { - if (scene->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &brush->id); + BKE_id_expand_local(&brush->id); + + /* enable fake user by default */ + id_fake_user_set(&brush->id); } - } + else { + Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */ - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &brush->id); - extern_local_brush(brush); + brush_new->id.us = 0; - /* enable fake user by default */ - id_fake_user_set(&brush->id); - } - else if (is_local && is_lib) { - Brush *brush_new = BKE_brush_copy(brush); /* Ensures FAKE_USER is set */ - id_us_min(&brush_new->id); /* Remove user added by standard BKE_libblock_copy(). */ - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, brush->id.lib, &brush_new->id); - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) { - if (scene->id.lib == NULL) { - BKE_paint_brush_set(&scene->toolsettings->imapaint.paint, brush_new); - } - } + BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -469,6 +449,7 @@ void BKE_brush_curve_preset(Brush *b, int preset) curvemapping_changed(b->curve, false); } +/* XXX Unused function. */ int BKE_brush_texture_set_nr(Brush *brush, int nr) { ID *idtest, *id = NULL; @@ -477,7 +458,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr) idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1); if (idtest == NULL) { /* new tex */ - if (id) idtest = (ID *)BKE_texture_copy((Tex *)id); + if (id) idtest = (ID *)BKE_texture_copy(G.main, (Tex *)id); else idtest = (ID *)BKE_texture_add(G.main, "Tex"); id_us_min(idtest); } @@ -816,9 +797,7 @@ void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float c void BKE_brush_size_set(Scene *scene, Brush *brush, int size) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - - size = (int)((float)size / U.pixelsize); - + /* make sure range is sane */ CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index a3cfe3f80b4..264d87b86f3 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -590,6 +590,77 @@ BVHTree *bvhtree_from_mesh_verts_ex( /** \name Edge Builder * \{ */ +static BVHTree *bvhtree_from_editmesh_edges_create_tree( + float epsilon, int tree_type, int axis, + BMEditMesh *em, const int edges_num, + const BLI_bitmap *edges_mask, int edges_num_active) +{ + BVHTree *tree = NULL; + int i; + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + if (edges_mask) { + BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num)); + } + else { + edges_num_active = edges_num; + } + + tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + + if (tree) { + BMIter iter; + BMEdge *eed; + BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], eed->v1->co); + copy_v3_v3(co[1], eed->v2->co); + + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active); + BLI_bvhtree_balance(tree); + } + + return tree; +} + +/* Builds a bvh tree where nodes are the edges of the given em */ +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + int edge_num = em->bm->totedge; + + BVHTree *tree = bvhtree_from_editmesh_edges_create_tree( + epsilon, tree_type, axis, + em, edge_num, edges_mask, edges_num_active); + + if (tree) { + memset(data, 0, sizeof(*data)); + data->tree = tree; + data->em = em; + data->nearest_callback = NULL; /* TODO */ + data->raycast_callback = NULL; /* TODO */ + /* TODO: not urgent however since users currently define own callbacks */ + data->nearest_to_ray_callback = NULL; + } + + return tree; +} +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, BMEditMesh *em, + float epsilon, int tree_type, int axis) +{ + return bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); +} + /* Builds a bvh tree where nodes are the edges of the given dm */ BVHTree *bvhtree_from_mesh_edges( BVHTreeFromMesh *data, DerivedMesh *dm, diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index eabee742327..ae7aac8b54f 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -49,6 +49,8 @@ #include "BKE_object.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -91,64 +93,46 @@ void *BKE_camera_add(Main *bmain, const char *name) return cam; } -Camera *BKE_camera_copy(Camera *cam) +Camera *BKE_camera_copy(Main *bmain, Camera *cam) { Camera *camn; - camn = BKE_libblock_copy(&cam->id); + camn = BKE_libblock_copy(bmain, &cam->id); - id_lib_extern((ID *)camn->dof_ob); - - if (cam->id.lib) { - BKE_id_lib_local_paths(G.main, cam->id.lib, &camn->id); + if (ID_IS_LINKED_DATABLOCK(cam)) { + BKE_id_expand_local(&camn->id); + BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id); } return camn; } -void BKE_camera_make_local(Camera *cam) +void BKE_camera_make_local(Main *bmain, Camera *cam) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (cam->id.lib == NULL) return; - if (cam->id.us == 1) { - id_clear_lib_data(bmain, &cam->id); + + if (!ID_IS_LINKED_DATABLOCK(cam)) { return; } - - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == cam) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &cam->id); - } - else if (is_local && is_lib) { - Camera *cam_new = BKE_camera_copy(cam); - cam_new->id.us = 0; + BKE_library_ID_test_usages(bmain, cam, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &cam->id); + BKE_id_expand_local(&cam->id); + } + else { + Camera *cam_new = BKE_camera_copy(bmain, cam); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, cam->id.lib, &cam_new->id); + cam_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == cam) { - if (ob->id.lib == NULL) { - ob->data = cam_new; - id_us_plus(&cam_new->id); - id_us_min(&cam->id); - } - } + BKE_libblock_remap(bmain, cam, cam_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index c1f1f0128f5..2932939b208 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1322,7 +1322,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode, .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a, }; - ScopesUpdateDataChunk data_chunk = {0}; + ScopesUpdateDataChunk data_chunk = {{0}}; INIT_MINMAX(data_chunk.min, data_chunk.max); BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk), diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a591d536b43..4c9ddd495e3 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2195,7 +2195,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT } else if (cob->type == CONSTRAINT_OBTYPE_BONE) { Object workob; - bPose pose = {0}; + bPose pose = {{0}}; bPoseChannel *pchan, *tchan; /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set @@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use /* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */ static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData)) { - if (*idpoin && (*idpoin)->lib) + if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin)) id_lib_extern(*idpoin); } diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index dec6ff22360..0e634e21ea3 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -58,6 +58,8 @@ #include "BKE_global.h" #include "BKE_key.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_material.h" @@ -172,12 +174,13 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) return cu; } -Curve *BKE_curve_copy(Curve *cu) +Curve *BKE_curve_copy(Main *bmain, Curve *cu) { Curve *cun; int a; - cun = BKE_libblock_copy(&cu->id); + cun = BKE_libblock_copy(bmain, &cu->id); + BLI_listbase_clear(&cun->nurb); BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb)); @@ -191,45 +194,29 @@ Curve *BKE_curve_copy(Curve *cu) cun->tb = MEM_dupallocN(cu->tb); cun->bb = MEM_dupallocN(cu->bb); - cun->key = BKE_key_copy(cu->key); - if (cun->key) cun->key->from = (ID *)cun; + if (cu->key) { + cun->key = BKE_key_copy(bmain, cu->key); + cun->key->from = (ID *)cun; + } cun->editnurb = NULL; cun->editfont = NULL; -#if 0 // XXX old animation system - /* single user ipo too */ - if (cun->ipo) cun->ipo = copy_ipo(cun->ipo); -#endif // XXX old animation system - id_us_plus((ID *)cun->vfont); id_us_plus((ID *)cun->vfontb); id_us_plus((ID *)cun->vfonti); id_us_plus((ID *)cun->vfontbi); - if (cu->id.lib) { - BKE_id_lib_local_paths(G.main, cu->id.lib, &cun->id); + if (ID_IS_LINKED_DATABLOCK(cu)) { + BKE_id_expand_local(&cun->id); + BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id); } return cun; } -static void extern_local_curve(Curve *cu) -{ - id_lib_extern((ID *)cu->vfont); - id_lib_extern((ID *)cu->vfontb); - id_lib_extern((ID *)cu->vfonti); - id_lib_extern((ID *)cu->vfontbi); - - if (cu->mat) { - extern_local_matarar(cu->mat, cu->totcol); - } -} - -void BKE_curve_make_local(Curve *cu) +void BKE_curve_make_local(Main *bmain, Curve *cu) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - when there are only lib users: don't do @@ -237,40 +224,26 @@ void BKE_curve_make_local(Curve *cu) * - mixed: do a copy */ - if (cu->id.lib == NULL) - return; - - if (cu->id.us == 1) { - id_clear_lib_data(bmain, &cu->id); - extern_local_curve(cu); + if (!ID_IS_LINKED_DATABLOCK(cu)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == cu) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } + BKE_library_ID_test_usages(bmain, cu, &is_local, &is_lib); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &cu->id); - extern_local_curve(cu); - } - else if (is_local && is_lib) { - Curve *cu_new = BKE_curve_copy(cu); - cu_new->id.us = 0; + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &cu->id); + if (cu->key) { + BKE_key_make_local(bmain, cu->key); + } + BKE_id_expand_local(&cu->id); + } + else { + Curve *cu_new = BKE_curve_copy(bmain, cu); - BKE_id_lib_local_paths(bmain, cu->id.lib, &cu_new->id); + cu_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == cu) { - if (ob->id.lib == NULL) { - ob->data = cu_new; - id_us_plus(&cu_new->id); - id_us_min(&cu->id); - } - } + BKE_libblock_remap(bmain, cu, cu_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -1384,6 +1357,71 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * MEM_freeN(basisu); } +/** + * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis. + */ +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint) +{ + const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1); + const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1); + return points_len; +} + +/** + * Calculate an array for the entire curve (cyclic or non-cyclic). + * \note Call for each axis. + * + * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array. + */ +void BKE_curve_calc_coords_axis( + const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points) +{ + const unsigned int points_len = BKE_curve_calc_coords_axis_len( + bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint); + float *r_points_offset = r_points; + + const unsigned int resolu_stride = resolu * stride; + const unsigned int bezt_array_last = bezt_array_len - 1; + + for (unsigned int i = 0; i < bezt_array_last; i++) { + const BezTriple *bezt_curr = &bezt_array[i]; + const BezTriple *bezt_next = &bezt_array[i + 1]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + } + + if (is_cyclic) { + const BezTriple *bezt_curr = &bezt_array[bezt_array_last]; + const BezTriple *bezt_next = &bezt_array[0]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + if (use_cyclic_duplicate_endpoint) { + *r_points_offset = *r_points; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + } + else { + float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride); + *r_points_last = bezt_array[bezt_array_last].vec[1][axis]; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + + BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset); + UNUSED_VARS_NDEBUG(points_len); +} + /* forward differencing method for bezier curve */ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) { diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index d02041d6da8..82ea710b5b6 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2205,7 +2205,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in /* tri index */ /* There is a low possibility of actually having a neighbor point which tri is * already set from another neighbor in a separate thread here. - * Cheking for both tri_index and neighbour_pixel above reduces that probability + * Checking for both tri_index and neighbour_pixel above reduces that probability * but it remains possible. * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour). @@ -3785,7 +3785,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, const float brush_radius = brush->paint_distance * surface->radius_scale; int numOfVerts; int ii; - Bounds3D mesh_bb = {0}; + Bounds3D mesh_bb = {{0}}; VolumeGrid *grid = bData->grid; dm = CDDM_copy(brush->dm); @@ -4475,7 +4475,7 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index) /* Sort of spinlock, but only for given ePoint. * Since the odds a same ePoint is modified at the same time by several threads is very low, this is - * much more eficient than a global spin lock. */ + * much more efficient than a global spin lock. */ const unsigned int pointlock_idx = n_trgt / 8; const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index af1bcd0c545..ac4f566dc62 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -49,6 +49,7 @@ #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" +#include "BKE_main.h" /* ************************************************** */ @@ -358,7 +359,7 @@ bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src) } /* make a copy of a given gpencil datablock */ -bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy) +bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy) { bGPDlayer *gpl, *gpld; bGPdata *dst; @@ -374,7 +375,7 @@ bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy) } else { /* make a copy when others use this */ - dst = BKE_libblock_copy(&src->id); + dst = BKE_libblock_copy(bmain, &src->id); } /* copy layers */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 95c7730431a..5a51d4797bb 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -86,18 +86,19 @@ Group *BKE_group_add(Main *bmain, const char *name) return group; } -Group *BKE_group_copy(Group *group) +Group *BKE_group_copy(Main *bmain, Group *group) { Group *groupn; - groupn = BKE_libblock_copy(&group->id); + groupn = BKE_libblock_copy(bmain, &group->id); BLI_duplicatelist(&groupn->gobject, &group->gobject); /* Do not copy group's preview (same behavior as for objects). */ groupn->preview = NULL; - if (group->id.lib) { - BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id); + if (ID_IS_LINKED_DATABLOCK(group)) { + BKE_id_expand_local(&groupn->id); + BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id); } return groupn; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 69384a70969..f6f38977402 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -72,6 +72,8 @@ #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -457,25 +459,18 @@ Image *BKE_image_copy(Main *bmain, Image *ima) nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format); BLI_duplicatelist(&nima->views, &ima->views); - if (ima->id.lib) { + nima->preview = BKE_previewimg_copy(ima->preview); + + if (ID_IS_LINKED_DATABLOCK(ima)) { + BKE_id_expand_local(&nima->id); BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id); } return nima; } -static void extern_local_image(Image *UNUSED(ima)) -{ - /* Nothing to do: images don't link to other IDs. This function exists to - * match id_make_local pattern. */ -} - -void BKE_image_make_local(struct Image *ima) +void BKE_image_make_local(Main *bmain, Image *ima) { - Main *bmain = G.main; - Tex *tex; - Brush *brush; - Mesh *me; bool is_local = false, is_lib = false; /* - only lib users: do nothing @@ -483,147 +478,23 @@ void BKE_image_make_local(struct Image *ima) * - mixed: make copy */ - if (ima->id.lib == NULL) return; - - /* Can't take short cut here: must check meshes at least because of bogus - * texface ID refs. - z0r */ -#if 0 - if (ima->id.us == 1) { - id_clear_lib_data(bmain, &ima->id); - extern_local_image(ima); + if (!ID_IS_LINKED_DATABLOCK(ima)) { return; } -#endif - - for (tex = bmain->tex.first; tex; tex = tex->id.next) { - if (tex->ima == ima) { - if (tex->id.lib) is_lib = true; - else is_local = true; - } - } - for (brush = bmain->brush.first; brush; brush = brush->id.next) { - if (brush->clone.image == ima) { - if (brush->id.lib) is_lib = true; - else is_local = true; - } - } - for (me = bmain->mesh.first; me; me = me->id.next) { - if (me->mtface) { - MTFace *tface; - int a, i; - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; + BKE_library_ID_test_usages(bmain, ima, &is_local, &is_lib); - for (a = 0; a < me->totface; a++, tface++) { - if (tface->tpage == ima) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - } - } - - if (me->mtpoly) { - MTexPoly *mtpoly; - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - mtpoly = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, mtpoly++) { - if (mtpoly->tpage == ima) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - } + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &ima->id); + BKE_id_expand_local(&ima->id); } + else { + Image *ima_new = BKE_image_copy(bmain, ima); - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &ima->id); - extern_local_image(ima); - } - else if (is_local && is_lib) { - Image *ima_new = BKE_image_copy(bmain, ima); - - ima_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ima->id.lib, &ima_new->id); - - tex = bmain->tex.first; - while (tex) { - if (tex->id.lib == NULL) { - if (tex->ima == ima) { - tex->ima = ima_new; - id_us_plus(&ima_new->id); - id_us_min(&ima->id); - } - } - tex = tex->id.next; - } - brush = bmain->brush.first; - while (brush) { - if (brush->id.lib == NULL) { - if (brush->clone.image == ima) { - brush->clone.image = ima_new; - id_us_plus(&ima_new->id); - id_us_min(&ima->id); - } - } - brush = brush->id.next; - } - /* Transfer references in texfaces. Texfaces don't add to image ID - * user count *unless* there are no other users. See - * readfile.c:lib_link_mtface. */ - me = bmain->mesh.first; - while (me) { - if (me->mtface) { - MTFace *tface; - int a, i; - - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) { - if (tface->tpage == ima) { - tface->tpage = ima_new; - id_us_ensure_real((ID *)ima_new); - id_lib_extern((ID *)ima_new); - } - } - } - } - } - - if (me->mtpoly) { - MTexPoly *mtpoly; - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - mtpoly = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, mtpoly++) { - if (mtpoly->tpage == ima) { - mtpoly->tpage = ima_new; - id_us_ensure_real((ID *)ima_new); - id_lib_extern((ID *)ima_new); - } - } - } - } - } + ima_new->id.us = 0; - me = me->id.next; + BKE_libblock_remap(bmain, ima, ima_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 2517e2cc197..e59facd3c39 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -58,6 +58,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_scene.h" @@ -149,14 +150,12 @@ Key *BKE_key_add(ID *id) /* common function */ return key; } -Key *BKE_key_copy(Key *key) +Key *BKE_key_copy(Main *bmain, Key *key) { Key *keyn; KeyBlock *kbn, *kb; - if (key == NULL) return NULL; - - keyn = BKE_libblock_copy(&key->id); + keyn = BKE_libblock_copy(bmain, &key->id); BLI_duplicatelist(&keyn->block, &key->block); @@ -171,22 +170,19 @@ Key *BKE_key_copy(Key *key) kb = kb->next; } - if (key->id.lib) { - BKE_id_lib_local_paths(G.main, key->id.lib, &keyn->id); + if (ID_IS_LINKED_DATABLOCK(key)) { + BKE_id_expand_local(&keyn->id); + BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id); } return keyn; } - Key *BKE_key_copy_nolib(Key *key) { Key *keyn; KeyBlock *kbn, *kb; - if (key == NULL) - return NULL; - keyn = MEM_dupallocN(key); keyn->adt = NULL; @@ -207,17 +203,16 @@ Key *BKE_key_copy_nolib(Key *key) return keyn; } -void BKE_key_make_local(Key *key) +void BKE_key_make_local(Main *bmain, Key *key) { + /* Note that here for now we simply just make it local... + * Sounds fishy behavior, but since skeys are not *real* IDs... */ - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - if (key == NULL) return; - - key->id.lib = NULL; - new_id(NULL, &key->id, NULL); + if (!ID_IS_LINKED_DATABLOCK(key)) { + return; + } + + id_clear_lib_data(bmain, &key->id); } /* Sort shape keys and Ipo curves after a change. This assumes that at most diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 692b703f721..003b154a70b 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -50,6 +50,8 @@ #include "BKE_global.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" @@ -114,12 +116,12 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) return la; } -Lamp *BKE_lamp_copy(Lamp *la) +Lamp *BKE_lamp_copy(Main *bmain, Lamp *la) { Lamp *lan; int a; - lan = BKE_libblock_copy(&la->id); + lan = BKE_libblock_copy(bmain, &la->id); for (a = 0; a < MAX_MTEX; a++) { if (lan->mtex[a]) { @@ -132,13 +134,13 @@ Lamp *BKE_lamp_copy(Lamp *la) lan->curfalloff = curvemapping_copy(la->curfalloff); if (la->nodetree) - lan->nodetree = ntreeCopyTree(la->nodetree); + lan->nodetree = ntreeCopyTree(bmain, la->nodetree); - if (la->preview) - lan->preview = BKE_previewimg_copy(la->preview); - - if (la->id.lib) { - BKE_id_lib_local_paths(G.main, la->id.lib, &lan->id); + lan->preview = BKE_previewimg_copy(la->preview); + + if (ID_IS_LINKED_DATABLOCK(la)) { + BKE_id_expand_local(&lan->id); + BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id); } return lan; @@ -166,14 +168,12 @@ Lamp *localize_lamp(Lamp *la) lan->nodetree = ntreeLocalize(la->nodetree); lan->preview = NULL; - + return lan; } -void BKE_lamp_make_local(Lamp *la) +void BKE_lamp_make_local(Main *bmain, Lamp *la) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing @@ -181,42 +181,23 @@ void BKE_lamp_make_local(Lamp *la) * - mixed: make copy */ - if (la->id.lib == NULL) return; - if (la->id.us == 1) { - id_clear_lib_data(bmain, &la->id); + if (!ID_IS_LINKED_DATABLOCK(la)) { return; } - - ob = bmain->object.first; - while (ob) { - if (ob->data == la) { - if (ob->id.lib) is_lib = true; - else is_local = true; + + BKE_library_ID_test_usages(bmain, la, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &la->id); + BKE_id_expand_local(&la->id); } - ob = ob->id.next; - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &la->id); - } - else if (is_local && is_lib) { - Lamp *la_new = BKE_lamp_copy(la); - la_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, la->id.lib, &la_new->id); - - ob = bmain->object.first; - while (ob) { - if (ob->data == la) { - - if (ob->id.lib == NULL) { - ob->data = la_new; - id_us_plus(&la_new->id); - id_us_min(&la->id); - } - } - ob = ob->id.next; + else { + Lamp *la_new = BKE_lamp_copy(bmain, la); + + la_new->id.us = 0; + + BKE_libblock_remap(bmain, la, la_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index 58c0a567116..67f49266efc 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -59,6 +59,8 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -275,15 +277,17 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) return lt; } -Lattice *BKE_lattice_copy(Lattice *lt) +Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt) { Lattice *ltn; - ltn = BKE_libblock_copy(<->id); + ltn = BKE_libblock_copy(bmain, <->id); ltn->def = MEM_dupallocN(lt->def); - ltn->key = BKE_key_copy(ltn->key); - if (ltn->key) ltn->key->from = (ID *)ltn; + if (lt->key) { + ltn->key = BKE_key_copy(bmain, ltn->key); + ltn->key->from = (ID *)ltn; + } if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; @@ -293,8 +297,9 @@ Lattice *BKE_lattice_copy(Lattice *lt) ltn->editlatt = NULL; - if (lt->id.lib) { - BKE_id_lib_local_paths(G.main, lt->id.lib, <n->id); + if (ID_IS_LINKED_DATABLOCK(lt)) { + BKE_id_expand_local(<n->id); + BKE_id_lib_local_paths(bmain, lt->id.lib, <n->id); } return ltn; @@ -325,48 +330,35 @@ void BKE_lattice_free(Lattice *lt) } -void BKE_lattice_make_local(Lattice *lt) +void BKE_lattice_make_local(Main *bmain, Lattice *lt) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (lt->id.lib == NULL) return; - if (lt->id.us == 1) { - id_clear_lib_data(bmain, <->id); + + if (!ID_IS_LINKED_DATABLOCK(lt)) { return; } - - for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) { - if (ob->data == lt) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, <->id); - } - else if (is_local && is_lib) { - Lattice *lt_new = BKE_lattice_copy(lt); - lt_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, lt->id.lib, <_new->id); - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == lt) { - if (ob->id.lib == NULL) { - ob->data = lt_new; - id_us_plus(<_new->id); - id_us_min(<->id); - } + + BKE_library_ID_test_usages(bmain, lt, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, <->id); + if (lt->key) { + BKE_key_make_local(bmain, lt->key); } + BKE_id_expand_local(<->id); + } + else { + Lattice *lt_new = BKE_lattice_copy(bmain, lt); + + lt_new->id.us = 0; + + BKE_libblock_remap(bmain, lt, lt_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5f7bded4262..978f1acefba 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -141,7 +141,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) void id_lib_extern(ID *id) { - if (id) { + if (id && ID_IS_LINKED_DATABLOCK(id)) { BLI_assert(BKE_idcode_is_linkable(GS(id->name))); if (id->tag & LIB_TAG_INDIRECT) { id->tag -= LIB_TAG_INDIRECT; @@ -250,9 +250,27 @@ void id_fake_user_clear(ID *id) } } +static int id_expand_local_callback( + void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag)) +{ + if (*id_pointer) { + id_lib_extern(*id_pointer); + } + + return IDWALK_RET_NOP; +} + +/** + * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions. + */ +void BKE_id_expand_local(ID *id) +{ + BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0); +} + /* calls the appropriate make_local method for the block, unless test. Returns true * if the block can be made local. */ -bool id_make_local(ID *id, bool test) +bool id_make_local(Main *bmain, ID *id, bool test) { if (id->tag & LIB_TAG_INDIRECT) return false; @@ -263,54 +281,45 @@ bool id_make_local(ID *id, bool test) case ID_LI: return false; /* can't be linked */ case ID_OB: - if (!test) BKE_object_make_local((Object *)id); + if (!test) BKE_object_make_local(bmain, (Object *)id); return true; case ID_ME: - if (!test) { - BKE_mesh_make_local((Mesh *)id); - BKE_key_make_local(((Mesh *)id)->key); - } + if (!test) BKE_mesh_make_local(bmain, (Mesh *)id); return true; case ID_CU: - if (!test) { - BKE_curve_make_local((Curve *)id); - BKE_key_make_local(((Curve *)id)->key); - } + if (!test) BKE_curve_make_local(bmain, (Curve *)id); return true; case ID_MB: - if (!test) BKE_mball_make_local((MetaBall *)id); + if (!test) BKE_mball_make_local(bmain, (MetaBall *)id); return true; case ID_MA: - if (!test) BKE_material_make_local((Material *)id); + if (!test) BKE_material_make_local(bmain, (Material *)id); return true; case ID_TE: - if (!test) BKE_texture_make_local((Tex *)id); + if (!test) BKE_texture_make_local(bmain, (Tex *)id); return true; case ID_IM: - if (!test) BKE_image_make_local((Image *)id); + if (!test) BKE_image_make_local(bmain, (Image *)id); return true; case ID_LT: - if (!test) { - BKE_lattice_make_local((Lattice *)id); - BKE_key_make_local(((Lattice *)id)->key); - } + if (!test) BKE_lattice_make_local(bmain, (Lattice *)id); return true; case ID_LA: - if (!test) BKE_lamp_make_local((Lamp *)id); + if (!test) BKE_lamp_make_local(bmain, (Lamp *)id); return true; case ID_CA: - if (!test) BKE_camera_make_local((Camera *)id); + if (!test) BKE_camera_make_local(bmain, (Camera *)id); return true; case ID_SPK: - if (!test) BKE_speaker_make_local((Speaker *)id); + if (!test) BKE_speaker_make_local(bmain, (Speaker *)id); return true; case ID_IP: return false; /* deprecated */ case ID_KE: - if (!test) BKE_key_make_local((Key *)id); + if (!test) BKE_key_make_local(bmain, (Key *)id); return true; case ID_WO: - if (!test) BKE_world_make_local((World *)id); + if (!test) BKE_world_make_local(bmain, (World *)id); return true; case ID_SCR: return false; /* can't be linked */ @@ -323,16 +332,16 @@ bool id_make_local(ID *id, bool test) case ID_GR: return false; /* not implemented */ case ID_AR: - if (!test) BKE_armature_make_local((bArmature *)id); + if (!test) BKE_armature_make_local(bmain, (bArmature *)id); return true; case ID_AC: - if (!test) BKE_action_make_local((bAction *)id); + if (!test) BKE_action_make_local(bmain, (bAction *)id); return true; case ID_NT: - if (!test) ntreeMakeLocal((bNodeTree *)id, true); + if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true); return true; case ID_BR: - if (!test) BKE_brush_make_local((Brush *)id); + if (!test) BKE_brush_make_local(bmain, (Brush *)id); return true; case ID_WM: return false; /* can't be linked */ @@ -349,9 +358,11 @@ bool id_make_local(ID *id, bool test) * Invokes the appropriate copy method for the block and returns the result in * newid, unless test. Returns true if the block can be copied. */ -bool id_copy(ID *id, ID **newid, bool test) +bool id_copy(Main *bmain, ID *id, ID **newid, bool test) { - if (!test) *newid = NULL; + if (!test) { + *newid = NULL; + } /* conventions: * - make shallow copy, only this ID block @@ -362,80 +373,80 @@ bool id_copy(ID *id, ID **newid, bool test) case ID_LI: return false; /* can't be copied from here */ case ID_OB: - if (!test) *newid = (ID *)BKE_object_copy((Object *)id); + if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id); return true; case ID_ME: - if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id); + if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id); return true; case ID_CU: - if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id); + if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id); return true; case ID_MB: - if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id); + if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id); return true; case ID_MA: - if (!test) *newid = (ID *)BKE_material_copy((Material *)id); + if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id); return true; case ID_TE: - if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id); + if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id); return true; case ID_IM: - if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id); + if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id); return true; case ID_LT: - if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id); + if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id); return true; case ID_LA: - if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id); + if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id); return true; case ID_SPK: - if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id); + if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id); return true; case ID_CA: - if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id); + if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); return true; case ID_IP: return false; /* deprecated */ case ID_KE: - if (!test) *newid = (ID *)BKE_key_copy((Key *)id); + if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id); return true; case ID_WO: - if (!test) *newid = (ID *)BKE_world_copy((World *)id); + if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id); return true; case ID_SCR: return false; /* can't be copied from here */ case ID_VF: return false; /* not implemented */ case ID_TXT: - if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id); + if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id); return true; case ID_SO: return false; /* not implemented */ case ID_GR: - if (!test) *newid = (ID *)BKE_group_copy((Group *)id); + if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id); return true; case ID_AR: - if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id); + if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id); return true; case ID_AC: - if (!test) *newid = (ID *)BKE_action_copy((bAction *)id); + if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id); return true; case ID_NT: - if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id); + if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id); return true; case ID_BR: - if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id); + if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id); return true; case ID_WM: return false; /* can't be copied from here */ case ID_GD: - if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false); + if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false); return true; case ID_MSK: - if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id); + if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id); return true; case ID_LS: - if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id); + if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id); return true; } @@ -450,7 +461,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) if (id) { /* if property isn't editable, we're going to have an extra block hanging around until we save */ if (RNA_property_editable(ptr, prop)) { - if (id_copy(id, &newid, false) && newid) { + if (id_copy(CTX_data_main(C), id, &newid, false) && newid) { /* copy animation actions too */ BKE_animdata_copy_id_action(id); /* us is 1 by convention, but RNA_property_pointer_set @@ -621,7 +632,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) /* flag for full recalc */ for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } @@ -969,7 +980,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action) } /* used everywhere in blenkernel */ -void *BKE_libblock_copy_ex(Main *bmain, ID *id) +void *BKE_libblock_copy(Main *bmain, ID *id) { ID *idn; size_t idn_len; @@ -1021,11 +1032,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action) return idn; } -void *BKE_libblock_copy(ID *id) -{ - return BKE_libblock_copy_ex(G.main, id); -} - static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag) { ID *id = *id_pointer; @@ -1045,7 +1051,7 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i void BKE_libblock_relink(ID *id) { - if (id->lib) + if (ID_IS_LINKED_DATABLOCK(id)) return; BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); @@ -1259,7 +1265,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name) for (idtest = lb->first; idtest; idtest = idtest->next) { /* if idtest is not a lib */ - if (id != idtest && idtest->lib == NULL) { + if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { /* do not test alphabetic! */ /* optimized */ if (idtest->name[2] == name[0]) { @@ -1319,7 +1325,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name) for (idtest = lb->first; idtest; idtest = idtest->next) { int nrtest; if ( (id != idtest) && - (idtest->lib == NULL) && + !ID_IS_LINKED_DATABLOCK(idtest) && (*name == *(idtest->name + 2)) && STREQLEN(name, idtest->name + 2, left_len) && (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len) @@ -1401,7 +1407,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname) char name[MAX_ID_NAME - 2]; /* if library, don't rename */ - if (id->lib) + if (ID_IS_LINKED_DATABLOCK(id)) return false; /* if no libdata given, look up based on ID */ @@ -1465,7 +1471,7 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist) ntree = ntreeFromID(id); if (ntree) { - ntreeMakeLocal(ntree, false); + ntreeMakeLocal(bmain, ntree, false); } if (GS(id->name) == ID_OB) { @@ -1506,7 +1512,7 @@ static void lib_indirect_test_id(ID *id, const Library *lib) #define LIBTAG(a) \ if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0 - if (id->lib) { + if (ID_IS_LINKED_DATABLOCK(id)) { /* datablocks that were indirectly related are now direct links * without this, appending data that has a link to other data will fail to write */ if (lib && id->lib->parent == lib) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 7cb5bfd1360..b623cecb0ff 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -45,6 +45,7 @@ #include "DNA_linestyle_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" @@ -71,6 +72,7 @@ #include "BKE_fcurve.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_rigidbody.h" #include "BKE_sca.h" @@ -85,7 +87,7 @@ if (!((_data)->status & IDWALK_STOP)) { \ const int _flag = (_data)->flag; \ ID *old_id = *(id_pp); \ - const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \ + const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \ if (_flag & IDWALK_READONLY) { \ BLI_assert(*(id_pp) == old_id); \ } \ @@ -126,6 +128,7 @@ enum { typedef struct LibraryForeachIDData { ID *self_id; int flag; + int cd_flag; LibraryIDLinkCallback callback; void *user_data; int status; @@ -285,6 +288,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u do { data.self_id = id; + data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0; AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -400,7 +404,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { Object *object = (Object *) id; + /* Object is special, proxies make things hard... */ + const int data_cd_flag = data.cd_flag; + const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0; + /* object data special case */ + data.cd_flag |= proxy_cd_flag; if (object->type == OB_EMPTY) { /* empty can have NULL or Image */ CALLBACK_INVOKE_ID(object->data, IDWALK_USER); @@ -411,6 +420,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL); } } + data.cd_flag = data_cd_flag; CALLBACK_INVOKE(object->parent, IDWALK_NOP); CALLBACK_INVOKE(object->track, IDWALK_NOP); @@ -419,9 +429,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP); CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP); CALLBACK_INVOKE(object->poselib, IDWALK_USER); + + data.cd_flag |= proxy_cd_flag; for (i = 0; i < object->totcol; i++) { CALLBACK_INVOKE(object->mat[i], IDWALK_USER); } + data.cd_flag = data_cd_flag; + CALLBACK_INVOKE(object->gpd, IDWALK_USER); CALLBACK_INVOKE(object->dup_group, IDWALK_USER); @@ -433,10 +447,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u if (object->pose) { bPoseChannel *pchan; + + data.cd_flag |= proxy_cd_flag; for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { CALLBACK_INVOKE(pchan->custom, IDWALK_USER); BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data); } + data.cd_flag = data_cd_flag; } if (object->rigidbody_constraint) { @@ -468,6 +485,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u for (i = 0; i < mesh->totcol; i++) { CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER); } + + /* XXX Really not happy with this - probably texface should rather use some kind of + * 'texture slots' and just set indices in each poly/face item - would also save some memory. + * Maybe a nice TODO for blender2.8? */ + if (mesh->mtface || mesh->mtpoly) { + for (i = 0; i < mesh->pdata.totlayer; i++) { + if (mesh->pdata.layers[i].type == CD_MTEXPOLY) { + MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; + + for (int j = 0; j < mesh->totpoly; j++, txface++) { + CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE); + } + } + } + + for (i = 0; i < mesh->fdata.totlayer; i++) { + if (mesh->fdata.layers[i].type == CD_MTFACE) { + MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; + + for (int j = 0; j < mesh->totface; j++, tface++) { + CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE); + } + } + } + } break; } @@ -743,6 +785,80 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag) } } +/** + * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used. + */ +/* This is a 'simplified' abstract version of BKE_library_foreach_ID_link() above, quite useful to reduce + * useless ietrations in some cases. */ +bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used) +{ + if (id_type_used == ID_AC) { + return id_type_can_have_animdata(id_type_owner); + } + + switch (id_type_owner) { + case ID_LI: + return ELEM(id_type_used, ID_LI); + case ID_SCE: + return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT, + ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) || + BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_OB: + /* Could be the following, but simpler to just always say 'yes' here. */ +#if 0 + return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */ + ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC + /* + constraints, modifiers and game logic ID types... */); +#else + return true; +#endif + case ID_ME: + return ELEM(id_type_used, ID_ME, ID_KE, ID_MA); + case ID_CU: + return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF); + case ID_MB: + return ELEM(id_type_used, ID_MA); + case ID_MA: + return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_TE: + return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_LT: + return ELEM(id_type_used, ID_KE); + case ID_LA: + return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_CA: + return ELEM(id_type_used, ID_OB); + case ID_KE: + return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); /* Warning! key->from, could be more types in future? */ + case ID_SCR: + return ELEM(id_type_used, ID_SCE); + case ID_WO: + return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_SPK: + return ELEM(id_type_used, ID_SO); + case ID_GR: + return ELEM(id_type_used, ID_OB); + case ID_NT: + /* Could be the following, but node.id has no type restriction... */ +#if 0 + return ELEM(id_type_used, ID_GD /* + node.id types... */); +#else + return true; +#endif + case ID_BR: + return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE); + case ID_MC: + return ELEM(id_type_used, ID_GD, ID_IM); + case ID_MSK: + return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */ + case ID_LS: + return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + default: + return false; + } +} + + /* ***** ID users iterator. ***** */ typedef struct IDUsersIter { ID *id; @@ -751,7 +867,7 @@ typedef struct IDUsersIter { int lb_idx; ID *curr_id; - int count; /* Set by callback. */ + int count_direct, count_indirect; /* Set by callback. */ } IDUsersIter; static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag) @@ -760,13 +876,17 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_i if (*id_p && (*id_p == iter->id)) { #if 0 - printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d)\n", + printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n", iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0, - (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0); -#else - UNUSED_VARS(cb_flag); + (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0, + (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0); #endif - iter->count++; + if (cb_flag & IDWALK_INDIRECT_USAGE) { + iter->count_indirect++; + } + else { + iter->count_direct++; + } } return IDWALK_RET_NOP; @@ -789,9 +909,86 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used) /* We do not care about iter.lb_array/lb_idx here... */ iter.id = id_used; iter.curr_id = id_user; - iter.count = 0; + iter.count_direct = iter.count_indirect = 0; BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP); - return iter.count; + return iter.count_direct + iter.count_indirect; +} + +static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked) +{ + IDUsersIter iter; + ListBase *lb_array[MAX_LIBARRAY]; + ID *id = idv; + int i = set_listbasepointers(bmain, lb_array); + bool is_defined = false; + + iter.id = id; + iter.count_direct = iter.count_indirect = 0; + while (i-- && !is_defined) { + ID *id_curr = lb_array[i]->first; + + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + continue; + } + + for (; id_curr && !is_defined; id_curr = id_curr->next) { + iter.curr_id = id_curr; + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + + is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0); + } + } + + return is_defined; +} + +/** + * Check whether given ID is used locally (i.e. by another non-linked ID). + */ +bool BKE_library_ID_is_locally_used(Main *bmain, void *idv) +{ + return library_ID_is_used(bmain, idv, false); +} + +/** + * Check whether given ID is used indirectly (i.e. by another linked ID). + */ +bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv) +{ + return library_ID_is_used(bmain, idv, true); +} + +/** + * Combine \a BKE_library_ID_is_locally_used() and \a BKE_library_ID_is_indirectly_used() in a single call. + */ +void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked) +{ + IDUsersIter iter; + ListBase *lb_array[MAX_LIBARRAY]; + ID *id = idv; + int i = set_listbasepointers(bmain, lb_array); + bool is_defined = false; + + iter.id = id; + iter.count_direct = iter.count_indirect = 0; + while (i-- && !is_defined) { + ID *id_curr = lb_array[i]->first; + + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + continue; + } + + for (; id_curr && !is_defined; id_curr = id_curr->next) { + iter.curr_id = id_curr; + BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + + is_defined = (iter.count_direct != 0 && iter.count_indirect != 0); + } + } + + *is_used_local = (iter.count_direct != 0); + *is_used_linked = (iter.count_indirect != 0); } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index e9598bee0df..62a6541529a 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -88,9 +88,11 @@ #include "BKE_mesh.h" #include "BKE_material.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_mball.h" +#include "BKE_modifier.h" #include "BKE_movieclip.h" -#include "BKE_mask.h" +#include "BKE_multires.h" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -162,18 +164,22 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), } if (*id_p && (*id_p == old_id)) { - const bool is_indirect = (id->lib != NULL); + const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0; const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, * on the other hand since they get reset to lib data on file open/reload it is indirect too... * Edit Mode is also a 'skip direct' case. */ const bool is_obj = (GS(id->name) == ID_OB); - const bool is_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; +#ifdef DEBUG_PRINT + printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n", + id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect); +#endif + if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) { id->tag |= LIB_TAG_DOIT; } @@ -181,13 +187,16 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ if ((is_never_null && skip_never_null) || (is_obj_editmode && (((Object *)id)->data == *id_p)) || - (skip_indirect && (is_proxy || is_indirect))) + (skip_indirect && is_indirect)) { - if (!is_indirect && (is_never_null || is_proxy || is_obj_editmode)) { + if (is_indirect) { + id_remap_data->skipped_indirect++; + } + else if (is_never_null || is_obj_editmode) { id_remap_data->skipped_direct++; } else { - id_remap_data->skipped_indirect++; + BLI_assert(0); } if (cb_flag & IDWALK_USER) { id_remap_data->skipped_refcounted++; @@ -221,6 +230,145 @@ static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), return IDWALK_RET_NOP; } +/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ +static void libblock_remap_data_preprocess_scene_base_unlink( + IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) +{ + if (skip_indirect && is_indirect) { + r_id_remap_data->skipped_indirect++; + r_id_remap_data->skipped_refcounted++; + } + else { + id_us_min((ID *)base->object); + BKE_scene_base_unlink(sce, base); + MEM_freeN(base); + if (!is_indirect) { + r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } +} + +static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) +{ + switch (GS(r_id_remap_data->id->name)) { + case ID_SCE: + { + Scene *sce = (Scene *)r_id_remap_data->id; + + if (!r_id_remap_data->new_id) { + const bool is_indirect = (sce->id.lib != NULL); + const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; + + /* In case we are unlinking... */ + if (!r_id_remap_data->old_id) { + /* ... everything from scene. */ + Base *base, *base_next; + for (base = sce->base.first; base; base = base_next) { + base_next = base->next; + libblock_remap_data_preprocess_scene_base_unlink( + r_id_remap_data, sce, base, skip_indirect, is_indirect); + } + } + else if (GS(r_id_remap_data->old_id->name) == ID_OB) { + /* ... a specific object from scene. */ + Object *old_ob = (Object *)r_id_remap_data->old_id; + Base *base = BKE_scene_base_find(sce, old_ob); + + if (base) { + libblock_remap_data_preprocess_scene_base_unlink( + r_id_remap_data, sce, base, skip_indirect, is_indirect); + } + } + } + break; + } + case ID_OB: + { + ID *old_id = r_id_remap_data->old_id; + if (!old_id || GS(old_id->name) == ID_AR) { + Object *ob = (Object *)r_id_remap_data->id; + /* Object's pose holds reference to armature bones... sic */ + /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states. + * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid + * another complex and risky condition nightmare like the one we have in + * foreach_libblock_remap_callback()... */ + if (ob->pose && (!old_id || ob->data == old_id)) { + BLI_assert(ob->type == OB_ARMATURE); + ob->pose->flag |= POSE_RECALC; + } + } + break; + } + default: + break; + } +} + +static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob) +{ + if (old_ob->flag & OB_FROMGROUP) { + /* Note that for Scene's BaseObject->flag, either we: + * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. + * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. + * So in any case, no need to update them here. */ + if (BKE_group_object_find(NULL, old_ob) == NULL) { + old_ob->flag &= ~OB_FROMGROUP; + } + if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ + for (Group *group = bmain->group.first; group; group = group->id.next) { + BKE_group_object_unlink(group, NULL, NULL, NULL); + } + } + else { + new_ob->flag |= OB_FROMGROUP; + } + } +} + +static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id) +{ + /* Note that here we assume no object has no base (i.e. all objects are assumed instanced + * in one scene...). */ + for (Base *base = sce->base.first; base; base = base->next) { + if (base->flag & OB_FROMGROUP) { + Object *ob = base->object; + + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id || grp->id.us == 0)) { + grp = BKE_group_object_find(grp, ob); + } + if (!grp) { + ob->flag &= ~OB_FROMGROUP; + } + } + if (!(ob->flag & OB_FROMGROUP)) { + base->flag &= ~OB_FROMGROUP; + } + } + } +} + +static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id) +{ + if (ob->data == new_id) { + switch (GS(new_id->name)) { + case ID_ME: + multires_force_update(ob); + break; + case ID_CU: + BKE_curve_type_test(ob); + break; + default: + break; + } + test_object_modifiers(ob); + test_object_materials(ob, new_id); + } +} + /** * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). * @@ -263,6 +411,7 @@ static void libblock_remap_data( printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); #endif r_id_remap_data->id = id; + libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); } else { @@ -274,11 +423,16 @@ static void libblock_remap_data( while (i--) { ID *id_curr = lb_array[i]->first; + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) { + continue; + } + for (; id_curr; id_curr = id_curr->next) { /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for * the user count handling... * XXX No more true (except for debug usage of those skipping counters). */ r_id_remap_data->id = id_curr; + libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link( id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); } @@ -323,29 +477,6 @@ void BKE_libblock_remap_locked( BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); BLI_assert(old_id != new_id); - /* Some pre-process updates. - * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? - */ - if (GS(old_id->name) == ID_OB) { - Object *old_ob = (Object *)old_id; - Object *new_ob = (Object *)new_id; - - if (new_ob == NULL) { - Scene *sce; - Base *base; - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - base = BKE_scene_base_find(sce, old_ob); - - if (base) { - id_us_min((ID *)base->object); - BKE_scene_base_unlink(sce, base); - MEM_freeN(base); - } - } - } - } - libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); if (free_notifier_reference_cb) { @@ -385,55 +516,21 @@ void BKE_libblock_remap_locked( */ switch (GS(old_id->name)) { case ID_OB: - { - Object *old_ob = (Object *)old_id; - Object *new_ob = (Object *)new_id; - - if (old_ob->flag & OB_FROMGROUP) { - /* Note that for Scene's BaseObject->flag, either we: - * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. - * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. - * So in any case, no need to update them here. */ - if (BKE_group_object_find(NULL, old_ob) == NULL) { - old_ob->flag &= ~OB_FROMGROUP; - } - if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ - Group *group; - for (group = bmain->group.first; group; group = group->id.next) { - BKE_group_object_unlink(group, NULL, NULL, NULL); - } - } - else { - new_ob->flag |= OB_FROMGROUP; - } - } + libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id); break; - } case ID_GR: - if (new_id == NULL) { /* Only affects us in case group was unlinked. */ + if (!new_id) { /* Only affects us in case group was unlinked. */ for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { - /* Note that here we assume no object has no base (i.e. all objects are assumed instanced - * in one scene...). */ - for (Base *base = sce->base.first; base; base = base->next) { - if (base->flag & OB_FROMGROUP) { - Object *ob = base->object; - - if (ob->flag & OB_FROMGROUP) { - Group *grp = BKE_group_object_find(NULL, ob); - - /* Unlinked group (old_id) is still in bmain... */ - if (grp && (&grp->id == old_id)) { - grp = BKE_group_object_find(grp, ob); - } - if (!grp) { - ob->flag &= ~OB_FROMGROUP; - } - } - if (!(ob->flag & OB_FROMGROUP)) { - base->flag &= ~OB_FROMGROUP; - } - } - } + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); + } + } + break; + case ID_ME: + case ID_CU: + case ID_MB: + if (new_id) { /* Only affects us in case obdata was relinked (changed). */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id); } } break; @@ -460,9 +557,10 @@ void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short r * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag * (quite obviously, 'non-NULL' usages can never be unlinked by this function...). */ -void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null) +void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect) { - const short remap_flags = ID_REMAP_SKIP_INDIRECT_USAGE | (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0); + const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) | + (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0); BKE_main_lock(bmain); @@ -488,14 +586,14 @@ void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null) * ... sigh */ void BKE_libblock_relink_ex( - void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) + Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) { ID *id = idv; ID *old_id = old_idv; ID *new_id = new_idv; int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE; - /* No need to lock here, we are only affecting given ID. */ + /* No need to lock here, we are only affecting given ID, not bmain database. */ BLI_assert(id); if (old_id) { @@ -507,6 +605,50 @@ void BKE_libblock_relink_ex( } libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL); + + /* Some after-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + switch (GS(id->name)) { + case ID_SCE: + { + Scene *sce = (Scene *)id; + + if (old_id) { + switch (GS(old_id->name)) { + case ID_OB: + { + libblock_remap_data_postprocess_object_fromgroup_update( + bmain, (Object *)old_id, (Object *)new_id); + break; + } + case ID_GR: + if (!new_id) { /* Only affects us in case group was unlinked. */ + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); + } + break; + default: + break; + } + } + else { + /* No choice but to check whole objects/groups. */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL); + } + for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); + } + } + } + case ID_OB: + if (new_id) { /* Only affects us in case obdata was relinked (changed). */ + libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id); + } + break; + default: + break; + } } static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) @@ -561,7 +703,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) #endif if (do_id_user) { - BKE_libblock_relink_ex(id, NULL, NULL, true); + BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); } switch (type) { @@ -705,7 +847,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ } if (id->us == 0) { - BKE_libblock_unlink(bmain, id, false); + BKE_libblock_unlink(bmain, id, false, false); BKE_libblock_free(bmain, id); } diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 30dc48819e9..c4a0d0074fb 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -171,7 +171,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l } } if (linestyle->nodetree) { - new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree); + new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree); } new_linestyle->r = linestyle->r; @@ -218,8 +218,9 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) BKE_linestyle_geometry_modifier_copy(new_linestyle, m); - if (linestyle->id.lib) { - BKE_id_lib_local_paths(G.main, linestyle->id.lib, &new_linestyle->id); + if (ID_IS_LINKED_DATABLOCK(linestyle)) { + BKE_id_expand_local(&new_linestyle->id); + BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id); } return new_linestyle; diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 94e53755ac4..9e070bbef22 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -533,7 +533,6 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); BezTriple *bezt = &point->bezt, *bezt_next; - float q0[2], q1[2], q2[2], r0[2], r1[2]; bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point); @@ -542,14 +541,7 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float return; } - interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); - interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u); - interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u); - - interp_v2_v2v2(r0, q0, q1, u); - interp_v2_v2v2(r1, q1, q2, u); - - interp_v2_v2v2(co, r0, r1, u); + interp_v2_v2v2v2v2_cubic(co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u); } BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2]) @@ -848,11 +840,11 @@ Mask *BKE_mask_copy_nolib(Mask *mask) return mask_new; } -Mask *BKE_mask_copy(Mask *mask) +Mask *BKE_mask_copy(Main *bmain, Mask *mask) { Mask *mask_new; - mask_new = BKE_libblock_copy(&mask->id); + mask_new = BKE_libblock_copy(bmain, &mask->id); BLI_listbase_clear(&mask_new->masklayers); @@ -861,8 +853,9 @@ Mask *BKE_mask_copy(Mask *mask) /* enable fake user by default */ id_fake_user_set(&mask->id); - if (mask->id.lib) { - BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id); + if (ID_IS_LINKED_DATABLOCK(mask)) { + BKE_id_expand_local(&mask_new->id); + BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id); } return mask_new; diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index db5ac54ada9..17811893c03 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -61,6 +61,8 @@ #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -217,12 +219,12 @@ Material *BKE_material_add(Main *bmain, const char *name) } /* XXX keep synced with next function */ -Material *BKE_material_copy(Material *ma) +Material *BKE_material_copy(Main *bmain, Material *ma) { Material *man; int a; - man = BKE_libblock_copy(&ma->id); + man = BKE_libblock_copy(bmain, &ma->id); id_lib_extern((ID *)man->group); @@ -237,16 +239,17 @@ Material *BKE_material_copy(Material *ma) if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview); - if (ma->nodetree) { - man->nodetree = ntreeCopyTree(ma->nodetree); + man->nodetree = ntreeCopyTree(bmain, ma->nodetree); } + man->preview = BKE_previewimg_copy(ma->preview); + BLI_listbase_clear(&man->gpumaterial); - - if (ma->id.lib) { - BKE_id_lib_local_paths(G.main, ma->id.lib, &man->id); + + if (ID_IS_LINKED_DATABLOCK(ma)) { + BKE_id_expand_local(&man->id); + BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id); } return man; @@ -282,180 +285,33 @@ Material *localize_material(Material *ma) return man; } -static void extern_local_material(Material *ma) -{ - int i; - for (i = 0; i < MAX_MTEX; i++) { - if (ma->mtex[i]) id_lib_extern((ID *)ma->mtex[i]->tex); - } -} - -void BKE_material_make_local(Material *ma) +void BKE_material_make_local(Main *bmain, Material *ma) { - Main *bmain = G.main; - Object *ob; - Mesh *me; - Curve *cu; - MetaBall *mb; - int a; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (ma->id.lib == NULL) return; - /* One local user; set flag and return. */ - if (ma->id.us == 1) { - id_clear_lib_data(bmain, &ma->id); - extern_local_material(ma); + if (!ID_IS_LINKED_DATABLOCK(ma)) { return; } - /* Check which other IDs reference this one to determine if it's used by - * lib or local */ - /* test objects */ - ob = bmain->object.first; - while (ob) { - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a] == ma) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - } - ob = ob->id.next; - } - /* test meshes */ - me = bmain->mesh.first; - while (me) { - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - me = me->id.next; - } - /* test curves */ - cu = bmain->curve.first; - while (cu) { - if (cu->mat) { - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a] == ma) { - if (cu->id.lib) is_lib = true; - else is_local = true; - } - } - } - cu = cu->id.next; - } - /* test mballs */ - mb = bmain->mball.first; - while (mb) { - if (mb->mat) { - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a] == ma) { - if (mb->id.lib) is_lib = true; - else is_local = true; - } - } - } - mb = mb->id.next; - } - - /* Only local users. */ - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &ma->id); - extern_local_material(ma); - } - /* Both user and local, so copy. */ - else if (is_local && is_lib) { - Material *ma_new = BKE_material_copy(ma); + BKE_library_ID_test_usages(bmain, ma, &is_local, &is_lib); - ma_new->id.us = 0; + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &ma->id); + BKE_id_expand_local(&ma->id); + } + else { + Material *ma_new = BKE_material_copy(bmain, ma); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ma->id.lib, &ma_new->id); + ma_new->id.us = 0; - /* do objects */ - ob = bmain->object.first; - while (ob) { - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a] == ma) { - if (ob->id.lib == NULL) { - ob->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - ob = ob->id.next; + BKE_libblock_remap(bmain, ma, ma_new, ID_REMAP_SKIP_INDIRECT_USAGE); } - /* do meshes */ - me = bmain->mesh.first; - while (me) { - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - if (me->id.lib == NULL) { - me->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - me = me->id.next; - } - /* do curves */ - cu = bmain->curve.first; - while (cu) { - if (cu->mat) { - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a] == ma) { - if (cu->id.lib == NULL) { - cu->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - cu = cu->id.next; - } - /* do mballs */ - mb = bmain->mball.first; - while (mb) { - if (mb->mat) { - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a] == ma) { - if (mb->id.lib == NULL) { - mb->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - mb = mb->id.next; - } - } -} - -/* for curve, mball, mesh types */ -void extern_local_matarar(struct Material **matar, short totcol) -{ - short i; - for (i = 0; i < totcol; i++) { - id_lib_extern((ID *)matar[i]); } } @@ -611,7 +467,7 @@ void BKE_material_append_id(ID *id, Material *ma) (*matar)[(*totcol)++] = ma; id_us_plus((ID *)ma); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } } @@ -637,7 +493,7 @@ Material *BKE_material_pop_id(ID *id, int index_i, bool update_data) (*totcol)--; *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol)); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } if (update_data) { @@ -776,7 +632,19 @@ void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user) if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; } -void test_object_materials(Main *bmain, ID *id) +void test_object_materials(Object *ob, ID *id) +{ + /* make the ob mat-array same size as 'ob->data' mat-array */ + const short *totcol; + + if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) { + return; + } + + BKE_material_resize_object(ob, *totcol, false); +} + +void test_all_objects_materials(Main *bmain, ID *id) { /* make the ob mat-array same size as 'ob->data' mat-array */ Object *ob; @@ -839,7 +707,7 @@ void assign_material_id(ID *id, Material *ma, short act) if (ma) id_us_plus(&ma->id); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } void assign_material(Object *ob, Material *ma, short act, int assign_type) @@ -852,8 +720,8 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) if (act < 1) act = 1; /* prevent crashing when using accidentally */ - BLI_assert(ob->id.lib == NULL); - if (ob->id.lib) return; + BLI_assert(!ID_IS_LINKED_DATABLOCK(ob)); + if (ID_IS_LINKED_DATABLOCK(ob)) return; /* test arraylens */ @@ -924,7 +792,7 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) if (ma) id_us_plus(&ma->id); - test_object_materials(G.main, ob->data); + test_object_materials(ob, ob->data); } @@ -1121,7 +989,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) Group *group; for (group = G.main->group.first; group; group = group->id.next) { - if (!group->id.lib && STREQ(group->id.name, ma->group->id.name)) { + if (!ID_IS_LINKED_DATABLOCK(group) && STREQ(group->id.name, ma->group->id.name)) { ma->group = group; } } @@ -2158,7 +2026,7 @@ static void convert_tfacematerial(Main *main, Material *ma) } /* create a new material */ else { - mat_new = BKE_material_copy(ma); + mat_new = BKE_material_copy(main, ma); if (mat_new) { /* rename the material*/ BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name)); @@ -2230,7 +2098,7 @@ int do_version_tface(Main *main) /* 1st part: marking mesh materials to update */ for (me = main->mesh.first; me; me = me->id.next) { - if (me->id.lib) continue; + if (ID_IS_LINKED_DATABLOCK(me)) continue; /* get the active tface layer */ index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); @@ -2284,7 +2152,7 @@ int do_version_tface(Main *main) * at doversion time: direct_link might not have happened on it, * so ma->mtex is not pointing to valid memory yet. * later we could, but it's better not */ - else if (ma->id.lib) + else if (ID_IS_LINKED_DATABLOCK(ma)) continue; /* material already marked as disputed */ @@ -2349,7 +2217,7 @@ int do_version_tface(Main *main) /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */ for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) { - if (ma->id.lib) continue; + if (ID_IS_LINKED_DATABLOCK(ma)) continue; /* disputed material */ if (ma->game.flag == MAT_BGE_DISPUTED) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 685cd35fc20..9a0a6e3540c 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -59,6 +59,8 @@ #include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_displist.h" #include "BKE_mball.h" #include "BKE_object.h" @@ -100,12 +102,12 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name) return mb; } -MetaBall *BKE_mball_copy(MetaBall *mb) +MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb) { MetaBall *mbn; int a; - mbn = BKE_libblock_copy(&mb->id); + mbn = BKE_libblock_copy(bmain, &mb->id); BLI_duplicatelist(&mbn->elems, &mb->elems); @@ -117,65 +119,40 @@ MetaBall *BKE_mball_copy(MetaBall *mb) mbn->editelems = NULL; mbn->lastelem = NULL; - if (mb->id.lib) { - BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id); + if (ID_IS_LINKED_DATABLOCK(mb)) { + BKE_id_expand_local(&mbn->id); + BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id); } return mbn; } -static void extern_local_mball(MetaBall *mb) +void BKE_mball_make_local(Main *bmain, MetaBall *mb) { - if (mb->mat) { - extern_local_matarar(mb->mat, mb->totcol); - } -} - -void BKE_mball_make_local(MetaBall *mb) -{ - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (mb->id.lib == NULL) return; - if (mb->id.us == 1) { - id_clear_lib_data(bmain, &mb->id); - extern_local_mball(mb); - + + if (!ID_IS_LINKED_DATABLOCK(mb)) { return; } - for (ob = G.main->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == mb) { - if (ob->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, mb, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &mb->id); + BKE_id_expand_local(&mb->id); } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &mb->id); - extern_local_mball(mb); - } - else if (is_local && is_lib) { - MetaBall *mb_new = BKE_mball_copy(mb); - mb_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, mb->id.lib, &mb_new->id); - - for (ob = G.main->object.first; ob; ob = ob->id.next) { - if (ob->data == mb) { - if (ob->id.lib == NULL) { - ob->data = mb_new; - id_us_plus(&mb_new->id); - id_us_min(&mb->id); - } - } + else { + MetaBall *mb_new = BKE_mball_copy(bmain, mb); + + mb_new->id.us = 0; + + BKE_libblock_remap(bmain, mb, mb_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index e8418e876bb..2068854421f 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1159,7 +1159,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); /* too big stiffness seems only ugly due to linear interpolation - * no need to have possibility for too big stiffness */ + * no need to have possibility for too big stiffness */ if (ml->s > 10.0f) new_ml->s = 10.0f; else new_ml->s = ml->s; @@ -1294,7 +1294,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); /* don't polygonize metaballs with too high resolution (base mball to small) - * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ + * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index f82e5cf61b3..787b9905734 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -49,6 +49,8 @@ #include "BKE_mesh.h" #include "BKE_displist.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -491,15 +493,13 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) return me; } -Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) +Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) { Mesh *men; - MTFace *tface; - MTexPoly *txface; - int a, i; + int a; const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */ - men = BKE_libblock_copy_ex(bmain, &me->id); + men = BKE_libblock_copy(bmain, &me->id); men->mat = MEM_dupallocN(me->mat); for (a = 0; a < men->totcol; a++) { @@ -520,53 +520,32 @@ Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) BKE_mesh_update_customdata_pointers(men, do_tessface); - /* ensure indirect linked data becomes lib-extern */ - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) - if (tface->tpage) - id_lib_extern((ID *)tface->tpage); - } - } - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - txface = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, txface++) - if (txface->tpage) - id_lib_extern((ID *)txface->tpage); - } - } - men->edit_btmesh = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); - - men->key = BKE_key_copy(me->key); - if (men->key) men->key->from = (ID *)men; - if (me->id.lib) { + if (me->key) { + men->key = BKE_key_copy(bmain, me->key); + men->key->from = (ID *)men; + } + + if (ID_IS_LINKED_DATABLOCK(me)) { + BKE_id_expand_local(&men->id); BKE_id_lib_local_paths(bmain, me->id.lib, &men->id); } return men; } -Mesh *BKE_mesh_copy(Mesh *me) -{ - return BKE_mesh_copy_ex(G.main, me); -} - -BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index) +BMesh *BKE_mesh_to_bmesh( + Mesh *me, Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params) { BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create(&allocsize, params); BM_mesh_bm_from_me( bm, me, (&(struct BMeshFromMeshParams){ @@ -576,49 +555,8 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index) return bm; } -static void expand_local_mesh(Mesh *me) -{ - id_lib_extern((ID *)me->texcomesh); - - if (me->mtface || me->mtpoly) { - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, txface++) { - /* special case: ima always local immediately */ - if (txface->tpage) { - id_lib_extern((ID *)txface->tpage); - } - } - } - } - - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - MTFace *tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) { - /* special case: ima always local immediately */ - if (tface->tpage) { - id_lib_extern((ID *)tface->tpage); - } - } - } - } - } - - if (me->mat) { - extern_local_matarar(me->mat, me->totcol); - } -} - -void BKE_mesh_make_local(Mesh *me) +void BKE_mesh_make_local(Main *bmain, Mesh *me) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing @@ -626,38 +564,26 @@ void BKE_mesh_make_local(Mesh *me) * - mixed: make copy */ - if (me->id.lib == NULL) return; - if (me->id.us == 1) { - id_clear_lib_data(bmain, &me->id); - expand_local_mesh(me); + if (!ID_IS_LINKED_DATABLOCK(me)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (me == ob->data) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &me->id); - expand_local_mesh(me); - } - else if (is_local && is_lib) { - Mesh *me_new = BKE_mesh_copy(me); - me_new->id.us = 0; + BKE_library_ID_test_usages(bmain, me, &is_local, &is_lib); + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &me->id); + if (me->key) { + BKE_key_make_local(bmain, me->key); + } + BKE_id_expand_local(&me->id); + } + else { + Mesh *me_new = BKE_mesh_copy(bmain, me); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, me->id.lib, &me_new->id); + me_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (me == ob->data) { - if (ob->id.lib == NULL) { - BKE_mesh_assign_object(ob, me_new); - } - } + BKE_libblock_remap(bmain, me, me_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -1008,7 +934,7 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me) id_us_plus((ID *)me); } - test_object_materials(G.main, (ID *)me); + test_object_materials(ob, (ID *)me); test_object_modifiers(ob); } @@ -2338,7 +2264,7 @@ Mesh *BKE_mesh_new_from_object( BKE_object_free_modifiers(tmpobj); /* copies the data */ - copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data); + copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit @@ -2419,7 +2345,7 @@ Mesh *BKE_mesh_new_from_object( /* copies object and modifiers (but not the data) */ if (cage) { /* copies the data */ - tmpmesh = BKE_mesh_copy_ex(bmain, ob->data); + tmpmesh = BKE_mesh_copy(bmain, ob->data); /* if not getting the original caged mesh, get final derived mesh */ } else { @@ -2516,8 +2442,8 @@ Mesh *BKE_mesh_new_from_object( BKE_mesh_tessface_ensure(tmpmesh); } - /* make sure materials get updated in objects */ - test_object_materials(bmain, &tmpmesh->id); + /* make sure materials get updated in object */ + test_object_materials(tmpobj ? tmpobj : ob, &tmpmesh->id); return tmpmesh; } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 59eeb5dd96a..936b014cca3 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -700,7 +700,7 @@ void test_object_modifiers(Object *ob) */ const char *modifier_path_relbase(Object *ob) { - if (G.relbase_valid || ob->id.lib) { + if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) { return ID_BLEND_PATH(G.main, &ob->id); } else { diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 18f3db6bd15..0838630a6cb 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -211,7 +211,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do bm = em->bm; } else { - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); } DM_to_bmesh_ex(dm, bm, do_tessellate); @@ -233,7 +235,9 @@ BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal) BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm, bm, calc_face_normal); diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 0527df67033..c321bc92a71 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -183,7 +183,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action) } else { /* use a copy of the action instead (user count shouldn't have changed yet) */ - strip_d->act = BKE_action_copy(strip_d->act); + strip_d->act = BKE_action_copy(G.main, strip_d->act); } } @@ -1291,7 +1291,7 @@ void BKE_nlastrip_recalculate_bounds(NlaStrip *strip) if (IS_EQF(mapping, 0.0f) == 0) strip->end = (actlen * mapping) + strip->start; - /* make sure we don't overlap our neighbours */ + /* make sure we don't overlap our neighbors */ nlastrip_fix_resize_overlaps(strip); } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index d78ddc41e97..296a00388c4 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -58,6 +58,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" @@ -1205,7 +1207,7 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski /* is ntree part of library? */ if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { - newtree = BKE_libblock_copy(&ntree->id); + newtree = BKE_libblock_copy(bmain, &ntree->id); } else { newtree = BKE_libblock_copy_nolib(&ntree->id, true); @@ -1289,7 +1291,8 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski /* node tree will generate its own interface type */ newtree->interface_type = NULL; - if (ntree->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ntree)) { + BKE_id_expand_local(&newtree->id); BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id); } @@ -1300,9 +1303,9 @@ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user { return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); } -bNodeTree *ntreeCopyTree(bNodeTree *ntree) +bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree) { - return ntreeCopyTree_ex(ntree, G.main, true); + return ntreeCopyTree_ex(ntree, bmain, true); } /* use when duplicating scenes */ @@ -1948,70 +1951,33 @@ bNodeTree *ntreeFromID(ID *id) } } -static void extern_local_ntree(bNodeTree *ntree) +void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist) { - for (bNode *node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - id_lib_extern(node->id); - } - } -} - -void ntreeMakeLocal(bNodeTree *ntree, bool id_in_mainlist) -{ - Main *bmain = G.main; - bool lib = false, local = false; + bool is_lib = false, is_local = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (ntree->id.lib == NULL) return; - if (ntree->id.us == 1) { - id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); - extern_local_ntree(ntree); + + if (!ID_IS_LINKED_DATABLOCK(ntree)) { return; } - - /* now check users of groups... again typedepending, callback... */ - FOREACH_NODETREE(G.main, tntree, owner_id) { - bNode *node; - /* find if group is in tree */ - for (node = tntree->nodes.first; node; node = node->next) { - if (node->id == (ID *)ntree) { - if (owner_id->lib) - lib = true; - else - local = true; - } + + BKE_library_ID_test_usages(bmain, ntree, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); + BKE_id_expand_local(&ntree->id); + } + else { + bNodeTree *ntree_new = ntreeCopyTree(bmain, ntree); + + ntree_new->id.us = 0; + + BKE_libblock_remap(bmain, ntree, ntree_new, ID_REMAP_SKIP_INDIRECT_USAGE); } - } FOREACH_NODETREE_END - - /* if all users are local, we simply make tree local */ - if (local && !lib) { - id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); - extern_local_ntree(ntree); - } - else if (local && lib) { - /* this is the mixed case, we copy the tree and assign it to local users */ - bNodeTree *newtree = ntreeCopyTree(ntree); - - newtree->id.us = 0; - - FOREACH_NODETREE(G.main, tntree, owner_id) { - bNode *node; - /* find if group is in tree */ - for (node = tntree->nodes.first; node; node = node->next) { - if (node->id == (ID *)ntree) { - if (owner_id->lib == NULL) { - node->id = (ID *)newtree; - id_us_plus(&newtree->id); - id_us_min(&ntree->id); - } - } - } - } FOREACH_NODETREE_END } } @@ -2715,7 +2681,7 @@ void BKE_node_clipboard_add_node(bNode *node) node_info->id = node->id; if (node->id) { BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); - if (node->id->lib) { + if (ID_IS_LINKED_DATABLOCK(node->id)) { BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name)); } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 357f01e0961..00c25bed1f7 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -95,6 +95,8 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_linestyle.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" @@ -931,7 +933,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) ModifierData *md; int a; - obn = BKE_libblock_copy_ex(bmain, &ob->id); + obn = BKE_libblock_copy(bmain, &ob->id); if (ob->totcol) { obn->mat = MEM_dupallocN(ob->mat); @@ -1001,11 +1003,11 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) copy_object_lod(obn, ob); - /* Copy runtime surve data. */ obn->curve_cache = NULL; - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { + BKE_id_expand_local(&obn->id); BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id); } @@ -1016,41 +1018,13 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) } /* copy objects, will re-initialize cached simulation data */ -Object *BKE_object_copy(Object *ob) +Object *BKE_object_copy(Main *bmain, Object *ob) { - return BKE_object_copy_ex(G.main, ob, false); + return BKE_object_copy_ex(bmain, ob, false); } -static void extern_local_object__modifiersForeachIDLink( - void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) +void BKE_object_make_local(Main *bmain, Object *ob) { - if (*idpoin) { - /* intentionally omit ID_OB */ - if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) { - id_lib_extern(*idpoin); - } - } -} - -static void extern_local_object(Object *ob) -{ - id_lib_extern((ID *)ob->data); - id_lib_extern((ID *)ob->dup_group); - id_lib_extern((ID *)ob->poselib); - id_lib_extern((ID *)ob->gpd); - - extern_local_matarar(ob->mat, ob->totcol); - - modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL); - - ob->preview = NULL; -} - -void BKE_object_make_local(Object *ob) -{ - Main *bmain = G.main; - Scene *sce; - Base *base; bool is_local = false, is_lib = false; /* - only lib users: do nothing @@ -1058,74 +1032,40 @@ void BKE_object_make_local(Object *ob) * - mixed: make copy */ - if (ob->id.lib == NULL) return; - - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - - if (ob->id.us == 1) { - id_clear_lib_data(bmain, &ob->id); - extern_local_object(ob); + if (!ID_IS_LINKED_DATABLOCK(ob)) { + return; } - else { - for (sce = bmain->scene.first; sce && ELEM(0, is_lib, is_local); sce = sce->id.next) { - if (BKE_scene_base_find(sce, ob)) { - if (sce->id.lib) is_lib = true; - else is_local = true; - } - } - if (is_local && is_lib == false) { + BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { id_clear_lib_data(bmain, &ob->id); - extern_local_object(ob); + BKE_id_expand_local(&ob->id); } - else if (is_local && is_lib) { - Object *ob_new = BKE_object_copy(ob); + else { + Object *ob_new = BKE_object_copy(bmain, ob); ob_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ob->id.lib, &ob_new->id); - - sce = bmain->scene.first; - while (sce) { - if (sce->id.lib == NULL) { - base = sce->base.first; - while (base) { - if (base->object == ob) { - base->object = ob_new; - id_us_plus(&ob_new->id); - id_us_min(&ob->id); - } - base = base->next; - } - } - sce = sce->id.next; - } + ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; + + BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } -/* - * Returns true if the Object is a from an external blend file (libdata) - */ +/* Returns true if the Object is from an external blend file (libdata) */ bool BKE_object_is_libdata(Object *ob) { - if (!ob) return false; - if (ob->proxy) return false; - if (ob->id.lib) return true; - return false; + return (ob && ID_IS_LINKED_DATABLOCK(ob)); } -/* Returns true if the Object data is a from an external blend file (libdata) */ +/* Returns true if the Object data is from an external blend file (libdata) */ bool BKE_object_obdata_is_libdata(Object *ob) { - if (!ob) return false; - if (ob->proxy && (ob->data == NULL || ((ID *)ob->data)->lib == NULL)) return false; - if (ob->id.lib) return true; - if (ob->data == NULL) return false; - if (((ID *)ob->data)->lib) return true; - - return false; + /* Linked objects with local obdata are forbidden! */ + BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true)); + return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data)); } /* *************** PROXY **************** */ @@ -1172,7 +1112,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* only on local objects because this causes indirect links * 'a -> b -> c', blend to point directly to a.blend * when a.blend has a proxy thats linked into c.blend */ - if (ob->id.lib == NULL) + if (!ID_IS_LINKED_DATABLOCK(ob)) id_lib_extern((ID *)dtar->id); } } @@ -1190,7 +1130,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) { /* paranoia checks */ - if (ob->id.lib || target->id.lib == NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) { printf("cannot make proxy\n"); return; } @@ -2567,7 +2507,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, printf("recalcob %s\n", ob->id.name + 2); /* handle proxy copy for target */ - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ Object *obg = ob->proxy_from->proxy_group; diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 8df501bd106..b5cb59da7d2 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, break; } case OB_ARMATURE: - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); @@ -268,7 +268,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx), // XXX: it's almost redundant now... /* Handle proxy copy for target, */ - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { if (ob->proxy_from->proxy_group) { /* Transform proxy into group space. */ Object *obg = ob->proxy_from->proxy_group; diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 1c318dfd115..489fc2f3710 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) int tot = 0; for (ima = bmain->image.first; ima; ima = ima->id.next) { - if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) { + if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) { if (ima->source == IMA_SRC_FILE) { BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id)); tot ++; @@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) } for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { - if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == false) { + if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) { vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name); tot ++; } } for (sound = bmain->sound.first; sound; sound = sound->id.next) { - if (sound->packedfile == NULL && sound->id.lib == NULL) { + if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) { sound->packedfile = newPackedFile(reports, sound->name, bmain->name); tot++; } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 58ec75dc706..ff69f381b06 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -276,16 +276,14 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) /* reserve size is rough guess */ GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface); - int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface, + int (*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface, "bvh node face vert indices"); - node->face_vert_indices = (const int (*)[4])face_vert_indices; + node->face_vert_indices = (const int (*)[3])face_vert_indices; for (int i = 0; i < totface; ++i) { const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]]; - const int sides = 3; - - for (int j = 0; j < sides; ++j) { + for (int j = 0; j < 3; ++j) { face_vert_indices[i][j] = map_insert_vert(bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v); @@ -690,8 +688,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting) { if (UNLIKELY(iter->stacksize == iter->stackspace)) { iter->stackspace *= 2; - - if (iter->stackspace != STACK_FIXED_DEPTH) { + if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) { iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace); } else { @@ -1496,12 +1493,18 @@ typedef struct { static bool ray_aabb_intersect(PBVHNode *node, void *data_v) { RaycastData *rcd = data_v; - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; - if (rcd->original) - BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); - else - BKE_pbvh_node_get_BB(node, bb_min, bb_max); + if (rcd->original) { + /* BKE_pbvh_node_get_original_BB */ + bb_min = node->orig_vb.bmin; + bb_max = node->orig_vb.bmax; + } + else { + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; + } return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin); } @@ -1801,17 +1804,21 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) { - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; - BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; } bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) { - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; - BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 88dc63d6cb2..55f9f384081 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -69,11 +69,134 @@ static void pbvh_bmesh_verify(PBVH *bvh); #endif +/** \name BMesh Utility API + * + * Use some local functions which assume triangles. + * \{ */ + +/** + * Typically using BM_LOOPS_OF_VERT and BM_FACES_OF_VERT iterators are fine, + * however this is an area where performance matters so do it in-line. + * + * Take care since 'break' won't works as expected within these macros! + */ + +#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \ +{ \ + struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \ + _iter.v = v_; \ + if (_iter.v->e) { \ + _iter.e_iter = _iter.e_first = _iter.v->e; \ + do { \ + if (_iter.e_iter->l) { \ + _iter.l_iter_radial = _iter.e_iter->l; \ + do { \ + if (_iter.l_iter_radial->v == _iter.v) { \ + l_iter_radial_ = _iter.l_iter_radial; + +#define BM_LOOPS_OF_VERT_ITER_END \ + } \ + } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \ + } \ + } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \ + } \ +} ((void)0) + +#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \ +{ \ + BMLoop *l_iter_radial_; \ + BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \ + f_iter_ = l_iter_radial_->f; \ + +#define BM_FACES_OF_VERT_ITER_END \ + } \ + BM_LOOPS_OF_VERT_ITER_END; \ +} + +static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) +{ + e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); + e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); + e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); +} + +BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) +{ + BMLoop *l = BM_FACE_FIRST_LOOP(f); + + BLI_assert(f->len == 3); + + r_index[0] = BM_elem_index_get(l->v); l = l->next; + r_index[1] = BM_elem_index_get(l->v); l = l->next; + r_index[2] = BM_elem_index_get(l->v); +} + +/** + * A version of #BM_face_exists, optimized for triangles + * when we know the loop and the opposite vertex. + * + * Check if any triangle is formed by (l_radial_first->v, l_radial_first->next->v, v_opposite), + * at either winding (since its a triangle no special checks are needed). + * + * <pre> + * l_radial_first->v & l_radial_first->next->v + * +---+ + * | / + * | / + * + v_opposite + * </pre> + * + * Its assumed that \a l_radial_first is never forming the target face. + */ +static bool bm_face_exists_tri_from_loop_vert( + BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing) +{ + BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v)); + if (l_radial_first->radial_next != l_radial_first) { + BMLoop *l_radial_iter = l_radial_first->radial_next; + do { + BLI_assert(l_radial_iter->f->len == 3); + if (l_radial_iter->prev->v == v_opposite) { + *r_face_existing = l_radial_iter->f; + return true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); + } + return false; +} + +/** + * Uses a map of vertices to lookup the final target. + * References can't point to previous items (would cause infinite loop). + */ +static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v) +{ + while (true) { + BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v); + if (v_next_p == NULL) { + /* not remapped*/ + return v; + } + else if (*v_next_p == NULL) { + /* removed and not remapped */ + return NULL; + } + else { + /* remapped */ + v = *v_next_p; + } + } +} + +/** \} */ + /****************************** Building ******************************/ /* Update node data after splitting */ -static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset) +static void pbvh_bmesh_node_finalize( + PBVH *bvh, const int node_index, + const int cd_vert_node_offset, const int cd_face_node_offset) { GSetIterator gs_iter; PBVHNode *n = &bvh->nodes[node_index]; @@ -200,7 +323,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde break; } } - + /* Clear this node */ /* Mark this node's unique verts as unclaimed */ @@ -224,18 +347,18 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde if (n->layer_disp) MEM_freeN(n->layer_disp); - + n->bm_faces = NULL; n->bm_unique_verts = NULL; n->bm_other_verts = NULL; n->layer_disp = NULL; - + if (n->draw_buffers) { GPU_free_pbvh_buffers(n->draw_buffers); n->draw_buffers = NULL; } n->flag &= ~PBVH_Leaf; - + /* Recurse */ pbvh_bmesh_node_split(bvh, bbc_array, children); pbvh_bmesh_node_split(bvh, bbc_array, children + 1); @@ -292,6 +415,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) /**********************************************************************/ +#if 0 static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele) { switch (ele->head.htype) { @@ -304,7 +428,7 @@ static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele) } -static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key) +static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key) { const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key); const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset); @@ -316,18 +440,45 @@ static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key) return node_index; } -static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key) +static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key) { - return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)]; + return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)]; } /* typecheck */ -#define pbvh_bmesh_node_lookup_index(bvh, key) ( \ +#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \ - pbvh_bmesh_node_lookup_index(bvh, key)) -#define pbvh_bmesh_node_lookup(bvh, key) ( \ + pbvh_bmesh_node_index_from_elem(bvh, key)) +#define pbvh_bmesh_node_from_elem(bvh, key) ( \ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \ - pbvh_bmesh_node_lookup(bvh, key)) + pbvh_bmesh_node_from_elem(bvh, key)) +#endif + +BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key) +{ + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset); + BLI_assert(node_index != DYNTOPO_NODE_NONE); + BLI_assert(node_index < bvh->totnode); + return node_index; +} + +BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key) +{ + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset); + BLI_assert(node_index != DYNTOPO_NODE_NONE); + BLI_assert(node_index < bvh->totnode); + return node_index; +} + +BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key) +{ + return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)]; +} + +BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key) +{ + return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)]; +} static BMVert *pbvh_bmesh_vert_create( @@ -357,6 +508,9 @@ static BMVert *pbvh_bmesh_vert_create( return v; } +/** + * \note Callers are responsible for checking if the face exists before adding. + */ static BMFace *pbvh_bmesh_face_create( PBVH *bvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], @@ -367,7 +521,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); - BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE); + BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -387,16 +541,16 @@ static BMFace *pbvh_bmesh_face_create( #if 0 static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) { - BMIter bm_iter; BMFace *f; int count = 0; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); if (f_node == node) { count++; } } + BM_FACES_OF_VERT_ITER_END; return count; } @@ -407,19 +561,19 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) { - BMIter bm_iter; - BMFace *f; int count = 0; + BMFace *f; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); if (f_node == node) { count++; if (count == count_max) { - break; + return count; } } } + BM_FACES_OF_VERT_ITER_END; return count; } @@ -427,16 +581,17 @@ static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert * /* Return a node that uses vertex 'v' other than its current owner */ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v) { - BMIter bm_iter; + PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v); BMFace *f; - PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v); - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); - if (f_node != current_node) + if (f_node != current_node) { return f_node; + } } + BM_FACES_OF_VERT_ITER_END; return NULL; } @@ -445,7 +600,7 @@ static void pbvh_bmesh_vert_ownership_transfer( PBVH *bvh, PBVHNode *new_owner, BMVert *v) { - PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v); /* mark node for update */ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; @@ -469,36 +624,36 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) /* never match for first time */ int f_node_index_prev = DYNTOPO_NODE_NONE; - PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v); BLI_gset_remove(v_node->bm_unique_verts, v, NULL); BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE); /* Have to check each neighboring face's node */ - BMIter bm_iter; BMFace *f; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f); /* faces often share the same node, * quick check to avoid redundant #BLI_gset_remove calls */ - if (f_node_index_prev == f_node_index) - continue; - f_node_index_prev = f_node_index; + if (f_node_index_prev != f_node_index) { + f_node_index_prev = f_node_index; - PBVHNode *f_node = &bvh->nodes[f_node_index]; - f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + PBVHNode *f_node = &bvh->nodes[f_node_index]; + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; - /* Remove current ownership */ - BLI_gset_remove(f_node->bm_other_verts, v, NULL); + /* Remove current ownership */ + BLI_gset_remove(f_node->bm_other_verts, v, NULL); - BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v)); - BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v)); + } } + BM_FACES_OF_VERT_ITER_END; } static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); /* Check if any of this face's vertices need to be removed * from the node */ @@ -923,13 +1078,6 @@ static void short_edge_queue_create( /*************************** Topology update **************************/ -static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) -{ - e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); - e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); - e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); -} - static void pbvh_bmesh_split_edge( EdgeQueueContext *eq_ctx, PBVH *bvh, BMEdge *e, BLI_Buffer *edge_loops) @@ -1101,15 +1249,16 @@ static bool pbvh_bmesh_subdivide_long_edges( static void pbvh_bmesh_collapse_edge( PBVH *bvh, BMEdge *e, BMVert *v1, BMVert *v2, - GSet *deleted_verts, + GHash *deleted_verts, BLI_Buffer *deleted_faces, EdgeQueueContext *eq_ctx) { BMVert *v_del, *v_conn; - float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset); /* one of the two vertices may be masked, select the correct one for deletion */ - if (mask_v1 < 1.0f) { + if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) < + BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset)) + { v_del = v1; v_conn = v2; } @@ -1141,33 +1290,43 @@ static void pbvh_bmesh_collapse_edge( * really buy anything. */ BLI_buffer_empty(deleted_faces); - BMIter bm_iter; - BMFace *f; + BMLoop *l; - BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) { - BMVert *v_tri[3]; + BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) { BMFace *existing_face; /* Get vertices, replace use of v_del with v_conn */ // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3); + BMFace *f = l->f; +#if 0 + BMVert *v_tri[3]; BM_face_as_array_vert_tri(f, v_tri); for (int i = 0; i < 3; i++) { if (v_tri[i] == v_del) { v_tri[i] = v_conn; } } +#endif /* Check if a face using these vertices already exists. If so, * skip adding this face and mark the existing one for * deletion as well. Prevents extraneous "flaps" from being * created. */ - if (BM_face_exists(v_tri, 3, &existing_face)) { +#if 0 + if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face))) +#else + if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face))) +#endif + { BLI_assert(existing_face); BLI_buffer_append(deleted_faces, BMFace *, existing_face); } else { + BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v}; + + BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); BMEdge *e_tri[3]; - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f); int ni = n - bvh->nodes; bm_edges_from_tri(bvh->bm, v_tri, e_tri); pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f); @@ -1180,6 +1339,7 @@ static void pbvh_bmesh_collapse_edge( BLI_buffer_append(deleted_faces, BMFace *, f); } + BM_LOOPS_OF_VERT_ITER_END; /* Delete the tagged faces */ for (int i = 0; i < deleted_faces->count; i++) { @@ -1209,10 +1369,14 @@ static void pbvh_bmesh_collapse_edge( * remove them from the PBVH */ for (int j = 0; j < 3; j++) { if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) { - BLI_gset_insert(deleted_verts, v_tri[j]); pbvh_bmesh_vert_remove(bvh, v_tri[j]); BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset); + + if (v_tri[j] == v_conn) { + v_conn = NULL; + } + BLI_ghash_insert(deleted_verts, v_tri[j], NULL); BM_vert_kill(bvh->bm, v_tri[j]); } } @@ -1220,17 +1384,26 @@ static void pbvh_bmesh_collapse_edge( /* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it * may have been deleted above) */ - if (!BLI_gset_haskey(deleted_verts, v_conn)) { + if (v_conn != NULL) { BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset); mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co); add_v3_v3(v_conn->no, v_del->no); normalize_v3(v_conn->no); + + /* update boundboxes attached to the connected vertex + * note that we can often get-away without this but causes T48779 */ + BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f); + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB; + } + BM_LOOPS_OF_VERT_ITER_END; } /* Delete v_del */ BLI_assert(!BM_vert_face_check(v_del)); - BLI_gset_insert(deleted_verts, v_del); BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); + /* v_conn == NULL is OK */ + BLI_ghash_insert(deleted_verts, v_del, v_conn); BM_vert_kill(bvh->bm, v_del); } @@ -1241,17 +1414,19 @@ static bool pbvh_bmesh_collapse_short_edges( { const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; bool any_collapsed = false; - GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts"); + /* deleted verts point to vertices they were merged into, or NULL when removed. */ + GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts"); while (!BLI_heap_is_empty(eq_ctx->q->heap)) { BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); - BMVert *v1 = pair[0], *v2 = pair[1]; + BMVert *v1 = pair[0], *v2 = pair[1]; BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; /* Check the verts still exist */ - if (BLI_gset_haskey(deleted_verts, v1) || - BLI_gset_haskey(deleted_verts, v2)) + if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) || + !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) || + (v1 == v2)) { continue; } @@ -1285,7 +1460,7 @@ static bool pbvh_bmesh_collapse_short_edges( deleted_faces, eq_ctx); } - BLI_gset_free(deleted_verts, NULL); + BLI_ghash_free(deleted_verts, NULL, NULL); return any_collapsed; } @@ -1406,18 +1581,23 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) } } -typedef struct FastNodeBuildInfo { +struct FastNodeBuildInfo { int totface; /* number of faces */ int start; /* start of faces in array */ struct FastNodeBuildInfo *child1; struct FastNodeBuildInfo *child2; -} FastNodeBuildInfo; +}; -/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies - * to a sub part of the arrays */ -static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena) +/** + * Recursively split the node if it exceeds the leaf_limit. + * This function is multithreadabe since each invocation applies + * to a sub part of the arrays + */ +static void pbvh_bmesh_node_limit_ensure_fast( + PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, + MemArena *arena) { - FastNodeBuildInfo *child1, *child2; + struct FastNodeBuildInfo *child1, *child2; if (node->totface <= bvh->leaf_limit) { return; @@ -1497,8 +1677,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC * each sequential part belonging to one node only */ BLI_assert((num_child1 + num_child2) == node->totface); - node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); - node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo)); + node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo)); child1->totface = num_child1; child1->start = node->start; @@ -1510,7 +1690,9 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena); } -static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index) +static void pbvh_bmesh_create_nodes_fast_recursive( + PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, + struct FastNodeBuildInfo *node, int node_index) { PBVHNode *n = bvh->nodes + node_index; /* two cases, node does not have children or does have children */ @@ -1651,7 +1833,7 @@ void BKE_pbvh_build_bmesh( bm->elem_index_dirty |= BM_FACE; /* setup root node */ - FastNodeBuildInfo rootnode = {0}; + struct FastNodeBuildInfo rootnode = {0}; rootnode.totface = bm->totface; /* start recursion, assign faces to nodes accordingly */ @@ -1693,12 +1875,14 @@ bool BKE_pbvh_bmesh_update_topology( if (mode & PBVH_Collapse) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); - EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; + EdgeQueueContext eq_ctx = { + &q, queue_pool, bvh->bm, + cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, + }; short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); - modified |= !BLI_heap_is_empty(q.heap); - pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, - &deleted_faces); + modified |= pbvh_bmesh_collapse_short_edges( + &eq_ctx, bvh, &deleted_faces); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1706,15 +1890,18 @@ bool BKE_pbvh_bmesh_update_topology( if (mode & PBVH_Subdivide) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); - EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; + EdgeQueueContext eq_ctx = { + &q, queue_pool, bvh->bm, + cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, + }; long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); - modified |= !BLI_heap_is_empty(q.heap); - pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops); + modified |= pbvh_bmesh_subdivide_long_edges( + &eq_ctx, bvh, &edge_loops); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } - + /* Unmark nodes */ for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -1735,16 +1922,6 @@ bool BKE_pbvh_bmesh_update_topology( return modified; } -BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) -{ - BMLoop *l = BM_FACE_FIRST_LOOP(f); - - BLI_assert(f->len == 3); - - r_index[0] = BM_elem_index_get(l->v); l = l->next; - r_index[1] = BM_elem_index_get(l->v); l = l->next; - r_index[2] = BM_elem_index_get(l->v); -} /* In order to perform operations on the original node coordinates * (currently just raycast), store the node's triangles and vertices. @@ -1858,8 +2035,8 @@ static void pbvh_bmesh_print(PBVH *bvh) BMFace *f; BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", - BM_elem_index_get(v), - pbvh_bmesh_node_lookup_index(bvh, f)); + BM_elem_index_get(f), + pbvh_bmesh_node_index_from_face(bvh, f)); } fprintf(stderr, "bm_vert_to_node:\n"); @@ -1867,7 +2044,7 @@ static void pbvh_bmesh_print(PBVH *bvh) BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), - pbvh_bmesh_node_lookup_index(bvh, v)); + pbvh_bmesh_node_index_from_vert(bvh, v)); } for (int n = 0; n < bvh->totnode; n++) { @@ -1909,17 +2086,23 @@ static void pbvh_bmesh_verify(PBVH *bvh) { /* build list of faces & verts to lookup */ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface); - BMFace *f; BMIter iter; - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BLI_gset_insert(faces_all, f); + + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE); + BLI_gset_insert(faces_all, f); + } } GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert); - BMVert *v; - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { - BLI_gset_insert(verts_all, v); + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { + BLI_gset_insert(verts_all, v); + } } } @@ -1936,76 +2119,83 @@ static void pbvh_bmesh_verify(PBVH *bvh) BLI_assert(totvert == BLI_gset_size(verts_all)); } - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BMIter bm_iter; - BMVert *v; - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BMIter bm_iter; + BMVert *v; + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); - /* Check that the face's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the face's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the face's node knows it owns the face */ - BLI_assert(BLI_gset_haskey(n->bm_faces, f)); + /* Check that the face's node knows it owns the face */ + BLI_assert(BLI_gset_haskey(n->bm_faces, f)); - /* Check the face's vertices... */ - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { - PBVHNode *nv; + /* Check the face's vertices... */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + PBVHNode *nv; - /* Check that the vertex is in the node */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ - BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex is in the node */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ + BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vertex has a node owner */ - nv = pbvh_bmesh_node_lookup(bvh, v); + /* Check that the vertex has a node owner */ + nv = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vertex's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); + /* Check that the vertex's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + } } } /* Check verts */ - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - /* vertex isn't tracked */ - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { - continue; - } + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + /* vertex isn't tracked */ + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { + continue; + } - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vert's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the vert's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the vert's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); + /* Check that the vert's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vert's node also contains one of the vert's - * adjacent faces */ - bool found = false; - BMIter bm_iter; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - if (pbvh_bmesh_node_lookup(bvh, f) == n) { - found = true; - break; + /* Check that the vert's node also contains one of the vert's + * adjacent faces */ + bool found = false; + BMIter bm_iter; + BMFace *f = NULL; + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + if (pbvh_bmesh_node_lookup(bvh, f) == n) { + found = true; + break; + } } - } - BLI_assert(found); + BLI_assert(found || f == NULL); #if 1 - /* total freak stuff, check if node exists somewhere else */ - /* Slow */ - for (int i = 0; i < bvh->totnode; i++) { - PBVHNode *n_other = &bvh->nodes[i]; - if ((n != n_other) && (n_other->bm_unique_verts)) { - BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + /* total freak stuff, check if node exists somewhere else */ + /* Slow */ + for (int i = 0; i < bvh->totnode; i++) { + PBVHNode *n_other = &bvh->nodes[i]; + if ((n != n_other) && (n_other->bm_unique_verts)) { + BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + } } - } #endif + } } #if 0 @@ -2049,7 +2239,8 @@ static void pbvh_bmesh_verify(PBVH *bvh) GSET_ITER (gs_iter, n->bm_other_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - BLI_assert(!BM_vert_face_check(v)); + /* this happens sometimes and seems harmless */ + // BLI_assert(!BM_vert_face_check(v)); BLI_assert(BLI_gset_haskey(verts_all, v)); } } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 4d2307c3e12..19d3b31bd31 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -83,12 +83,11 @@ struct PBVHNode { * array. The array is sized to match 'totprim', and each of * the face's corners gets an index into the vert_indices * array, in the same order as the corners in the original - * MFace. The fourth value should not be used if the original - * face is a triangle. + * MLoopTri. * * Used for leaf nodes in a mesh-based PBVH (not multires.) */ - const int (*face_vert_indices)[4]; + const int (*face_vert_indices)[3]; /* Indicates whether this node is a leaf or not; also used for * marking various updates that need to be applied. */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 4a649c2ea6d..572d23b39c7 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -150,7 +150,7 @@ static void remove_sequencer_fcurves(Scene *sce) } } -Scene *BKE_scene_copy(Scene *sce, int type) +Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; @@ -161,7 +161,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (type == SCE_COPY_EMPTY) { ListBase rl, rv; /* XXX. main should become an arg */ - scen = BKE_scene_add(G.main, sce->id.name + 2); + scen = BKE_scene_add(bmain, sce->id.name + 2); rl = scen->r.layers; rv = scen->r.views; @@ -182,10 +182,10 @@ Scene *BKE_scene_copy(Scene *sce, int type) BKE_sound_destroy_scene(scen); } else { - scen = BKE_libblock_copy(&sce->id); + scen = BKE_libblock_copy(bmain, &sce->id); BLI_duplicatelist(&(scen->base), &(sce->base)); - BKE_main_id_clear_newpoins(G.main); + BKE_main_id_clear_newpoins(bmain); id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->set); @@ -209,7 +209,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (sce->nodetree) { /* ID's are managed on both copy and switch */ - scen->nodetree = ntreeCopyTree(sce->nodetree); + scen->nodetree = ntreeCopyTree(bmain, sce->nodetree); ntreeSwitchID(scen->nodetree, &sce->id, &scen->id); } @@ -237,7 +237,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { if (lineset->linestyle) { id_us_plus((ID *)lineset->linestyle); - lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle); } } } @@ -319,7 +319,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (type == SCE_COPY_FULL) { if (scen->world) { id_us_plus((ID *)scen->world); - scen->world = BKE_world_copy(scen->world); + scen->world = BKE_world_copy(bmain, scen->world); BKE_animdata_copy_id_action((ID *)scen->world); } @@ -333,7 +333,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) /* grease pencil */ if (scen->gpd) { if (type == SCE_COPY_FULL) { - scen->gpd = gpencil_data_duplicate(scen->gpd, false); + scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false); } else if (type == SCE_COPY_EMPTY) { scen->gpd = NULL; @@ -343,9 +343,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) } } - if (sce->preview) { - scen->preview = BKE_previewimg_copy(sce->preview); - } + scen->preview = BKE_previewimg_copy(sce->preview); return scen; } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 25b32cc40aa..fc3daa132c6 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2243,7 +2243,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa .. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/ /* rule we never alter free variables :bp->vec bp->pos in here ! - * this will ruin adaptive stepsize AKA heun! (BM) + * this will ruin adaptive stepsize AKA heun! (BM) */ SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index e5075a2d382..a91d8657179 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -34,6 +34,8 @@ #include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_speaker.h" @@ -66,30 +68,25 @@ void *BKE_speaker_add(Main *bmain, const char *name) return spk; } -Speaker *BKE_speaker_copy(Speaker *spk) +Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk) { Speaker *spkn; - spkn = BKE_libblock_copy(&spk->id); + spkn = BKE_libblock_copy(bmain, &spk->id); + if (spkn->sound) id_us_plus(&spkn->sound->id); - if (spk->id.lib) { + if (ID_IS_LINKED_DATABLOCK(spk)) { + BKE_id_expand_local(&spkn->id); BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id); } return spkn; } -static void extern_local_speaker(Speaker *spk) -{ - id_lib_extern((ID *)spk->sound); -} - -void BKE_speaker_make_local(Speaker *spk) +void BKE_speaker_make_local(Main *bmain, Speaker *spk) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; /* - only lib users: do nothing @@ -97,44 +94,23 @@ void BKE_speaker_make_local(Speaker *spk) * - mixed: make copy */ - if (spk->id.lib == NULL) return; - if (spk->id.us == 1) { - id_clear_lib_data(bmain, &spk->id); - extern_local_speaker(spk); + if (!ID_IS_LINKED_DATABLOCK(spk)) { return; } - ob = bmain->object.first; - while (ob) { - if (ob->data == spk) { - if (ob->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, spk, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &spk->id); + BKE_id_expand_local(&spk->id); } - ob = ob->id.next; - } + else { + Speaker *spk_new = BKE_speaker_copy(bmain, spk); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &spk->id); - extern_local_speaker(spk); - } - else if (is_local && is_lib) { - Speaker *spk_new = BKE_speaker_copy(spk); - spk_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, spk->id.lib, &spk_new->id); - - ob = bmain->object.first; - while (ob) { - if (ob->data == spk) { - - if (ob->id.lib == NULL) { - ob->data = spk_new; - id_us_plus(&spk_new->id); - id_us_min(&spk->id); - } - } - ob = ob->id.next; + spk_new->id.us = 0; + + BKE_libblock_remap(bmain, spk, spk_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index fdc2edba57f..269d6d32b31 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -452,7 +452,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta) Text *tan; TextLine *line, *tmp; - tan = BKE_libblock_copy(&ta->id); + tan = BKE_libblock_copy(bmain, &ta->id); /* file name can be NULL */ if (ta->name) { @@ -491,7 +491,8 @@ Text *BKE_text_copy(Main *bmain, Text *ta) init_undo_text(tan); - if (ta->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ta)) { + BKE_id_expand_local(&tan->id); BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id); } diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 3e4f13a2c8f..dcd60aaa702 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -58,6 +58,8 @@ #include "BKE_main.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_image.h" #include "BKE_material.h" #include "BKE_texture.h" @@ -843,11 +845,11 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) /* ------------------------------------------------------------------------- */ -Tex *BKE_texture_copy(Tex *tex) +Tex *BKE_texture_copy(Main *bmain, Tex *tex) { Tex *texn; - texn = BKE_libblock_copy(&tex->id); + texn = BKE_libblock_copy(bmain, &tex->id); if (BKE_texture_is_image_user(tex)) { id_us_plus((ID *)texn->ima); } @@ -866,11 +868,14 @@ Tex *BKE_texture_copy(Tex *tex) if (tex->nodetree->execdata) { ntreeTexEndExecTree(tex->nodetree->execdata); } - texn->nodetree = ntreeCopyTree(tex->nodetree); + texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); } - if (tex->id.lib) { - BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id); + texn->preview = BKE_previewimg_copy(tex->preview); + + if (ID_IS_LINKED_DATABLOCK(tex)) { + BKE_id_expand_local(&texn->id); + BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id); } return texn; @@ -912,169 +917,32 @@ Tex *BKE_texture_localize(Tex *tex) /* ------------------------------------------------------------------------- */ -static void extern_local_texture(Tex *tex) +void BKE_texture_make_local(Main *bmain, Tex *tex) { - id_lib_extern((ID *)tex->ima); -} - -void BKE_texture_make_local(Tex *tex) -{ - Main *bmain = G.main; - Material *ma; - World *wrld; - Lamp *la; - Brush *br; - FreestyleLineStyle *ls; - int a; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (tex->id.lib == NULL) return; - if (tex->id.us == 1) { - id_clear_lib_data(bmain, &tex->id); - extern_local_texture(tex); + if (!ID_IS_LINKED_DATABLOCK(tex)) { return; } - - ma = bmain->mat.first; - while (ma) { - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex == tex) { - if (ma->id.lib) is_lib = true; - else is_local = true; - } - } - ma = ma->id.next; - } - la = bmain->lamp.first; - while (la) { - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex == tex) { - if (la->id.lib) is_lib = true; - else is_local = true; - } - } - la = la->id.next; - } - wrld = bmain->world.first; - while (wrld) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) { - if (wrld->id.lib) is_lib = true; - else is_local = true; - } - } - wrld = wrld->id.next; - } - br = bmain->brush.first; - while (br) { - if (br->mtex.tex == tex) { - if (br->id.lib) is_lib = true; - else is_local = true; - } - if (br->mask_mtex.tex == tex) { - if (br->id.lib) is_lib = true; - else is_local = true; - } - br = br->id.next; - } - ls = bmain->linestyle.first; - while (ls) { - for (a = 0; a < MAX_MTEX; a++) { - if (ls->mtex[a] && ls->mtex[a]->tex == tex) { - if (ls->id.lib) is_lib = true; - else is_local = true; - } - } - ls = ls->id.next; - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &tex->id); - extern_local_texture(tex); - } - else if (is_local && is_lib) { - Tex *tex_new = BKE_texture_copy(tex); - tex_new->id.us = 0; + BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, tex->id.lib, &tex_new->id); - - ma = bmain->mat.first; - while (ma) { - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex == tex) { - if (ma->id.lib == NULL) { - ma->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - ma = ma->id.next; - } - la = bmain->lamp.first; - while (la) { - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex == tex) { - if (la->id.lib == NULL) { - la->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - la = la->id.next; - } - wrld = bmain->world.first; - while (wrld) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) { - if (wrld->id.lib == NULL) { - wrld->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - wrld = wrld->id.next; + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &tex->id); + BKE_id_expand_local(&tex->id); } - br = bmain->brush.first; - while (br) { - if (br->mtex.tex == tex) { - if (br->id.lib == NULL) { - br->mtex.tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - if (br->mask_mtex.tex == tex) { - if (br->id.lib == NULL) { - br->mask_mtex.tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - br = br->id.next; - } - ls = bmain->linestyle.first; - while (ls) { - for (a = 0; a < MAX_MTEX; a++) { - if (ls->mtex[a] && ls->mtex[a]->tex == tex) { - if (ls->id.lib == NULL) { - ls->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - ls = ls->id.next; + else { + Tex *tex_new = BKE_texture_copy(bmain, tex); + + tex_new->id.us = 0; + + BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index ec021586be5..9795a8174f8 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -46,6 +46,8 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_world.h" @@ -117,12 +119,12 @@ World *add_world(Main *bmain, const char *name) return wrld; } -World *BKE_world_copy(World *wrld) +World *BKE_world_copy(Main *bmain, World *wrld) { World *wrldn; int a; - wrldn = BKE_libblock_copy(&wrld->id); + wrldn = BKE_libblock_copy(bmain, &wrld->id); for (a = 0; a < MAX_MTEX; a++) { if (wrld->mtex[a]) { @@ -133,16 +135,16 @@ World *BKE_world_copy(World *wrld) } if (wrld->nodetree) { - wrldn->nodetree = ntreeCopyTree(wrld->nodetree); + wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree); } - if (wrld->preview) - wrldn->preview = BKE_previewimg_copy(wrld->preview); + wrldn->preview = BKE_previewimg_copy(wrld->preview); BLI_listbase_clear(&wrldn->gpumaterial); - if (wrld->id.lib) { - BKE_id_lib_local_paths(G.main, wrld->id.lib, &wrldn->id); + if (ID_IS_LINKED_DATABLOCK(wrld)) { + BKE_id_expand_local(&wrldn->id); + BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id); } return wrldn; @@ -174,48 +176,32 @@ World *localize_world(World *wrld) return wrldn; } -void BKE_world_make_local(World *wrld) +void BKE_world_make_local(Main *bmain, World *wrld) { - Main *bmain = G.main; - Scene *sce; bool is_local = false, is_lib = false; /* - only lib users: do nothing * - only local users: set flag * - mixed: make copy */ - - if (wrld->id.lib == NULL) return; - if (wrld->id.us == 1) { - id_clear_lib_data(bmain, &wrld->id); + + if (!ID_IS_LINKED_DATABLOCK(wrld)) { return; } - - for (sce = bmain->scene.first; sce && ELEM(false, is_lib, is_local); sce = sce->id.next) { - if (sce->world == wrld) { - if (sce->id.lib) is_lib = true; - else is_local = true; + + BKE_library_ID_test_usages(bmain, wrld, &is_local, &is_lib); + + if (is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &wrld->id); + BKE_id_expand_local(&wrld->id); } - } + else { + World *wrld_new = BKE_world_copy(bmain, wrld); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &wrld->id); - } - else if (is_local && is_lib) { - World *wrld_new = BKE_world_copy(wrld); - wrld_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrld_new->id); - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->world == wrld) { - if (sce->id.lib == NULL) { - sce->world = wrld_new; - id_us_plus(&wrld_new->id); - id_us_min(&wrld->id); - } - } + wrld_new->id.us = 0; + + BKE_libblock_remap(bmain, wrld, wrld_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } |