diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2017-02-12 23:43:13 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2017-02-12 23:43:13 +0300 |
commit | 10b24eabbab0193f6944cdf3bec7b386c75d5445 (patch) | |
tree | 28cefb0f056191e09828cb79d2f7f728df4e2ead /source/blender/blenkernel/intern | |
parent | f754ce1c5e050d1637fe97d78f782d6a68da6c15 (diff) | |
parent | b104057d001d2472cc55c7fa51cff3275e331523 (diff) |
Merge branch 'blender2.8' into transform-manipulators
Conflicts:
source/blender/editors/interface/resources.c
source/blender/editors/space_view3d/view3d_intern.h
source/blender/editors/transform/transform_manipulator.c
source/blender/gpu/CMakeLists.txt
source/blender/gpu/intern/gpu_shader.c
Diffstat (limited to 'source/blender/blenkernel/intern')
40 files changed, 2741 insertions, 582 deletions
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index e0bbe345fc4..39f1db0b886 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -2216,6 +2216,12 @@ static void mesh_calc_modifiers( } } + /* Some modifiers, like datatransfer, may generate those data as temp layer, we do not want to keep them, + * as they are used by display code when available (i.e. even if autosmooth is disabled). */ + if (!do_loop_normals && CustomData_has_layer(&finaldm->loopData, CD_NORMAL)) { + CustomData_free_layers(&finaldm->loopData, CD_NORMAL, finaldm->numLoopData); + } + #ifdef WITH_GAMEENGINE /* NavMesh - this is a hack but saves having a NavMesh modifier */ if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) { @@ -2551,6 +2557,15 @@ static void editbmesh_calc_modifiers( /* same as mesh_calc_modifiers (if using loop normals, poly nors have already been computed). */ if (!do_loop_normals) { dm_ensure_display_normals(*r_final); + + /* Some modifiers, like datatransfer, may generate those data, we do not want to keep them, + * as they are used by display code when available (i.e. even if autosmooth is disabled). */ + if (CustomData_has_layer(&(*r_final)->loopData, CD_NORMAL)) { + CustomData_free_layers(&(*r_final)->loopData, CD_NORMAL, (*r_final)->numLoopData); + } + if (r_cage && CustomData_has_layer(&(*r_cage)->loopData, CD_NORMAL)) { + CustomData_free_layers(&(*r_cage)->loopData, CD_NORMAL, (*r_cage)->numLoopData); + } } /* add an orco layer if needed */ diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 2f65e71c6d2..237e4e80172 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -283,7 +283,7 @@ void animviz_get_object_motionpaths(Object *ob, ListBase *targets) /* tweak the object ordering to trick depsgraph into making MotionPath calculations run faster */ static void motionpaths_calc_optimise_depsgraph(Scene *scene, ListBase *targets) { - Base *base, *baseNext; + BaseLegacy *base, *baseNext; MPathTarget *mpt; /* make sure our temp-tag isn't already in use */ @@ -321,7 +321,7 @@ static void motionpaths_calc_update_scene(Scene *scene) BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); } else { /* otherwise we can optimize by restricting updates */ - Base *base, *last = NULL; + BaseLegacy *base, *last = NULL; /* only stuff that moves or needs display still */ DAG_scene_update_flags(G.main, scene, scene->lay, true, false); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 89e93a6384d..2565eb1900c 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1037,6 +1037,17 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float if (use_dverts) { defnrToPC = MEM_callocN(sizeof(*defnrToPC) * defbase_tot, "defnrToBone"); defnrToPCIndex = MEM_callocN(sizeof(*defnrToPCIndex) * defbase_tot, "defnrToIndex"); + /* TODO(sergey): Some considerations here: + * + * - Make it more generic function, maybe even keep together with chanhash. + * - Check whether keeping this consistent across frames gives speedup. + * - Don't use hash for small armatures. + */ + GHash *idx_hash = BLI_ghash_ptr_new("pose channel index by name"); + int pchan_index = 0; + for (pchan = armOb->pose->chanbase.first; pchan != NULL; pchan = pchan->next, ++pchan_index) { + BLI_ghash_insert(idx_hash, pchan, SET_INT_IN_POINTER(pchan_index)); + } for (i = 0, dg = target->defbase.first; dg; i++, dg = dg->next) { defnrToPC[i] = BKE_pose_channel_find_name(armOb->pose, dg->name); /* exclude non-deforming bones */ @@ -1045,10 +1056,11 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float defnrToPC[i] = NULL; } else { - defnrToPCIndex[i] = BLI_findindex(&armOb->pose->chanbase, defnrToPC[i]); + defnrToPCIndex[i] = GET_INT_FROM_POINTER(BLI_ghash_lookup(idx_hash, defnrToPC[i])); } } } + BLI_ghash_free(idx_hash, NULL, NULL); } } } diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index a8670395fc4..afd60102453 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -234,7 +234,7 @@ int BKE_blender_test_break(void) * \note Don't use MEM_mallocN so functions can be registered at any time. * \{ */ -struct AtExitData { +static struct AtExitData { struct AtExitData *next; void (*func)(void *user_data); diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 0d509ecea06..57b707a31d3 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -239,7 +239,7 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local) if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data(bmain, &brush->id); - BKE_id_expand_local(&brush->id); + BKE_id_expand_local(bmain, &brush->id); /* enable fake user by default */ id_fake_user_set(&brush->id); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 264d87b86f3..d0e0c82e3be 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -376,6 +376,45 @@ static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *r } } +#define V3_MUL_ELEM(a, b) \ + (a)[0] * (b)[0], \ + (a)[1] * (b)[1], \ + (a)[2] * (b)[2] + +/* Callback to bvh tree nearest edge to ray. + * The tree must have been built using bvhtree_from_mesh_edges. + * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */ +static void mesh_edges_nearest_to_ray( + void *userdata, const float ray_co[3], const float ray_dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct BVHTreeFromMesh *data = userdata; + const MVert *vert = data->vert; + const MEdge *e = &data->edge[index]; + + const float t0[3] = {V3_MUL_ELEM(vert[e->v1].co, scale)}; + const float t1[3] = {V3_MUL_ELEM(vert[e->v2].co, scale)}; + const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; + + float depth, point[3]; + const float dist_sq = dist_squared_ray_to_seg_v3(origin_sc, dir_sc, t0, t1, point, &depth); + + if (dist_sq < nearest->dist_sq) { + nearest->dist_sq = dist_sq; + nearest->index = index; + + point[0] /= scale[0]; + point[1] /= scale[1]; + point[2] /= scale[2]; + + copy_v3_v3(nearest->co, point); + sub_v3_v3v3(nearest->no, t0, t1); + } +} + +#undef V3_MUL_ELEM + /** \} */ /* @@ -393,8 +432,6 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( BMEditMesh *em, const int verts_num, const BLI_bitmap *verts_mask, int verts_num_active) { - BVHTree *tree = NULL; - int i; BM_mesh_elem_table_ensure(em->bm, BM_VERT); if (verts_mask) { BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); @@ -403,15 +440,14 @@ static BVHTree *bvhtree_from_editmesh_verts_create_tree( verts_num_active = verts_num; } - tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); if (tree) { - BMIter iter; - BMVert *eve; - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + for (int i = 0; i < verts_num; i++) { if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { continue; } + BMVert *eve = BM_vert_at_index(em->bm, i); BLI_bvhtree_insert(tree, i, eve->co, 1); } BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); @@ -426,28 +462,25 @@ static BVHTree *bvhtree_from_mesh_verts_create_tree( MVert *vert, const int verts_num, const BLI_bitmap *verts_mask, int verts_num_active) { - BVHTree *tree = NULL; - int i; - if (vert) { - if (verts_mask) { - BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); - } - else { - verts_num_active = verts_num; - } + BLI_assert(vert != NULL); + if (verts_mask) { + BLI_assert(IN_RANGE_INCL(verts_num_active, 0, verts_num)); + } + else { + verts_num_active = verts_num; + } - tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(verts_num_active, epsilon, tree_type, axis); - if (tree) { - for (i = 0; i < verts_num; i++) { - if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { - continue; - } - BLI_bvhtree_insert(tree, i, vert[i].co, 1); + if (tree) { + for (int i = 0; i < verts_num; i++) { + if (verts_mask && !BLI_BITMAP_TEST_BOOL(verts_mask, i)) { + continue; } - BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); - BLI_bvhtree_balance(tree); + BLI_bvhtree_insert(tree, i, vert[i].co, 1); } + BLI_assert(BLI_bvhtree_get_size(tree) == verts_num_active); + BLI_bvhtree_balance(tree); } return tree; @@ -488,11 +521,9 @@ BVHTree *bvhtree_from_editmesh_verts_ex( const BLI_bitmap *verts_mask, int verts_num_active, float epsilon, int tree_type, int axis) { - int vert_num = em->bm->totvert; - BVHTree *tree = bvhtree_from_editmesh_verts_create_tree( epsilon, tree_type, axis, - em, vert_num, verts_mask, verts_num_active); + em, em->bm->totvert, verts_mask, verts_num_active); if (tree) { memset(data, 0, sizeof(*data)); @@ -505,6 +536,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex( return tree; } + BVHTree *bvhtree_from_editmesh_verts( BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis) @@ -515,8 +547,8 @@ BVHTree *bvhtree_from_editmesh_verts( epsilon, tree_type, axis); } - -/* Builds a bvh tree where nodes are the vertices of the given dm */ +/* Builds a bvh tree where nodes are the vertices of the given dm + * and stores the BVHTree in dm->bvhCache */ BVHTree *bvhtree_from_mesh_verts( BVHTreeFromMesh *data, DerivedMesh *dm, float epsilon, int tree_type, int axis) @@ -557,7 +589,8 @@ BVHTree *bvhtree_from_mesh_verts( } /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_verts_setup_data(data, tree, true, epsilon, vert, vert_allocated); + bvhtree_from_mesh_verts_setup_data( + data, tree, true, epsilon, vert, vert_allocated); return data->tree; } @@ -577,7 +610,8 @@ BVHTree *bvhtree_from_mesh_verts_ex( epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active); /* Setup BVHTreeFromMesh */ - bvhtree_from_mesh_verts_setup_data(data, tree, false, epsilon, vert, vert_allocated); + bvhtree_from_mesh_verts_setup_data( + data, tree, false, epsilon, vert, vert_allocated); return data->tree; } @@ -595,8 +629,6 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( 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)); @@ -605,9 +637,10 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( edges_num_active = edges_num; } - tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); if (tree) { + int i; BMIter iter; BMEdge *eed; BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) { @@ -627,6 +660,70 @@ static BVHTree *bvhtree_from_editmesh_edges_create_tree( return tree; } +static BVHTree *bvhtree_from_mesh_edges_create_tree( + MVert *vert, MEdge *edge, const int edge_num, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + if (edges_mask) { + BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edge_num)); + } + else { + edges_num_active = edge_num; + } + BLI_assert(vert != NULL); + BLI_assert(edge != NULL); + + /* Create a bvh-tree of the given target */ + BVHTree *tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + if (tree) { + for (int i = 0; i < edge_num; i++) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], vert[edge[i].v1].co); + copy_v3_v3(co[1], vert[edge[i].v2].co); + + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_bvhtree_balance(tree); + } + + return tree; +} + +static void bvhtree_from_mesh_edges_setup_data( + BVHTreeFromMesh *data, BVHTree *tree, const bool is_cached, float epsilon, + MVert *vert, const bool vert_allocated, MEdge *edge, const bool edge_allocated) +{ + memset(data, 0, sizeof(*data)); + data->tree = tree; + + if (data->tree) { + data->cached = is_cached; + + data->nearest_callback = mesh_edges_nearest_point; + data->raycast_callback = mesh_edges_spherecast; + data->nearest_to_ray_callback = mesh_edges_nearest_to_ray; + + data->vert = vert; + data->vert_allocated = vert_allocated; + data->edge = edge; + data->edge_allocated = edge_allocated; + + data->sphere_radius = epsilon; + } + else { + if (vert_allocated) { + MEM_freeN(vert); + } + if (edge_allocated) { + MEM_freeN(edge); + } + } +} + /* Builds a bvh tree where nodes are the edges of the given em */ BVHTree *bvhtree_from_editmesh_edges_ex( BVHTreeFromEditMesh *data, BMEditMesh *em, @@ -651,6 +748,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex( return tree; } + BVHTree *bvhtree_from_editmesh_edges( BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis) @@ -683,27 +781,13 @@ BVHTree *bvhtree_from_mesh_edges( BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_EDGES); if (tree == NULL) { - int i; - int numEdges = dm->getNumEdges(dm); - - if (vert != NULL && edge != NULL) { - /* Create a bvh-tree of the given target */ - tree = BLI_bvhtree_new(numEdges, epsilon, tree_type, axis); - if (tree != NULL) { - for (i = 0; i < numEdges; i++) { - float co[2][3]; - copy_v3_v3(co[0], vert[edge[i].v1].co); - copy_v3_v3(co[1], vert[edge[i].v2].co); - - BLI_bvhtree_insert(tree, i, co[0], 2); - } - BLI_bvhtree_balance(tree); + tree = bvhtree_from_mesh_edges_create_tree( + vert, edge, dm->getNumEdges(dm), + NULL, -1, epsilon, tree_type, axis); - /* Save on cache for later use */ - /* printf("BVHTree built and saved on cache\n"); */ - bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); - } - } + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(&dm->bvhCache, tree, BVHTREE_FROM_EDGES); } BLI_rw_mutex_unlock(&cache_rwlock); } @@ -711,33 +795,34 @@ BVHTree *bvhtree_from_mesh_edges( /* printf("BVHTree is already build, using cached tree\n"); */ } - /* Setup BVHTreeFromMesh */ - memset(data, 0, sizeof(*data)); - data->tree = tree; + bvhtree_from_mesh_edges_setup_data( + data, tree, true, epsilon, vert, vert_allocated, edge, edge_allocated); - if (data->tree) { - data->cached = true; + return data->tree; +} - data->nearest_callback = mesh_edges_nearest_point; - data->raycast_callback = mesh_edges_spherecast; - data->nearest_to_ray_callback = NULL; +/** + * Builds a bvh tree where nodes are the given edges . + * \param vert/edge_allocated if true, elem freeing will be done when freeing data. + * \param edges_mask if not null, true elements give which vert to add to BVH tree. + * \param edges_num_active if >= 0, number of active edges to add to BVH tree (else will be computed from mask). + */ +BVHTree *bvhtree_from_mesh_edges_ex( + BVHTreeFromMesh *data, + MVert *vert, const bool vert_allocated, + MEdge *edge, const int edges_num, const bool edge_allocated, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + BVHTree *tree = bvhtree_from_mesh_edges_create_tree( + vert, edge, edges_num, edges_mask, edges_num_active, + epsilon, tree_type, axis); - data->vert = vert; - data->vert_allocated = vert_allocated; - data->edge = edge; - data->edge_allocated = edge_allocated; + /* Setup BVHTreeFromMesh */ + bvhtree_from_mesh_edges_setup_data( + data, tree, false, epsilon, vert, vert_allocated, edge, edge_allocated); - data->sphere_radius = epsilon; - } - else { - if (vert_allocated) { - MEM_freeN(vert); - } - if (edge_allocated) { - MEM_freeN(edge); - } - } return data->tree; } diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index deeb35bd880..8630e8562b0 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -205,7 +205,7 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f /* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { Object *ob = base->object; ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); @@ -215,7 +215,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) if (cache_file == mcmd->cache_file) { #ifdef WITH_ALEMBIC - CacheReader_free(mcmd->reader); + if (mcmd->reader != NULL) { + CacheReader_free(mcmd->reader); + } #endif mcmd->reader = NULL; mcmd->object_path[0] = '\0'; @@ -231,7 +233,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) if (cache_file == data->cache_file) { #ifdef WITH_ALEMBIC - CacheReader_free(data->reader); + if (data->reader != NULL) { + CacheReader_free(data->reader); + } #endif data->reader = NULL; data->object_path[0] = '\0'; diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 9cb553aa27b..978204f1cf5 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -853,7 +853,7 @@ static Object *camera_multiview_advanced(Scene *scene, Object *camera, const cha } if (name[0] != '\0') { - Base *base = BKE_scene_base_find_by_name(scene, name); + BaseLegacy *base = BKE_scene_base_find_by_name(scene, name); if (base) { return base->object; } diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index f2dd2a3fcf6..483fa977aff 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -2398,21 +2398,28 @@ DerivedMesh *CDDM_from_editbmesh(BMEditMesh *em, const bool use_mdisps, const bo use_tessface, em->tottri, (const BMLoop *(*)[3])em->looptris); } -static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) +static DerivedMesh *cddm_copy_ex(DerivedMesh *source, + const bool need_tessface_data, + const bool faces_from_tessfaces) { + const bool copy_tessface_data = (faces_from_tessfaces || need_tessface_data); CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm"); DerivedMesh *dm = &cddm->dm; int numVerts = source->numVertData; int numEdges = source->numEdgeData; - int numTessFaces = source->numTessFaceData; + int numTessFaces = copy_tessface_data ? source->numTessFaceData : 0; int numLoops = source->numLoopData; int numPolys = source->numPolyData; + /* NOTE: Don't copy tessellation faces if not requested explicitly. */ + /* ensure these are created if they are made on demand */ source->getVertDataArray(source, CD_ORIGINDEX); source->getEdgeDataArray(source, CD_ORIGINDEX); - source->getTessFaceDataArray(source, CD_ORIGINDEX); source->getPolyDataArray(source, CD_ORIGINDEX); + if (copy_tessface_data) { + source->getTessFaceDataArray(source, CD_ORIGINDEX); + } /* this initializes dm, and copies all non mvert/medge/mface layers */ DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numTessFaces, @@ -2421,23 +2428,33 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) dm->cd_flag = source->cd_flag; dm->dirty = source->dirty; + /* Tessellation data is never copied, so tag it here. */ + dm->dirty |= DM_DIRTY_TESS_CDLAYERS; + CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts); CustomData_copy_data(&source->edgeData, &dm->edgeData, 0, 0, numEdges); - CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces); + if (copy_tessface_data) { + CustomData_copy_data(&source->faceData, &dm->faceData, 0, 0, numTessFaces); + } /* now add mvert/medge/mface layers */ cddm->mvert = source->dupVertArray(source); cddm->medge = source->dupEdgeArray(source); - cddm->mface = source->dupTessFaceArray(source); CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts); CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges); - CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces); - - if (!faces_from_tessfaces) + + if (faces_from_tessfaces || copy_tessface_data) { + cddm->mface = source->dupTessFaceArray(source); + CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numTessFaces); + } + + if (!faces_from_tessfaces) { DM_DupPolys(source, dm); - else + } + else { CDDM_tessfaces_to_faces(dm); + } cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP); cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY); @@ -2447,12 +2464,17 @@ static DerivedMesh *cddm_copy_ex(DerivedMesh *source, int faces_from_tessfaces) DerivedMesh *CDDM_copy(DerivedMesh *source) { - return cddm_copy_ex(source, 0); + return cddm_copy_ex(source, false, false); } DerivedMesh *CDDM_copy_from_tessface(DerivedMesh *source) { - return cddm_copy_ex(source, 1); + return cddm_copy_ex(source, false, true); +} + +DerivedMesh *CDDM_copy_with_tessface(DerivedMesh *source) +{ + return cddm_copy_ex(source, true, false); } /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c new file mode 100644 index 00000000000..289586153ea --- /dev/null +++ b/source/blender/blenkernel/intern/collection.c @@ -0,0 +1,453 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/collection.c + * \ingroup bke + */ + +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_iterator.h" +#include "BLI_listbase.h" +#include "BLT_translation.h" +#include "BLI_string_utils.h" + +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_scene.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +/** + * Add a collection to a collection ListBase and syncronize all render layers + * The ListBase is NULL when the collection is to be added to the master collection + */ +SceneCollection *BKE_collection_add(Scene *scene, SceneCollection *sc_parent, const char *name) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc = MEM_callocN(sizeof(SceneCollection), "New Collection"); + + if (!name) { + name = DATA_("New Collection"); + } + + if (!sc_parent) { + sc_parent = sc_master; + } + + BLI_strncpy(sc->name, name, sizeof(sc->name)); + BLI_uniquename(&sc_master->scene_collections, sc, DATA_("Collection"), '.', offsetof(SceneCollection, name), sizeof(sc->name)); + + BLI_addtail(&sc_parent->scene_collections, sc); + + BKE_layer_sync_new_scene_collection(scene, sc_parent, sc); + return sc; +} + +/** + * Free the collection items recursively + */ +static void collection_free(SceneCollection *sc) +{ + for (LinkData *link = sc->objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->objects); + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + id_us_min(link->data); + } + BLI_freelistN(&sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + collection_free(nsc); + } + BLI_freelistN(&sc->scene_collections); +} + +/** + * Unlink the collection recursively + * return true if unlinked + */ +static bool collection_remlink(SceneCollection *sc_parent, SceneCollection *sc_gone) +{ + for (SceneCollection *sc = sc_parent->scene_collections.first; sc; sc = sc->next) + { + if (sc == sc_gone) { + BLI_remlink(&sc_parent->scene_collections, sc_gone); + return true; + } + + if (collection_remlink(sc, sc_gone)) { + return true; + } + } + return false; +} + +/** + * Recursively remove any instance of this SceneCollection + */ +static void layer_collection_remove(SceneLayer *sl, ListBase *lb, const SceneCollection *sc) +{ + LayerCollection *lc = lb->first; + while(lc) { + if (lc->scene_collection == sc) { + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); + BKE_layer_collection_free(sl, lc); + BLI_remlink(lb, lc); + + LayerCollection *lc_next = lc->next; + MEM_freeN(lc); + lc = lc_next; + + /* only the "top-level" layer collections may have the + * same SceneCollection in a sibling tree. + */ + if (lb != &sl->layer_collections) { + return; + } + } + + else { + layer_collection_remove(sl, &lc->layer_collections, sc); + lc = lc->next; + } + } +} + +/** + * Remove a collection from the scene, and syncronize all render layers + */ +bool BKE_collection_remove(Scene *scene, SceneCollection *sc) +{ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* the master collection cannot be removed */ + if (sc == sc_master) { + return false; + } + + /* unlink from the respective collection tree */ + if (!collection_remlink(sc_master, sc)) { + BLI_assert(false); + } + + /* clear the collection items */ + collection_free(sc); + + /* check all layers that use this collection and clear them */ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + layer_collection_remove(sl, &sl->layer_collections, sc); + BKE_scene_layer_base_flag_recalculate(sl); + sl->active_collection = 0; + } + + MEM_freeN(sc); + return true; +} + +/** + * Returns the master collection + */ +SceneCollection *BKE_collection_master(Scene *scene) +{ + return scene->collection; +} + +/** + * Free (or release) any data used by the master collection (does not free the master collection itself). + * Used only to clear the entire scene data since it's not doing re-syncing of the LayerCollection tree + */ +void BKE_collection_master_free(Scene *scene){ + collection_free(BKE_collection_master(scene)); +} + +static void collection_object_add(Scene *scene, SceneCollection *sc, Object *ob) +{ + BLI_addtail(&sc->objects, BLI_genericNodeN(ob)); + id_us_plus((ID *)ob); + BKE_layer_sync_object_link(scene, sc, ob); +} + +/** + * Add object to collection + */ +void BKE_collection_object_add(Scene *scene, SceneCollection *sc, Object *ob) +{ + if (BLI_findptr(&sc->objects, ob, offsetof(LinkData, data))) { + /* don't add the same object twice */ + return; + } + collection_object_add(scene, sc, ob); +} + +/** + * Add object to all collections that reference objects is in + * (used to copy objects) + */ +void BKE_collection_object_add_from(Scene *scene, Object *ob_src, Object *ob_dst) +{ + SceneCollection *sc; + FOREACH_SCENE_COLLECTION(scene, sc) + { + if (BLI_findptr(&sc->objects, ob_src, offsetof(LinkData, data))) { + collection_object_add(scene, sc, ob_dst); + } + } + FOREACH_SCENE_COLLECTION_END +} + +/** + * Remove object from collection + */ +void BKE_collection_object_remove(Main *bmain, Scene *scene, SceneCollection *sc, Object *ob, const bool free_us) +{ + + LinkData *link = BLI_findptr(&sc->objects, ob, offsetof(LinkData, data)); + + if (link == NULL) { + return; + } + + BLI_remlink(&sc->objects, link); + MEM_freeN(link); + + TODO_LAYER_SYNC_FILTER; /* need to remove all instances of ob in scene collections -> filter_objects */ + BKE_layer_sync_object_unlink(scene, sc, ob); + + if (free_us) { + BKE_libblock_free_us(bmain, ob); + } + else { + id_us_min(&ob->id); + } +} + +/** + * Remove object from all collections of scene + */ +void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const bool free_us) +{ + BKE_scene_remove_rigidbody_object(scene, ob); + + SceneCollection *sc; + FOREACH_SCENE_COLLECTION(scene, sc) + { + BKE_collection_object_remove(bmain, scene, sc, ob, free_us); + } + FOREACH_SCENE_COLLECTION_END +} + +/* ---------------------------------------------------------------------- */ +/* Iteractors */ +/* scene collection iteractor */ + +typedef struct SceneCollectionsIteratorData { + Scene *scene; + void **array; + int tot, cur; + } SceneCollectionsIteratorData; + +static void scene_collection_callback(SceneCollection *sc, BKE_scene_collections_Cb callback, void *data) +{ + callback(sc, data); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_callback(nsc, callback, data); + } +} + +static void scene_collections_count(SceneCollection *UNUSED(sc), void *data) +{ + int *tot = data; + (*tot)++; +} + +static void scene_collections_build_array(SceneCollection *sc, void *data) +{ + SceneCollection ***array = data; + **array = sc; + (*array)++; +} + +static void scene_collections_array(Scene *scene, SceneCollection ***collections_array, int *tot) +{ + SceneCollection *sc = BKE_collection_master(scene); + SceneCollection **array; + + *collections_array = NULL; + *tot = 0; + + if (scene == NULL) + return; + + scene_collection_callback(sc, scene_collections_count, tot); + + if (*tot == 0) + return; + + *collections_array = array = MEM_mallocN(sizeof(SceneCollection *) * (*tot), "SceneCollectionArray"); + scene_collection_callback(sc, scene_collections_build_array, &array); +} + +/** + * Only use this in non-performance critical situations + * (it iterates over all scene collections twice) + */ +void BKE_scene_collections_Iterator_begin(Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneCollectionsIteratorData *data = MEM_callocN(sizeof(SceneCollectionsIteratorData), __FUNCTION__); + + data->scene = scene; + iter->data = data; + + scene_collections_array(scene, (SceneCollection ***)&data->array, &data->tot); + BLI_assert(data->tot != 0); + + data->cur = 0; + iter->current = data->array[data->cur]; + iter->valid = true; +} + +void BKE_scene_collections_Iterator_next(struct Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (++data->cur < data->tot) { + iter->current = data->array[data->cur]; + } + else { + iter->valid = false; + } +} + +void BKE_scene_collections_Iterator_end(struct Iterator *iter) +{ + SceneCollectionsIteratorData *data = iter->data; + + if (data) { + if (data->array) { + MEM_freeN(data->array); + } + MEM_freeN(data); + } + iter->valid = false; +} + + +/* scene objects iteractor */ + +typedef struct SceneObjectsIteratorData { + GSet *visited; + LinkData *link; + Iterator scene_collection_iter; +} SceneObjectsIteratorData; + +void BKE_scene_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + Scene *scene = data_in; + SceneObjectsIteratorData *data = MEM_callocN(sizeof(SceneObjectsIteratorData), __FUNCTION__); + iter->data = data; + + /* lookup list ot make sure each object is object called once */ + data->visited = BLI_gset_ptr_new(__func__); + + /* we wrap the scenecollection iterator here to go over the scene collections */ + BKE_scene_collections_Iterator_begin(&data->scene_collection_iter, scene); + + SceneCollection *sc = data->scene_collection_iter.current; + iter->current = sc->objects.first; + iter->valid = true; + + if (iter->current == NULL) { + BKE_scene_objects_Iterator_next(iter); + } +} + +/** + * Gets the first unique object in the sequence + */ +static LinkData *object_base_unique(GSet *gs, LinkData *link) +{ + if (link == NULL) { + return NULL; + } + + Object *ob = link->data; + if (!BLI_gset_haskey(gs, ob)) { + BLI_gset_add(gs, ob); + return link; + } + else { + return object_base_unique(gs, link->next); + } +} + +void BKE_scene_objects_Iterator_next(Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + LinkData *link = data->link ? object_base_unique(data->visited, data->link->next) : NULL; + + if (link) { + data->link = link; + iter->current = link->data; + } + else { + /* if this is the last object of this ListBase look at the next SceneCollection */ + SceneCollection *sc; + BKE_scene_collections_Iterator_next(&data->scene_collection_iter); + do { + sc = data->scene_collection_iter.current; + /* get the first unique object of this collection */ + LinkData *new_link = object_base_unique(data->visited, sc->objects.first); + if (new_link) { + data->link = new_link; + iter->current = data->link->data; + return; + } + BKE_scene_collections_Iterator_next(&data->scene_collection_iter); + } while (data->scene_collection_iter.valid); + + if (!data->scene_collection_iter.valid) { + iter->valid = false; + } + } +} + +void BKE_scene_objects_Iterator_end(Iterator *iter) +{ + SceneObjectsIteratorData *data = iter->data; + if (data) { + BKE_scene_collections_Iterator_end(&data->scene_collection_iter); + BLI_gset_free(data->visited, NULL); + MEM_freeN(data); + } +} diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index ee25be36855..b5f76240c0b 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -514,7 +514,7 @@ static void add_collision_object(Object ***objs, unsigned int *numobj, unsigned // collision object will exclude self Object **get_collisionobjects_ext(Scene *scene, Object *self, Group *group, int layer, unsigned int *numcollobj, unsigned int modifier_type, bool dupli) { - Base *base; + BaseLegacy *base; Object **objs; GroupObject *go; unsigned int numobj= 0, maxobj= 100; @@ -596,7 +596,7 @@ ListBase *get_collider_cache(Scene *scene, Object *self, Group *group) } else { Scene *sce_iter; - Base *base; + BaseLegacy *base; /* add objects in same layer in scene */ for (SETLOOPER(scene, sce_iter, base)) { diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 4c01bfd35f2..a7c53dda8c7 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -47,6 +47,7 @@ #include "BLT_translation.h" #include "BKE_context.h" +#include "BKE_layer.h" #include "BKE_main.h" #include "BKE_screen.h" #include "BKE_sound.h" @@ -814,6 +815,14 @@ struct SpaceClip *CTX_wm_space_clip(const bContext *C) return NULL; } +struct SpaceCollections *CTX_wm_space_collections(const bContext *C) +{ + ScrArea *sa = CTX_wm_area(C); + if (sa && sa->spacetype == SPACE_COLLECTIONS) + return sa->spacedata.first; + return NULL; +} + void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) { C->wm.manager = wm; @@ -836,8 +845,9 @@ void CTX_wm_window_set(bContext *C, wmWindow *win) void CTX_wm_screen_set(bContext *C, bScreen *screen) { C->wm.screen = screen; - if (C->wm.screen) - C->data.scene = C->wm.screen->scene; + if (C->wm.screen) { + CTX_data_scene_set(C, C->wm.screen->scene); + } C->wm.area = NULL; C->wm.region = NULL; } @@ -896,6 +906,59 @@ Scene *CTX_data_scene(const bContext *C) return C->data.scene; } +SceneLayer *CTX_data_scene_layer(const bContext *C) +{ + SceneLayer *sl; + + if (ctx_data_pointer_verify(C, "render_layer", (void *)&sl)) { + return sl; + } + else { + return BKE_scene_layer_active(CTX_data_scene(C)); + } +} + +/** + * This is tricky. Sometimes the user overrides the render_layer + * but not the scene_collection. In this case what to do? + * + * If the scene_collection is linked to the SceneLayer we use it. + * Otherwise we fallback to the active one of the SceneLayer. + */ +LayerCollection *CTX_data_layer_collection(const bContext *C) +{ + SceneLayer *sl = CTX_data_scene_layer(C); + LayerCollection *lc; + + if (ctx_data_pointer_verify(C, "layer_collection", (void *)&lc)) { + if (BKE_scene_layer_has_collection(sl, lc->scene_collection)) { + return lc; + } + } + + /* fallback */ + return BKE_layer_collection_active(sl); +} + +SceneCollection *CTX_data_scene_collection(const bContext *C) +{ + SceneCollection *sc; + if (ctx_data_pointer_verify(C, "scene_collection", (void *)&sc)) { + if (BKE_scene_layer_has_collection(CTX_data_scene_layer(C), sc)) { + return sc; + } + } + + LayerCollection *lc = CTX_data_layer_collection(C); + if (lc) { + return lc->scene_collection; + } + + /* fallback */ + Scene *scene = CTX_data_scene(C); + return BKE_collection_master(scene); +} + int CTX_data_mode_enum(const bContext *C) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 98d37fb07bf..c9f0b8ec9ca 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -2595,7 +2595,7 @@ bool CustomData_from_bmeshpoly_test(CustomData *fdata, CustomData *pdata, Custom if (!LAYER_CMP(ldata, CD_TANGENT, fdata, CD_TANGENT)) return false; -#undef TEST_RET +#undef LAYER_CMP /* if no layers are on either CustomData's, * then there was nothing to do... */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index bc9871aee54..39d06a13e6e 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -488,7 +488,7 @@ static void scene_setSubframe(Scene *scene, float subframe) static int surface_getBrushFlags(DynamicPaintSurface *surface, const Scene *scene) { - Base *base = NULL; + BaseLegacy *base = NULL; GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; @@ -5780,7 +5780,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su * Loop through surface's target paint objects and do painting */ { - Base *base = NULL; + BaseLegacy *base = NULL; GroupObject *go = NULL; Object *brushObj = NULL; ModifierData *md = NULL; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index fe8f5ebdca6..668d4d6c9e2 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -209,7 +209,7 @@ static void add_particles_to_effectors(ListBase **effectors, Scene *scene, Effec ListBase *pdInitEffectors(Scene *scene, Object *ob_src, ParticleSystem *psys_src, EffectorWeights *weights, bool for_simulation) { - Base *base; + BaseLegacy *base; unsigned int layer= ob_src->lay; ListBase *effectors = NULL; diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index 9b011dbb003..9c81a8b49be 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -130,18 +130,11 @@ static bool group_object_add_internal(Group *group, Object *ob) return true; } -bool BKE_group_object_add(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_add(Group *group, Object *object) { if (group_object_add_internal(group, object)) { if ((object->flag & OB_FROMGROUP) == 0) { - - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag |= OB_FROMGROUP; - - if (base) - base->flag |= OB_FROMGROUP; } return true; } @@ -208,18 +201,12 @@ bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group) return group_object_cyclic_check_internal(object, group); } -bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base) +bool BKE_group_object_unlink(Group *group, Object *object) { if (group_object_unlink_internal(group, object)) { /* object can be NULL */ if (object && BKE_group_object_find(NULL, object) == NULL) { - if (scene && base == NULL) - base = BKE_scene_base_find(scene, object); - object->flag &= ~OB_FROMGROUP; - - if (base) - base->flag &= ~OB_FROMGROUP; } return true; } diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index d098366aef4..69a2067f4e6 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -174,15 +174,10 @@ void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool lib_local) void BKE_lamp_free(Lamp *la) { - MTex *mtex; int a; for (a = 0; a < MAX_MTEX; a++) { - mtex = la->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(la->mtex[a]); } BKE_animdata_free((ID *)la, false); @@ -193,6 +188,7 @@ void BKE_lamp_free(Lamp *la) if (la->nodetree) { ntreeFreeTree(la->nodetree); MEM_freeN(la->nodetree); + la->nodetree = NULL; } BKE_previewimg_free(&la->preview); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c new file mode 100644 index 00000000000..ef4816af54d --- /dev/null +++ b/source/blender/blenkernel/intern/layer.c @@ -0,0 +1,1096 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/blenkernel/intern/layer.c + * \ingroup bke + */ + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLT_translation.h" + +#include "BKE_layer.h" +#include "BKE_collection.h" +#include "BKE_layer.h" +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DNA_ID.h" +#include "DNA_layer_types.h" +#include "DNA_object_types.h" +#include "DNA_node_types.h" +#include "DNA_scene_types.h" + +#include "MEM_guardedalloc.h" + +/* prototype */ +struct CollectionEngineSettingsCB_Type; +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc); +static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc); +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); +static CollectionEngineSettings *collection_engine_settings_create(struct CollectionEngineSettingsCB_Type *ces_type); +static void layer_collection_engine_settings_free(LayerCollection *lc); +static void layer_collection_create_engine_settings(LayerCollection *lc); +static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob, const char *engine_name); +static void object_bases_Iterator_next(Iterator *iter, const int flag); + +/* RenderLayer */ + +/** + * Returns the SceneLayer to be used for rendering + */ +SceneLayer *BKE_scene_layer_active(struct Scene *scene) +{ + SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer); + BLI_assert(sl); + return sl; +} + +/** + * Add a new renderlayer + * by default, a renderlayer has the master collection + */ +SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name) +{ + if (!name) { + name = DATA_("Render Layer"); + } + + SceneLayer *sl = MEM_callocN(sizeof(SceneLayer), "Scene Layer"); + sl->flag |= SCENE_LAYER_RENDER; + + BLI_addtail(&scene->render_layers, sl); + + /* unique name */ + BLI_strncpy_utf8(sl->name, name, sizeof(sl->name)); + BLI_uniquename(&scene->render_layers, sl, DATA_("SceneLayer"), '.', offsetof(SceneLayer, name), sizeof(sl->name)); + + SceneCollection *sc = BKE_collection_master(scene); + layer_collection_add(sl, &sl->layer_collections, sc); + + return sl; +} + +bool BKE_scene_layer_remove(Main *bmain, Scene *scene, SceneLayer *sl) +{ + const int act = BLI_findindex(&scene->render_layers, sl); + + if (act == -1) { + return false; + } + else if ( (scene->render_layers.first == scene->render_layers.last) && + (scene->render_layers.first == sl)) + { + /* ensure 1 layer is kept */ + return false; + } + + BLI_remlink(&scene->render_layers, sl); + + BKE_scene_layer_free(sl); + MEM_freeN(sl); + + scene->active_layer = 0; + /* TODO WORKSPACE: set active_layer to 0 */ + + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + if (sce->nodetree) { + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act); + } + } + + return true; +} + +/** + * Free (or release) any data used by this SceneLayer (does not free the SceneLayer itself). + */ +void BKE_scene_layer_free(SceneLayer *sl) +{ + sl->basact = NULL; + BLI_freelistN(&sl->object_bases); + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_free(NULL, lc); + } + BLI_freelistN(&sl->layer_collections); +} + +/** + * Set the render engine of a renderlayer + */ +void BKE_scene_layer_engine_set(SceneLayer *sl, const char *engine) +{ + BLI_strncpy_utf8(sl->engine, engine, sizeof(sl->engine)); +} + +/** + * Tag all the selected objects of a renderlayer + */ +void BKE_scene_layer_selected_objects_tag(SceneLayer *sl, const int tag) +{ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + base->object->flag |= tag; + } + else { + base->object->flag &= ~tag; + } + } +} + +static bool find_scene_collection_in_scene_collections(ListBase *lb, const LayerCollection *lc) +{ + for (LayerCollection *lcn = lb->first; lcn; lcn = lcn->next) { + if (lcn == lc) { + return true; + } + if (find_scene_collection_in_scene_collections(&lcn->layer_collections, lc)) { + return true; + } + } + return false; +} + +/** + * Find the SceneLayer a LayerCollection belongs to + */ +SceneLayer *BKE_scene_layer_find_from_collection(Scene *scene, LayerCollection *lc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + if (find_scene_collection_in_scene_collections(&sl->layer_collections, lc)) { + return sl; + } + } + return NULL; +} + +/* Base */ + +Base *BKE_scene_layer_base_find(SceneLayer *sl, Object *ob) +{ + return BLI_findptr(&sl->object_bases, ob, offsetof(Base, object)); +} + +void BKE_scene_layer_base_deselect_all(SceneLayer *sl) +{ + Base *base; + + for (base = sl->object_bases.first; base; base = base->next) { + base->flag &= ~BASE_SELECTED; + } +} + +void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase) +{ + sl->basact = selbase; + if ((selbase->flag & BASE_SELECTABLED) != 0) { + selbase->flag |= BASE_SELECTED; + } +} + +static void scene_layer_object_base_unref(SceneLayer* sl, Base *base) +{ + base->refcount--; + + /* It only exists in the RenderLayer */ + if (base->refcount == 0) { + if (sl->basact == base) { + sl->basact = NULL; + } + + BLI_remlink(&sl->object_bases, base); + MEM_freeN(base); + } +} + +static void layer_collection_base_flag_recalculate(LayerCollection *lc, const bool tree_is_visible, const bool tree_is_selectable) +{ + bool is_visible = tree_is_visible && ((lc->flag & COLLECTION_VISIBLE) != 0); + /* an object can only be selected if it's visible */ + bool is_selectable = tree_is_selectable && is_visible && ((lc->flag & COLLECTION_SELECTABLE) != 0); + + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + Base *base = link->data; + + if (is_visible) { + base->flag |= BASE_VISIBLED; + } + else { + base->flag &= ~BASE_VISIBLED; + } + + if (is_selectable) { + base->flag |= BASE_SELECTABLED; + } + else { + base->flag &= ~BASE_SELECTABLED; + } + } + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + layer_collection_base_flag_recalculate(lcn, is_visible, is_selectable); + } +} + +/** + * Re-evaluate the ObjectBase flags for SceneLayer + */ +void BKE_scene_layer_base_flag_recalculate(SceneLayer *sl) +{ + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_base_flag_recalculate(lc, true, true); + } + + /* if base is not selectabled, clear select */ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) == 0) { + base->flag &= ~BASE_SELECTED; + } + } +} + +/** + * Tag Scene Layer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_recalculate(SceneLayer *sl) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + for (Base *base = sl->object_bases.first; base; base = base->next) { + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } +} + +/** + * Tag Object in SceneLayer to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_object_recalculate(SceneLayer *sl, Object *ob) +{ + Base *base = BLI_findptr(&sl->object_bases, ob, offsetof(Base, object)); + if (base) { + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } +} + +/** + * Tag all Objects in LayerCollection to recalculation + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_collection_recalculate(SceneLayer *sl, LayerCollection *lc) +{ + sl->flag |= SCENE_LAYER_ENGINE_DIRTY; + + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + Base *base = (Base *)link->data; + base->flag |= BASE_DIRTY_ENGINE_SETTINGS; + } + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + BKE_scene_layer_engine_settings_collection_recalculate(sl, lcn); + } +} + +/** + * Re-calculate the engine settings for all the objects in SceneLayer + * + * Temporary function, waiting for real depsgraph + */ +void BKE_scene_layer_engine_settings_update(struct SceneLayer *sl, const char *engine_name) +{ + if ((sl->flag & SCENE_LAYER_ENGINE_DIRTY) == 0) { + return; + } + + /* do the complete settings update */ + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_DIRTY_ENGINE_SETTINGS) != 0) && \ + (base->flag & BASE_VISIBLED) != 0) + { + scene_layer_engine_settings_update(sl, base->object, engine_name); + base->flag &= ~BASE_DIRTY_ENGINE_SETTINGS; + } + } + + sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY; +} + +/** + * Return the base if existent, or create it if necessary + * Always bump the refcount + */ +static Base *object_base_add(SceneLayer *sl, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + if (base == NULL) { + base = MEM_callocN(sizeof(Base), "Object Base"); + + /* do not bump user count, leave it for SceneCollections */ + base->object = ob; + BLI_addtail(&sl->object_bases, base); + } + base->refcount++; + return base; +} + +/* LayerCollection */ + +/** + * When freeing the entire SceneLayer at once we don't bother with unref + * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree + */ +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + if (sl) { + for (LinkData *link = lc->object_bases.first; link; link = link->next) { + scene_layer_object_base_unref(sl, link->data); + } + } + + BLI_freelistN(&lc->object_bases); + BLI_freelistN(&lc->overrides); + layer_collection_engine_settings_free(lc); + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_free(sl, nlc); + } + + BLI_freelistN(&lc->layer_collections); +} + +/** + * Free (or release) LayerCollection from SceneLayer + * (does not free the LayerCollection itself). + */ +void BKE_layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_free(sl, lc); +} + +/* LayerCollection */ + +/** + * Recursively get the collection for a given index + */ +static LayerCollection *collection_from_index(ListBase *lb, const int number, int *i) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + if (*i == number) { + return lc; + } + + (*i)++; + + LayerCollection *lc_nested = collection_from_index(&lc->layer_collections, number, i); + if (lc_nested) { + return lc_nested; + } + } + return NULL; +} + +/** + * Get the active collection + */ +LayerCollection *BKE_layer_collection_active(SceneLayer *sl) +{ + int i = 0; + return collection_from_index(&sl->layer_collections, sl->active_collection, &i); +} + +/** + * Recursively get the count of collections + */ +static int collection_count(ListBase *lb) +{ + int i = 0; + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + i += collection_count(&lc->layer_collections) + 1; + } + return i; +} + +/** + * Get the total number of collections + * (including all the nested collections) + */ +int BKE_layer_collection_count(SceneLayer *sl) +{ + return collection_count(&sl->layer_collections); +} + +/** + * Recursively get the index for a given collection + */ +static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i) +{ + for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { + if (lcol == lc) { + return *i; + } + + (*i)++; + + int i_nested = index_from_collection(&lcol->layer_collections, lc, i); + if (i_nested != -1) { + return i_nested; + } + } + return -1; +} + +/** + * Return -1 if not found + */ +int BKE_layer_collection_findindex(SceneLayer *sl, LayerCollection *lc) +{ + int i = 0; + return index_from_collection(&sl->layer_collections, lc, &i); +} + +/** + * Link a collection to a renderlayer + * The collection needs to be created separately + */ +LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc) +{ + LayerCollection *lc = layer_collection_add(sl, &sl->layer_collections, sc); + sl->active_collection = BKE_layer_collection_findindex(sl, lc); + return lc; +} + +/** + * Unlink a collection base from a renderlayer + * The corresponding collection is not removed from the master collection + */ +void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc) +{ + BKE_layer_collection_free(sl, lc); + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_collection_recalculate(sl, lc); + + BLI_remlink(&sl->layer_collections, lc); + MEM_freeN(lc); + sl->active_collection = 0; +} + +static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base = object_base_add(sl, ob); + + /* only add an object once - prevent SceneCollection->objects and + * SceneCollection->filter_objects to add the same object */ + + if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data))) { + return; + } + + BLI_addtail(&lc->object_bases, BLI_genericNodeN(base)); + + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_object_recalculate(sl, ob); +} + +static void layer_collection_object_remove(SceneLayer *sl, LayerCollection *lc, Object *ob) +{ + Base *base; + base = BKE_scene_layer_base_find(sl, ob); + + LinkData *link = BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)); + BLI_remlink(&lc->object_bases, link); + MEM_freeN(link); + + scene_layer_object_base_unref(sl, base); +} + +static void layer_collection_objects_populate(SceneLayer *sl, LayerCollection *lc, ListBase *objects) +{ + for (LinkData *link = objects->first; link; link = link->next) { + layer_collection_object_add(sl, lc, link->data); + } +} + +static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, SceneCollection *sc) +{ + layer_collection_objects_populate(sl, lc, &sc->objects); + layer_collection_objects_populate(sl, lc, &sc->filter_objects); + + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + layer_collection_add(sl, &lc->layer_collections, nsc); + } +} + +static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc) +{ + LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); + BLI_addtail(lb, lc); + + lc->scene_collection = sc; + lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED; + + layer_collection_create_engine_settings(lc); + layer_collection_populate(sl, lc, sc); + return lc; +} + + +/* ---------------------------------------------------------------------- */ + +/** + * See if render layer has the scene collection linked directly, or indirectly (nested) + */ +bool BKE_scene_layer_has_collection(struct SceneLayer *sl, struct SceneCollection *sc) +{ + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + if (find_layer_collection_by_scene_collection(lc, sc) != NULL) { + return true; + } + } + return false; +} + +/** + * See if the object is in any of the scene layers of the scene + */ +bool BKE_scene_has_object(Scene *scene, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + Base *base = BKE_scene_layer_base_find(sl, ob); + if (base) { + return true; + } + } + return false; +} + + +/* ---------------------------------------------------------------------- */ +/* Syncing */ + +static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + return lc; + } + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(nlc, sc); + if (found) { + return found; + } + } + return NULL; +} + +/** + * Add a new LayerCollection for all the SceneLayers that have sc_parent + */ +void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc_parent, SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *lc_parent = find_layer_collection_by_scene_collection(lc, sc_parent); + if (lc_parent) { + layer_collection_add(sl, &lc_parent->layer_collections, sc); + } + } + } +} + +/** + * Add a corresponding ObjectBase to all the equivalent LayerCollection + */ +void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_add(sl, found, ob); + } + } + } +} + +/** + * Remove the equivalent object base to all layers that have this collection + * also remove all reference to ob in the filter_objects + */ +void BKE_layer_sync_object_unlink(Scene *scene, SceneCollection *sc, Object *ob) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + LayerCollection *found = find_layer_collection_by_scene_collection(lc, sc); + if (found) { + layer_collection_object_remove(sl, found, ob); + } + } + BKE_scene_layer_base_flag_recalculate(sl); + BKE_scene_layer_engine_settings_object_recalculate(sl, ob); + } +} + +/* ---------------------------------------------------------------------- */ +/* Override */ + +/** + * Add a new datablock override + */ +void BKE_collection_override_datablock_add(LayerCollection *UNUSED(lc), const char *UNUSED(data_path), ID *UNUSED(id)) +{ + TODO_LAYER_OVERRIDE; +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings */ + +ListBase R_engines_settings_callbacks = {NULL, NULL}; + +typedef struct CollectionEngineSettingsCB_Type { + struct CollectionEngineSettingsCB_Type *next, *prev; + + char name[MAX_NAME]; /* engine name */ + + CollectionEngineSettingsCB callback; + +} CollectionEngineSettingsCB_Type; + +static void create_engine_settings_layer_collection(LayerCollection *lc, CollectionEngineSettingsCB_Type *ces_type) +{ + if (BKE_layer_collection_engine_get(lc, ces_type->name)) { + return; + } + + CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); + BLI_addtail(&lc->engine_settings, ces); + + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + create_engine_settings_layer_collection(lcn, ces_type); + } +} + +static void create_engines_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + create_engine_settings_layer_collection(lc, ces_type); + } + } +} + +void BKE_layer_collection_engine_settings_callback_register( + Main *bmain, const char *engine_name, CollectionEngineSettingsCB func) +{ + CollectionEngineSettingsCB_Type *ces_type; + + /* cleanup in case it existed */ + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + + if (ces_type) { + BLI_remlink(&R_engines_settings_callbacks, ces_type); + MEM_freeN(ces_type); + } + + ces_type = MEM_callocN(sizeof(CollectionEngineSettingsCB_Type), "collection_engine_type"); + BLI_strncpy_utf8(ces_type->name, engine_name, sizeof(ces_type->name)); + ces_type->callback = func; + BLI_addtail(&R_engines_settings_callbacks, ces_type); + + if (bmain) { + /* populate all of the collections of the scene with those settings */ + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + create_engines_settings_scene(scene, ces_type); + } + } +} + +void BKE_layer_collection_engine_settings_callback_free(void) +{ + BLI_freelistN(&R_engines_settings_callbacks); +} + +static CollectionEngineSettings *collection_engine_settings_create(CollectionEngineSettingsCB_Type *ces_type) +{ + /* create callback data */ + CollectionEngineSettings *ces = MEM_callocN(sizeof(CollectionEngineSettings), "Collection Engine Settings"); + BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name)); + + /* call callback */ + ces_type->callback(NULL, ces); + + return ces; +} + +/** + * Initialize a CollectionEngineSettings + * + * Usually we would pass LayerCollection->engine_settings + * But depsgraph uses this for Object->collection_settings + */ +CollectionEngineSettings *BKE_layer_collection_engine_settings_create(const char *engine_name) +{ + CollectionEngineSettingsCB_Type *ces_type; + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + BLI_assert(ces_type); + + CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); + return ces; +} + +/** + * Free the CollectionEngineSettings + */ +void BKE_layer_collection_engine_settings_free(CollectionEngineSettings *ces) +{ + BLI_freelistN(&ces->properties); +} + +static void layer_collection_engine_settings_free(LayerCollection *lc) +{ + for (CollectionEngineSettings *ces = lc->engine_settings.first; ces; ces = ces->next) { + BKE_layer_collection_engine_settings_free(ces); + } + BLI_freelistN(&lc->engine_settings); +} + +/** + * Initialize the render settings for a single LayerCollection + */ +static void layer_collection_create_engine_settings(LayerCollection *lc) +{ + CollectionEngineSettingsCB_Type *ces_type; + for (ces_type = R_engines_settings_callbacks.first; ces_type; ces_type = ces_type->next) { + create_engine_settings_layer_collection(lc, ces_type); + } +} + +/** + * Return layer collection engine settings for specified engine + */ +CollectionEngineSettings *BKE_layer_collection_engine_get(LayerCollection *lc, const char *engine_name) +{ + CollectionEngineSettings *ces; + ces = BLI_findstring(&lc->engine_settings, engine_name, offsetof(CollectionEngineSettings, name)); + return ces; +} + +/* ---------------------------------------------------------------------- */ +/* Engine Settings Properties */ + +void BKE_collection_engine_property_add_float(CollectionEngineSettings *ces, const char *name, float value) +{ + CollectionEnginePropertyFloat *prop; + prop = MEM_callocN(sizeof(CollectionEnginePropertyFloat), "collection engine settings float"); + prop->data.type = COLLECTION_PROP_TYPE_FLOAT; + BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name)); + prop->value = value; + BLI_addtail(&ces->properties, prop); +} + +void BKE_collection_engine_property_add_int(CollectionEngineSettings *ces, const char *name, int value) +{ + CollectionEnginePropertyInt *prop; + prop = MEM_callocN(sizeof(CollectionEnginePropertyInt), "collection engine settings int"); + prop->data.type = COLLECTION_PROP_TYPE_INT; + BLI_strncpy_utf8(prop->data.name, name, sizeof(prop->data.name)); + prop->value = value; + BLI_addtail(&ces->properties, prop); +} + +CollectionEngineProperty *BKE_collection_engine_property_get(CollectionEngineSettings *ces, const char *name) +{ + return BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); +} + +int BKE_collection_engine_property_value_get_int(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyInt *prop; + prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return prop->value; +} + +float BKE_collection_engine_property_value_get_float(CollectionEngineSettings *ces, const char *name) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return prop->value; +} + +void BKE_collection_engine_property_value_set_int(CollectionEngineSettings *ces, const char *name, int value) +{ + CollectionEnginePropertyInt *prop; + prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +void BKE_collection_engine_property_value_set_float(CollectionEngineSettings *ces, const char *name, float value) +{ + CollectionEnginePropertyFloat *prop; + prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + prop->value = value; + prop->data.flag |= COLLECTION_PROP_USE; +} + +bool BKE_collection_engine_property_use_get(CollectionEngineSettings *ces, const char *name) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + return ((prop->flag & COLLECTION_PROP_USE) != 0); +} + +void BKE_collection_engine_property_use_set(CollectionEngineSettings *ces, const char *name, bool value) +{ + CollectionEngineProperty *prop; + prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + + if (value) { + prop->flag |= COLLECTION_PROP_USE; + } + else { + prop->flag &= ~COLLECTION_PROP_USE; + } +} + +/* Engine Settings recalculate */ + +static void collection_engine_settings_init(CollectionEngineSettings *ces, const char *engine_name) +{ + CollectionEngineSettingsCB_Type *ces_type; + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + + BLI_listbase_clear(&ces->properties); + BLI_strncpy_utf8(ces->name, ces_type->name, sizeof(ces->name)); + + /* call callback */ + ces_type->callback(NULL, ces); +} + +static void collection_engine_settings_copy(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src) +{ + BLI_strncpy_utf8(ces_dst->name, ces_src->name, sizeof(ces_dst->name)); + BLI_freelistN(&ces_dst->properties); + + for (CollectionEngineProperty *prop = ces_src->properties.first; prop; prop = prop->next) { + CollectionEngineProperty *prop_new = MEM_dupallocN(prop); + BLI_addtail(&ces_dst->properties, prop_new); + } +} + +/** + * Set a value from a CollectionProperty to another + */ +static void collection_engine_property_set (CollectionEngineProperty *prop_dst, CollectionEngineProperty *prop_src){ + if ((prop_src->flag & COLLECTION_PROP_USE) != 0) { + /* mark the property as used, so the engine knows if the value was ever set*/ + prop_dst->flag |= COLLECTION_PROP_USE; + switch (prop_src->type) { + case COLLECTION_PROP_TYPE_FLOAT: + ((CollectionEnginePropertyFloat *)prop_dst)->value = ((CollectionEnginePropertyFloat *)prop_src)->value; + break; + case COLLECTION_PROP_TYPE_INT: + ((CollectionEnginePropertyInt *)prop_dst)->value = ((CollectionEnginePropertyInt *)prop_src)->value; + break; + default: + BLI_assert(false); + break; + } + } +} + +static void collection_engine_settings_merge(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src) +{ + CollectionEngineProperty *prop_src, *prop_dst; + + prop_dst = ces_dst->properties.first; + for (prop_src = ces_src->properties.first; prop_src; prop_src = prop_src->next, prop_dst = prop_dst->next) { + collection_engine_property_set(prop_dst, prop_src); + } +} + +static void layer_collection_engine_settings_update( + LayerCollection *lc, CollectionEngineSettings *ces_parent, + Base *base, CollectionEngineSettings *ces_ob) +{ + if ((lc->flag & COLLECTION_VISIBLE) == 0) { + return; + } + + CollectionEngineSettings ces = {NULL}; + collection_engine_settings_copy(&ces, ces_parent); + + CollectionEngineSettings *ces_lc = BKE_layer_collection_engine_get(lc, ces.name); + collection_engine_settings_merge(&ces, ces_lc); + + if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)) != NULL) { + collection_engine_settings_merge(ces_ob, &ces); + } + + /* do it recursively */ + for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { + layer_collection_engine_settings_update(lcn, &ces, base, ces_ob); + } + + BKE_layer_collection_engine_settings_free(&ces); +} + +/** + * Update the collection settings pointer allocated in the object + * This is to be flushed from the Depsgraph + */ +static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob, const char *engine_name) +{ + Base *base = BKE_scene_layer_base_find(sl, ob); + CollectionEngineSettings ces_layer = {NULL}, *ces_ob; + + collection_engine_settings_init(&ces_layer, engine_name); + + if (ob->collection_settings) { + BKE_layer_collection_engine_settings_free(ob->collection_settings); + MEM_freeN(ob->collection_settings); + } + + CollectionEngineSettingsCB_Type *ces_type; + ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + ces_ob = collection_engine_settings_create(ces_type); + + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_engine_settings_update(lc, &ces_layer, base, ces_ob); + } + + BKE_layer_collection_engine_settings_free(&ces_layer); + ob->collection_settings = ces_ob; +} + +/* ---------------------------------------------------------------------- */ +/* Iterators */ + +static void object_bases_Iterator_begin(Iterator *iter, void *data_in, const int flag) +{ + SceneLayer *sl = data_in; + Base *base = sl->object_bases.first; + + /* when there are no objects */ + if (base == NULL) { + iter->valid = false; + return; + } + + iter->valid = true; + iter->data = base; + + if ((base->flag & flag) == 0) { + object_bases_Iterator_next(iter, flag); + } + else { + iter->current = base; + } +} + +static void object_bases_Iterator_next(Iterator *iter, const int flag) +{ + Base *base = ((Base *)iter->data)->next; + + while (base) { + if ((base->flag & flag) != 0) { + iter->current = base; + iter->data = base; + return; + } + base = base->next; + } + + iter->current = NULL; + iter->valid = false; +} + +static void objects_Iterator_begin(Iterator *iter, void *data_in, const int flag) +{ + object_bases_Iterator_begin(iter, data_in, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +static void objects_Iterator_next(Iterator *iter, const int flag) +{ + object_bases_Iterator_next(iter, flag); + + if (iter->valid) { + iter->current = ((Base *)iter->current)->object; + } +} + +void BKE_selected_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_SELECTED); +} + +void BKE_selected_objects_Iterator_next(Iterator *iter) +{ + objects_Iterator_next(iter, BASE_SELECTED); +} + +void BKE_selected_objects_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_objects_Iterator_begin(Iterator *iter, void *data_in) +{ + objects_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_objects_Iterator_next(Iterator *iter) +{ + objects_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_objects_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} + +void BKE_visible_bases_Iterator_begin(Iterator *iter, void *data_in) +{ + object_bases_Iterator_begin(iter, data_in, BASE_VISIBLED); +} + +void BKE_visible_bases_Iterator_next(Iterator *iter) +{ + object_bases_Iterator_next(iter, BASE_VISIBLED); +} + +void BKE_visible_bases_Iterator_end(Iterator *UNUSED(iter)) +{ + /* do nothing */ +} diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index de35d1e0eac..2398c6724ed 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -76,6 +76,7 @@ #include "BLI_ghash.h" #include "BLI_linklist.h" #include "BLI_memarena.h" +#include "BLI_mempool.h" #include "BLI_string_utils.h" #include "BLI_threads.h" @@ -273,8 +274,12 @@ void BKE_id_clear_newpoin(ID *id) } static int id_expand_local_callback( - void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag)) + void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int cb_flag) { + if (cb_flag & IDWALK_CB_PRIVATE) { + return IDWALK_RET_NOP; + } + /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)... * Just skip it, shape key can only be either indirectly linked, or fully local, period. * And let's curse one more time that stupid useless shapekey ID type! */ @@ -288,9 +293,9 @@ static int id_expand_local_callback( /** * 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) +void BKE_id_expand_local(Main *bmain, ID *id) { - BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0); + BKE_library_foreach_ID_link(bmain, id, id_expand_local_callback, NULL, IDWALK_READONLY); } /** @@ -299,7 +304,7 @@ void BKE_id_expand_local(ID *id) void BKE_id_copy_ensure_local(Main *bmain, ID *old_id, ID *new_id) { if (ID_IS_LINKED_DATABLOCK(old_id)) { - BKE_id_expand_local(new_id); + BKE_id_expand_local(bmain, new_id); BKE_id_lib_local_paths(bmain, old_id->lib, new_id); } } @@ -326,7 +331,7 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data_ex(bmain, id, id_in_mainlist); - BKE_id_expand_local(id); + BKE_id_expand_local(bmain, id); } else { ID *id_new; @@ -1252,6 +1257,10 @@ void BKE_main_free(Main *mainvar) } } + if (mainvar->relations) { + BKE_main_relations_free(mainvar); + } + BLI_spin_end((SpinLock *)mainvar->lock); MEM_freeN(mainvar->lock); DEG_evaluation_context_free(mainvar->eval_ctx); @@ -1268,6 +1277,78 @@ void BKE_main_unlock(struct Main *bmain) BLI_spin_unlock((SpinLock *) bmain->lock); } + +static int main_relations_create_cb(void *user_data, ID *id_self, ID **id_pointer, int cb_flag) +{ + MainIDRelations *rel = user_data; + + if (*id_pointer) { + MainIDRelationsEntry *entry, **entry_p; + + entry = BLI_mempool_alloc(rel->entry_pool); + if (BLI_ghash_ensure_p(rel->id_user_to_used, id_self, (void ***)&entry_p)) { + entry->next = *entry_p; + } + else { + entry->next = NULL; + } + entry->id_pointer = id_pointer; + entry->usage_flag = cb_flag; + *entry_p = entry; + + entry = BLI_mempool_alloc(rel->entry_pool); + if (BLI_ghash_ensure_p(rel->id_used_to_user, *id_pointer, (void ***)&entry_p)) { + entry->next = *entry_p; + } + else { + entry->next = NULL; + } + entry->id_pointer = (ID **)id_self; + entry->usage_flag = cb_flag; + *entry_p = entry; + } + + return IDWALK_RET_NOP; +} + +/** Generate the mappings between used IDs and their users, and vice-versa. */ +void BKE_main_relations_create(Main *bmain) +{ + ListBase *lbarray[MAX_LIBARRAY]; + ID *id; + int a; + + if (bmain->relations != NULL) { + BKE_main_relations_free(bmain); + } + + bmain->relations = MEM_mallocN(sizeof(*bmain->relations), __func__); + bmain->relations->id_used_to_user = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + bmain->relations->id_user_to_used = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + bmain->relations->entry_pool = BLI_mempool_create(sizeof(MainIDRelationsEntry), 128, 128, BLI_MEMPOOL_NOP); + + for (a = set_listbasepointers(bmain, lbarray); a--; ) { + for (id = lbarray[a]->first; id; id = id->next) { + BKE_library_foreach_ID_link(NULL, id, main_relations_create_cb, bmain->relations, IDWALK_READONLY); + } + } +} + +void BKE_main_relations_free(Main *bmain) +{ + if (bmain->relations) { + if (bmain->relations->id_used_to_user) { + BLI_ghash_free(bmain->relations->id_used_to_user, NULL, NULL); + } + if (bmain->relations->id_user_to_used) { + BLI_ghash_free(bmain->relations->id_user_to_used, NULL, NULL); + } + BLI_mempool_destroy(bmain->relations->entry_pool); + MEM_freeN(bmain->relations); + bmain->relations = NULL; + } +} + /** * Generates a raw .blend file thumbnail data from given image. * @@ -1623,6 +1704,53 @@ void BKE_main_id_clear_newpoins(Main *bmain) } } + +static void library_make_local_copying_check(ID *id, GSet *loop_tags, MainIDRelations *id_relations, GSet *done_ids) +{ + if (BLI_gset_haskey(done_ids, id)) { + return; /* Already checked, nothing else to do. */ + } + + MainIDRelationsEntry *entry = BLI_ghash_lookup(id_relations->id_used_to_user, id); + BLI_gset_insert(loop_tags, id); + for (; entry != NULL; entry = entry->next) { + ID *par_id = (ID *)entry->id_pointer; /* used_to_user stores ID pointer, not pointer to ID pointer... */ + + /* Shapekeys are considered 'private' to their owner ID here, and never tagged (since they cannot be linked), + * so we have to switch effective parent to their owner. */ + if (GS(par_id->name) == ID_KE) { + par_id = ((Key *)par_id)->from; + } + + if (par_id->lib == NULL) { + /* Local user, early out to avoid some gset querying... */ + continue; + } + if (!BLI_gset_haskey(done_ids, par_id)) { + if (BLI_gset_haskey(loop_tags, par_id)) { + /* We are in a 'dependency loop' of IDs, this does not say us anything, skip it. + * Note that this is the situation that can lead to archipelagoes of linked data-blocks + * (since all of them have non-local users, they would all be duplicated, leading to a loop of unused + * linked data-blocks that cannot be freed since they all use each other...). */ + continue; + } + /* Else, recursively check that user ID. */ + library_make_local_copying_check(par_id, loop_tags, id_relations, done_ids); + } + + if (par_id->tag & LIB_TAG_DOIT) { + /* This user will be fully local in future, so far so good, nothing to do here but check next user. */ + } + else { + /* This user won't be fully local in future, so current ID won't be either. And we are done checking it. */ + id->tag &= ~LIB_TAG_DOIT; + break; + } + } + BLI_gset_add(done_ids, id); + BLI_gset_remove(loop_tags, id, NULL); +} + /** Make linked datablocks local. * * \param bmain Almost certainly G.main. @@ -1633,11 +1761,10 @@ void BKE_main_id_clear_newpoins(Main *bmain) /* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether * they were also indirectly used or not... * - * Current version uses regular id_make_local callback, which is not super-efficient since this ends up - * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID). - * - * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances - * are now *reasonably* OK. + * Current version uses regular id_make_local callback, with advanced pre-processing step to detect all cases of + * IDs currently indirectly used, but which will be used by local data only once this function is finished. + * This allows to avoid any uneeded duplication of IDs, and hence all time lost afterwards to remove + * orphaned linked data-blocks... */ void BKE_library_make_local( Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake) @@ -1648,9 +1775,12 @@ void BKE_library_make_local( LinkNode *todo_ids = NULL; LinkNode *copied_ids = NULL; - LinkNode *linked_loop_candidates = NULL; MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__); + BKE_main_relations_create(bmain); + + GSet *done_ids = BLI_gset_ptr_new(__func__); + /* Step 1: Detect datablocks to make local. */ for (a = set_listbasepointers(bmain, lbarray); a--; ) { id = lbarray[a]->first; @@ -1660,16 +1790,25 @@ void BKE_library_make_local( const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name))); for (; id; id = id->next) { + ID *ntree = (ID *)ntreeFromID(id); + id->tag &= ~LIB_TAG_DOIT; + if (ntree != NULL) { + ntree->tag &= ~LIB_TAG_DOIT; + } if (id->lib == NULL) { id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); } - /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its - * possible to tag data you don't want to be made local, used for - * appending data, so any libdata already linked wont become local - * (very nasty to discover all your links are lost after appending). + /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its possible to tag data you don't want to + * be made local, used for appending data, so any libdata already linked wont become local (very nasty + * to discover all your links are lost after appending). * Also, never ever make proxified objects local, would not make any sense. */ + /* Some more notes: + * - Shapekeys are never tagged here (since they are not linkable). + * - Nodetrees used in materials etc. have to be tagged manually, since they do not exist in Main (!). + * This is ok-ish on 'make local' side of things (since those are handled by their 'owner' IDs), + * but complicates slightly the pre-processing of relations between IDs at step 2... */ else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && ELEM(lib, NULL, id->lib) && !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && @@ -1677,13 +1816,32 @@ void BKE_library_make_local( { BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem); id->tag |= LIB_TAG_DOIT; + + /* Tag those nasty non-ID nodetrees, but do not add them to todo list, making them local is handled + * by 'owner' ID. This is needed for library_make_local_copying_check() to work OK at step 2. */ + if (ntree != NULL) { + ntree->tag |= LIB_TAG_DOIT; + } + } + else { + /* Linked ID that we won't be making local (needed info for step 2, see below). */ + BLI_gset_add(done_ids, id); } } } /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future, - * local data), others will need to be duplicated and further processed later. */ - BKE_library_indirectly_used_data_tag_clear(bmain); + * local data), others will need to be duplicated. */ + GSet *loop_tags = BLI_gset_ptr_new(__func__); + for (LinkNode *it = todo_ids; it; it = it->next) { + library_make_local_copying_check(it->link, loop_tags, bmain->relations, done_ids); + BLI_assert(BLI_gset_size(loop_tags) == 0); + } + BLI_gset_free(loop_tags, NULL); + BLI_gset_free(done_ids, NULL); + + /* Next step will most likely add new IDs, better to get rid of this mapping now. */ + BKE_main_relations_free(bmain); /* Step 3: Make IDs local, either directly (quick and simple), or using generic process, * which involves more complex checks and might instead create a local copy of original linked ID. */ @@ -1693,10 +1851,10 @@ void BKE_library_make_local( if (id->tag & LIB_TAG_DOIT) { /* We know all users of this object are local or will be made fully local, even if currently there are - * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make + * some indirect usages. So instead of making a copy that we'll likely get rid of later, directly make * that data block local. Saves a tremendous amount of time with complex scenes... */ id_clear_lib_data_ex(bmain, id, true); - BKE_id_expand_local(id); + BKE_id_expand_local(bmain, id); id->tag &= ~LIB_TAG_DOIT; } else { @@ -1732,6 +1890,9 @@ void BKE_library_make_local( /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated loop, * as lbarray ordering is not enough to ensure us we did catch all dependencies * (e.g. if making local a parent object before its child...). See T48907. */ + /* TODO This is now the biggest step by far (in term of processing time). We may be able to gain here by + * using again main->relations mapping, but... this implies BKE_libblock_remap & co to be able to update + * main->relations on the fly. Have to think about it a bit more, and see whether new code is OK first, anyway. */ for (LinkNode *it = copied_ids; it; it = it->next) { id = it->link; @@ -1750,6 +1911,53 @@ void BKE_library_make_local( } } + /* Note: Keeping both version of the code (old one being safer, since it still has checks against unused IDs) + * for now, we can remove old one once it has been tested for some time in master... */ +#if 1 + /* Step 5: proxy 'remapping' hack. */ + for (LinkNode *it = copied_ids; it; it = it->next) { + /* Attempt to re-link copied proxy objects. This allows appending of an entire scene + * from another blend file into this one, even when that blend file contains proxified + * armatures that have local references. Since the proxified object needs to be linked + * (not local), this will only work when the "Localize all" checkbox is disabled. + * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ + if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { + Object *ob = (Object *)id; + Object *ob_new = (Object *)id->newid; + bool is_local = false, is_lib = false; + + /* Proxies only work when the proxified object is linked-in from a library. */ + if (ob->proxy->id.lib == NULL) { + printf("Warning, proxy object %s will loose its link to %s, because the " + "proxified object is local.\n", id->newid->name, ob->proxy->id.name); + continue; + } + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + + /* We can only switch the proxy'ing to a made-local proxy if it is no longer + * referred to from a library. Not checking for local use; if new local proxy + * was not used locally would be a nasty bug! */ + if (is_local || is_lib) { + printf("Warning, made-local proxy object %s will loose its link to %s, " + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n", + id->newid->name, ob->proxy->id.name, is_local, is_lib); + } + else { + /* we can switch the proxy'ing from the linked-in to the made-local proxy. + * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that + * was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */ + ob_new->proxy = ob->proxy; + ob_new->proxy_group = ob->proxy_group; + ob_new->proxy_from = ob->proxy_from; + ob_new->proxy->proxy_from = ob_new; + ob->proxy = ob->proxy_from = ob->proxy_group = NULL; + } + } + } +#else + LinkNode *linked_loop_candidates = NULL; + /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end... * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */ bool do_loop = true; @@ -1800,6 +2008,8 @@ void BKE_library_make_local( if (!is_local) { if (!is_lib) { /* Not used at all, we can free it! */ + BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process, should not happen anymore"); + printf("\t%s (from %s)\n", id->name, id->lib->id.name); BKE_libblock_free(bmain, id); it->link = NULL; do_loop = true; @@ -1813,7 +2023,7 @@ void BKE_library_make_local( /* Grrrrrrr... those half-datablocks-stuff... grrrrrrrrrrr... * Here we have to also tag them as potential candidates, otherwise they would falsy report - * ID they used as 'directly used' in fourth step. */ + * ID they used as 'directly used' in sixth step. */ ID *ntree = (ID *)ntreeFromID(id); if (ntree != NULL) { ntree->tag |= LIB_TAG_DOIT; @@ -1838,6 +2048,7 @@ void BKE_library_make_local( /* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based * archipelagos, so no need to check again after we have deleted one, as done in previous step. */ if (id->tag & LIB_TAG_DOIT) { + BLI_assert(!"Unused linked data copy remaining from MakeLibLocal process (archipelago case), should not happen anymore"); /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here... * Setting it to NULL may not be 100% correct, but should be safe and do the work. */ if (GS(id->name) == ID_OB) { @@ -1858,6 +2069,7 @@ void BKE_library_make_local( it->link = NULL; } } +#endif BKE_main_id_clear_newpoins(bmain); BLI_memarena_free(linklist_mem); diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index bfc26fcac0f..a071b3202be 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -63,10 +63,12 @@ #include "DNA_world_types.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" #include "BKE_animsys.h" +#include "BKE_collection.h" #include "BKE_constraint.h" #include "BKE_fcurve.h" #include "BKE_library.h" @@ -83,11 +85,12 @@ #define FOREACH_FINALIZE _finalize #define FOREACH_FINALIZE_VOID FOREACH_FINALIZE: (void)0 -#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, cb_flag) \ +#define FOREACH_CALLBACK_INVOKE_ID_PP(_data, id_pp, _cb_flag) \ + CHECK_TYPE(id_pp, ID **); \ 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 | (_data)->cd_flag); \ + const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, _cb_flag | (_data)->cb_flag); \ if (_flag & IDWALK_READONLY) { \ BLI_assert(*(id_pp) == old_id); \ } \ @@ -128,7 +131,7 @@ enum { typedef struct LibraryForeachIDData { ID *self_id; int flag; - int cd_flag; + int cb_flag; LibraryIDLinkCallback callback; void *user_data; int status; @@ -139,19 +142,19 @@ typedef struct LibraryForeachIDData { } LibraryForeachIDData; static void library_foreach_rigidbodyworldSceneLooper( - struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cd_flag) + struct RigidBodyWorld *UNUSED(rbw), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } static void library_foreach_modifiersForeachIDLink( - void *user_data, Object *UNUSED(object), ID **id_pointer, int cd_flag) + void *user_data, Object *UNUSED(object), ID **id_pointer, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } @@ -160,44 +163,44 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), ID bool is_reference, void *user_data) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - const int cd_flag = is_reference ? IDWALK_USER : IDWALK_NOP; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } static void library_foreach_particlesystemsObjectLooper( - ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cd_flag) + ParticleSystem *UNUSED(psys), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } static void library_foreach_sensorsObjectLooper( - bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cd_flag) + bSensor *UNUSED(sensor), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } static void library_foreach_controllersObjectLooper( - bController *UNUSED(controller), ID **id_pointer, void *user_data, int cd_flag) + bController *UNUSED(controller), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } static void library_foreach_actuatorsObjectLooper( - bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cd_flag) + bActuator *UNUSED(actuator), ID **id_pointer, void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *) user_data; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cd_flag); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pointer, cb_flag); FOREACH_FINALIZE_VOID; } @@ -206,7 +209,7 @@ static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *stri { NlaStrip *substrip; - FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_CB_USER); for (substrip = strip->strips.first; substrip; substrip = substrip->next) { library_foreach_nla_strip(data, substrip); @@ -229,14 +232,14 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * /* only used targets */ DRIVER_TARGETS_USED_LOOPER(dvar) { - FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_NOP); + FOREACH_CALLBACK_INVOKE_ID(data, dtar->id, IDWALK_CB_NOP); } DRIVER_TARGETS_LOOPER_END } } - FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER); - FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_CB_USER); + FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_CB_USER); for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) { for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) { @@ -249,23 +252,28 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) { - FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_NOP); - FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, mtex->object, IDWALK_CB_NOP); + FOREACH_CALLBACK_INVOKE(data, mtex->tex, IDWALK_CB_USER); FOREACH_FINALIZE_VOID; } static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) { - FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER); - FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_CB_USER); + FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_CB_USER); FOREACH_FINALIZE_VOID; } static void library_foreach_ID_as_subdata_link( - ID *id, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data) + ID **id_pp, LibraryIDLinkCallback callback, void *user_data, int flag, LibraryForeachIDData *data) { + /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ + ID *id = *id_pp; + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE); + BLI_assert(id == *id_pp); + if (flag & IDWALK_RECURSE) { /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in IDWALK_RECURSE case is * troublesome, see T49553. */ @@ -275,8 +283,10 @@ static void library_foreach_ID_as_subdata_link( } } else { - BKE_library_foreach_ID_link(id, callback, user_data, flag); + BKE_library_foreach_ID_link(NULL, id, callback, user_data, flag); } + + FOREACH_FINALIZE_VOID; } /** @@ -284,7 +294,7 @@ static void library_foreach_ID_as_subdata_link( * * \note: May be extended to be recursive in the future. */ -void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *user_data, int flag) +void BKE_library_foreach_ID_link(Main *bmain, ID *id, LibraryIDLinkCallback callback, void *user_data, int flag) { LibraryForeachIDData data; int i; @@ -312,9 +322,21 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u #define CALLBACK_INVOKE(check_id_super, cb_flag) \ FOREACH_CALLBACK_INVOKE(&data, check_id_super, cb_flag) - do { + for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; - data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0; + data.cb_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_CB_INDIRECT_USAGE : 0; + + if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY)) { + /* Note that this is minor optimization, even in worst cases (like id being an object with lots of + * drivers and constraints and modifiers, or material etc. with huge node tree), + * but we might as well use it (Main->relations is always assumed valid, it's responsability of code + * creating it to free it, especially if/when it starts modifying Main database). */ + MainIDRelationsEntry *entry = BLI_ghash_lookup(bmain->relations->id_user_to_used, id); + for (; entry != NULL; entry = entry->next) { + FOREACH_CALLBACK_INVOKE_ID_PP(&data, entry->id_pointer, entry->usage_flag); + } + continue; + } AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -325,7 +347,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_LI: { Library *lib = (Library *) id; - CALLBACK_INVOKE(lib->parent, IDWALK_NOP); + CALLBACK_INVOKE(lib->parent, IDWALK_CB_NOP); break; } case ID_SCE: @@ -333,41 +355,41 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u Scene *scene = (Scene *) id; ToolSettings *toolsett = scene->toolsettings; SceneRenderLayer *srl; - Base *base; + BaseLegacy *legacy_base; - CALLBACK_INVOKE(scene->camera, IDWALK_NOP); - CALLBACK_INVOKE(scene->world, IDWALK_USER); - CALLBACK_INVOKE(scene->set, IDWALK_NOP); - CALLBACK_INVOKE(scene->clip, IDWALK_USER); + CALLBACK_INVOKE(scene->camera, IDWALK_CB_NOP); + CALLBACK_INVOKE(scene->world, IDWALK_CB_USER); + CALLBACK_INVOKE(scene->set, IDWALK_CB_NOP); + CALLBACK_INVOKE(scene->clip, IDWALK_CB_USER); if (scene->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)scene->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&scene->nodetree, callback, user_data, flag, &data); } /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, * since basact is just a pointer to one of those items. */ - CALLBACK_INVOKE(scene->obedit, IDWALK_NOP); + CALLBACK_INVOKE(scene->obedit, IDWALK_CB_NOP); for (srl = scene->r.layers.first; srl; srl = srl->next) { FreestyleModuleConfig *fmc; FreestyleLineSet *fls; if (srl->mat_override) { - CALLBACK_INVOKE(srl->mat_override, IDWALK_USER); + CALLBACK_INVOKE(srl->mat_override, IDWALK_CB_USER); } if (srl->light_override) { - CALLBACK_INVOKE(srl->light_override, IDWALK_USER); + CALLBACK_INVOKE(srl->light_override, IDWALK_CB_USER); } for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { if (fmc->script) { - CALLBACK_INVOKE(fmc->script, IDWALK_NOP); + CALLBACK_INVOKE(fmc->script, IDWALK_CB_NOP); } } for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { if (fls->group) { - CALLBACK_INVOKE(fls->group, IDWALK_USER); + CALLBACK_INVOKE(fls->group, IDWALK_CB_USER); } if (fls->linestyle) { - CALLBACK_INVOKE(fls->linestyle, IDWALK_USER); + CALLBACK_INVOKE(fls->linestyle, IDWALK_CB_USER); } } } @@ -376,38 +398,59 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u Sequence *seq; SEQP_BEGIN(scene->ed, seq) { - CALLBACK_INVOKE(seq->scene, IDWALK_NOP); - CALLBACK_INVOKE(seq->scene_camera, IDWALK_NOP); - CALLBACK_INVOKE(seq->clip, IDWALK_USER); - CALLBACK_INVOKE(seq->mask, IDWALK_USER); - CALLBACK_INVOKE(seq->sound, IDWALK_USER); + CALLBACK_INVOKE(seq->scene, IDWALK_CB_NOP); + CALLBACK_INVOKE(seq->scene_camera, IDWALK_CB_NOP); + CALLBACK_INVOKE(seq->clip, IDWALK_CB_USER); + CALLBACK_INVOKE(seq->mask, IDWALK_CB_USER); + CALLBACK_INVOKE(seq->sound, IDWALK_CB_USER); for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) { - CALLBACK_INVOKE(smd->mask_id, IDWALK_USER); + CALLBACK_INVOKE(smd->mask_id, IDWALK_CB_USER); } } SEQ_END } - CALLBACK_INVOKE(scene->gpd, IDWALK_USER); + CALLBACK_INVOKE(scene->gpd, IDWALK_CB_USER); + + for (legacy_base = scene->base.first; legacy_base; legacy_base = legacy_base->next) { + CALLBACK_INVOKE(legacy_base->object, IDWALK_CB_USER); + } + + SceneCollection *sc; + FOREACH_SCENE_COLLECTION(scene, sc) + { + for (LinkData *link = sc->objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + + for (LinkData *link = sc->filter_objects.first; link; link = link->next) { + CALLBACK_INVOKE_ID(link->data, IDWALK_CB_USER); + } + } + FOREACH_SCENE_COLLECTION_END - for (base = scene->base.first; base; base = base->next) { - CALLBACK_INVOKE(base->object, IDWALK_USER); + SceneLayer *sl; + for (sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + CALLBACK_INVOKE(base->object, IDWALK_NOP); + } } for (TimeMarker *marker = scene->markers.first; marker; marker = marker->next) { - CALLBACK_INVOKE(marker->camera, IDWALK_NOP); + CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); } if (toolsett) { - CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_CB_NOP); + + CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_CB_NOP); + CALLBACK_INVOKE(toolsett->particle.object, IDWALK_CB_NOP); + CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_CB_NOP); - CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP); library_foreach_paint(&data, &toolsett->imapaint.paint); - CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER); - CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER); - CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER); + CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_CB_USER); + CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_CB_USER); + CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_CB_USER); if (toolsett->vpaint) { library_foreach_paint(&data, &toolsett->vpaint->paint); @@ -417,7 +460,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (toolsett->sculpt) { library_foreach_paint(&data, &toolsett->sculpt->paint); - CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_CB_NOP); } if (toolsett->uvsculpt) { library_foreach_paint(&data, &toolsett->uvsculpt->paint); @@ -428,7 +471,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u BKE_rigidbody_world_id_loop(scene->rigidbody_world, library_foreach_rigidbodyworldSceneLooper, &data); } - CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_NOP); + CALLBACK_INVOKE(scene->gm.dome.warptext, IDWALK_CB_NOP); break; } @@ -439,75 +482,75 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u ParticleSystem *psys; /* 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; + const int data_cb_flag = data.cb_flag; + const int proxy_cb_flag = (object->proxy || object->proxy_group) ? IDWALK_CB_INDIRECT_USAGE : 0; /* object data special case */ - data.cd_flag |= proxy_cd_flag; + data.cb_flag |= proxy_cb_flag; if (object->type == OB_EMPTY) { /* empty can have NULL or Image */ - CALLBACK_INVOKE_ID(object->data, IDWALK_USER); + CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER); } else { /* when set, this can't be NULL */ if (object->data) { - CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL); + CALLBACK_INVOKE_ID(object->data, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); } } - data.cd_flag = data_cd_flag; + data.cb_flag = data_cb_flag; - CALLBACK_INVOKE(object->parent, IDWALK_NOP); - CALLBACK_INVOKE(object->track, IDWALK_NOP); + CALLBACK_INVOKE(object->parent, IDWALK_CB_NOP); + CALLBACK_INVOKE(object->track, IDWALK_CB_NOP); /* object->proxy is refcounted, but not object->proxy_group... *sigh* */ - CALLBACK_INVOKE(object->proxy, IDWALK_USER); - CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP); + CALLBACK_INVOKE(object->proxy, IDWALK_CB_USER); + CALLBACK_INVOKE(object->proxy_group, IDWALK_CB_NOP); /* Special case! * Since this field is set/owned by 'user' of this ID (and not ID itself), it is only indirect usage * if proxy object is linked... Twisted. */ if (object->proxy_from) { - data.cd_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_INDIRECT_USAGE : 0; + data.cb_flag = ID_IS_LINKED_DATABLOCK(object->proxy_from) ? IDWALK_CB_INDIRECT_USAGE : 0; } - CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP); - data.cd_flag = data_cd_flag; + CALLBACK_INVOKE(object->proxy_from, IDWALK_CB_NOP); + data.cb_flag = data_cb_flag; - CALLBACK_INVOKE(object->poselib, IDWALK_USER); + CALLBACK_INVOKE(object->poselib, IDWALK_CB_USER); - data.cd_flag |= proxy_cd_flag; + data.cb_flag |= proxy_cb_flag; for (i = 0; i < object->totcol; i++) { - CALLBACK_INVOKE(object->mat[i], IDWALK_USER); + CALLBACK_INVOKE(object->mat[i], IDWALK_CB_USER); } - data.cd_flag = data_cd_flag; + data.cb_flag = data_cb_flag; - CALLBACK_INVOKE(object->gpd, IDWALK_USER); - CALLBACK_INVOKE(object->dup_group, IDWALK_USER); + CALLBACK_INVOKE(object->gpd, IDWALK_CB_USER); + CALLBACK_INVOKE(object->dup_group, IDWALK_CB_USER); if (object->pd) { - CALLBACK_INVOKE(object->pd->tex, IDWALK_USER); - CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP); + CALLBACK_INVOKE(object->pd->tex, IDWALK_CB_USER); + CALLBACK_INVOKE(object->pd->f_source, IDWALK_CB_NOP); } /* Note that ob->effect is deprecated, so no need to handle it here. */ if (object->pose) { bPoseChannel *pchan; - data.cd_flag |= proxy_cd_flag; + data.cb_flag |= proxy_cb_flag; for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { - CALLBACK_INVOKE(pchan->custom, IDWALK_USER); + CALLBACK_INVOKE(pchan->custom, IDWALK_CB_USER); BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data); } - data.cd_flag = data_cd_flag; + data.cb_flag = data_cb_flag; } if (object->rigidbody_constraint) { - CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_NOP); - CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_NOP); + CALLBACK_INVOKE(object->rigidbody_constraint->ob1, IDWALK_CB_NOP); + CALLBACK_INVOKE(object->rigidbody_constraint->ob2, IDWALK_CB_NOP); } if (object->lodlevels.first) { LodLevel *level; for (level = object->lodlevels.first; level; level = level->next) { - CALLBACK_INVOKE(level->source, IDWALK_NOP); + CALLBACK_INVOKE(level->source, IDWALK_CB_NOP); } } @@ -519,10 +562,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (object->soft) { - CALLBACK_INVOKE(object->soft->collision_group, IDWALK_NOP); + CALLBACK_INVOKE(object->soft->collision_group, IDWALK_CB_NOP); if (object->soft->effector_weights) { - CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP); + CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_CB_NOP); } } @@ -535,10 +578,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_ME: { Mesh *mesh = (Mesh *) id; - CALLBACK_INVOKE(mesh->texcomesh, IDWALK_USER); - CALLBACK_INVOKE(mesh->key, IDWALK_USER); + CALLBACK_INVOKE(mesh->texcomesh, IDWALK_CB_USER); + CALLBACK_INVOKE(mesh->key, IDWALK_CB_USER); for (i = 0; i < mesh->totcol; i++) { - CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER); + CALLBACK_INVOKE(mesh->mat[i], IDWALK_CB_USER); } /* XXX Really not happy with this - probably texface should rather use some kind of @@ -550,7 +593,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; for (int j = 0; j < mesh->totpoly; j++, txface++) { - CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE); + CALLBACK_INVOKE(txface->tpage, IDWALK_CB_USER_ONE); } } } @@ -560,7 +603,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; for (int j = 0; j < mesh->totface; j++, tface++) { - CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE); + CALLBACK_INVOKE(tface->tpage, IDWALK_CB_USER_ONE); } } } @@ -571,17 +614,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_CU: { Curve *curve = (Curve *) id; - CALLBACK_INVOKE(curve->bevobj, IDWALK_NOP); - CALLBACK_INVOKE(curve->taperobj, IDWALK_NOP); - CALLBACK_INVOKE(curve->textoncurve, IDWALK_NOP); - CALLBACK_INVOKE(curve->key, IDWALK_USER); + CALLBACK_INVOKE(curve->bevobj, IDWALK_CB_NOP); + CALLBACK_INVOKE(curve->taperobj, IDWALK_CB_NOP); + CALLBACK_INVOKE(curve->textoncurve, IDWALK_CB_NOP); + CALLBACK_INVOKE(curve->key, IDWALK_CB_USER); for (i = 0; i < curve->totcol; i++) { - CALLBACK_INVOKE(curve->mat[i], IDWALK_USER); + CALLBACK_INVOKE(curve->mat[i], IDWALK_CB_USER); } - CALLBACK_INVOKE(curve->vfont, IDWALK_USER); - CALLBACK_INVOKE(curve->vfontb, IDWALK_USER); - CALLBACK_INVOKE(curve->vfonti, IDWALK_USER); - CALLBACK_INVOKE(curve->vfontbi, IDWALK_USER); + CALLBACK_INVOKE(curve->vfont, IDWALK_CB_USER); + CALLBACK_INVOKE(curve->vfontb, IDWALK_CB_USER); + CALLBACK_INVOKE(curve->vfonti, IDWALK_CB_USER); + CALLBACK_INVOKE(curve->vfontbi, IDWALK_CB_USER); break; } @@ -589,7 +632,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { MetaBall *metaball = (MetaBall *) id; for (i = 0; i < metaball->totcol; i++) { - CALLBACK_INVOKE(metaball->mat[i], IDWALK_USER); + CALLBACK_INVOKE(metaball->mat[i], IDWALK_CB_USER); } break; } @@ -604,9 +647,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (material->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)material->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&material->nodetree, callback, user_data, flag, &data); } - CALLBACK_INVOKE(material->group, IDWALK_USER); + CALLBACK_INVOKE(material->group, IDWALK_CB_USER); break; } @@ -615,26 +658,26 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u Tex *texture = (Tex *) id; if (texture->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)texture->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&texture->nodetree, callback, user_data, flag, &data); } - CALLBACK_INVOKE(texture->ima, IDWALK_USER); + CALLBACK_INVOKE(texture->ima, IDWALK_CB_USER); if (texture->env) { - CALLBACK_INVOKE(texture->env->object, IDWALK_NOP); - CALLBACK_INVOKE(texture->env->ima, IDWALK_USER); + CALLBACK_INVOKE(texture->env->object, IDWALK_CB_NOP); + CALLBACK_INVOKE(texture->env->ima, IDWALK_CB_USER); } if (texture->pd) - CALLBACK_INVOKE(texture->pd->object, IDWALK_NOP); + CALLBACK_INVOKE(texture->pd->object, IDWALK_CB_NOP); if (texture->vd) - CALLBACK_INVOKE(texture->vd->object, IDWALK_NOP); + CALLBACK_INVOKE(texture->vd->object, IDWALK_CB_NOP); if (texture->ot) - CALLBACK_INVOKE(texture->ot->object, IDWALK_NOP); + CALLBACK_INVOKE(texture->ot->object, IDWALK_CB_NOP); break; } case ID_LT: { Lattice *lattice = (Lattice *) id; - CALLBACK_INVOKE(lattice->key, IDWALK_USER); + CALLBACK_INVOKE(lattice->key, IDWALK_CB_USER); break; } @@ -648,7 +691,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)lamp->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&lamp->nodetree, callback, user_data, flag, &data); } break; } @@ -656,7 +699,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_CA: { Camera *camera = (Camera *) id; - CALLBACK_INVOKE(camera->dof_ob, IDWALK_NOP); + CALLBACK_INVOKE(camera->dof_ob, IDWALK_CB_NOP); break; } @@ -667,14 +710,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u * (see also foreach_libblock_id_users_callback). */ Key *key = (Key *) id; - CALLBACK_INVOKE_ID(key->from, IDWALK_NOP); + CALLBACK_INVOKE_ID(key->from, IDWALK_CB_NOP); break; } case ID_SCR: { bScreen *screen = (bScreen *) id; - CALLBACK_INVOKE(screen->scene, IDWALK_USER_ONE); + CALLBACK_INVOKE(screen->scene, IDWALK_CB_USER_ONE); break; } @@ -688,7 +731,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)world->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&world->nodetree, callback, user_data, flag, &data); } break; } @@ -696,7 +739,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_SPK: { Speaker *speaker = (Speaker *) id; - CALLBACK_INVOKE(speaker->sound, IDWALK_USER); + CALLBACK_INVOKE(speaker->sound, IDWALK_CB_USER); break; } @@ -705,7 +748,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u Group *group = (Group *) id; GroupObject *gob; for (gob = group->gobject.first; gob; gob = gob->next) { - CALLBACK_INVOKE(gob->ob, IDWALK_USER_ONE); + CALLBACK_INVOKE(gob->ob, IDWALK_CB_USER_ONE); } break; } @@ -714,9 +757,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u { bNodeTree *ntree = (bNodeTree *) id; bNode *node; - CALLBACK_INVOKE(ntree->gpd, IDWALK_USER); + CALLBACK_INVOKE(ntree->gpd, IDWALK_CB_USER); for (node = ntree->nodes.first; node; node = node->next) { - CALLBACK_INVOKE_ID(node->id, IDWALK_USER); + CALLBACK_INVOKE_ID(node->id, IDWALK_CB_USER); } break; } @@ -724,9 +767,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_BR: { Brush *brush = (Brush *) id; - CALLBACK_INVOKE(brush->toggle_brush, IDWALK_NOP); - CALLBACK_INVOKE(brush->clone.image, IDWALK_NOP); - CALLBACK_INVOKE(brush->paint_curve, IDWALK_USER); + CALLBACK_INVOKE(brush->toggle_brush, IDWALK_CB_NOP); + CALLBACK_INVOKE(brush->clone.image, IDWALK_CB_NOP); + CALLBACK_INVOKE(brush->paint_curve, IDWALK_CB_USER); library_foreach_mtex(&data, &brush->mtex); library_foreach_mtex(&data, &brush->mask_mtex); break; @@ -735,10 +778,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_PA: { ParticleSettings *psett = (ParticleSettings *) id; - CALLBACK_INVOKE(psett->dup_group, IDWALK_NOP); - CALLBACK_INVOKE(psett->dup_ob, IDWALK_NOP); - CALLBACK_INVOKE(psett->bb_ob, IDWALK_NOP); - CALLBACK_INVOKE(psett->collision_group, IDWALK_NOP); + CALLBACK_INVOKE(psett->dup_group, IDWALK_CB_NOP); + CALLBACK_INVOKE(psett->dup_ob, IDWALK_CB_NOP); + CALLBACK_INVOKE(psett->bb_ob, IDWALK_CB_NOP); + CALLBACK_INVOKE(psett->collision_group, IDWALK_CB_NOP); for (i = 0; i < MAX_MTEX; i++) { if (psett->mtex[i]) { @@ -747,16 +790,16 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (psett->effector_weights) { - CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP); + CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_CB_NOP); } if (psett->pd) { - CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER); - CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP); + CALLBACK_INVOKE(psett->pd->tex, IDWALK_CB_USER); + CALLBACK_INVOKE(psett->pd->f_source, IDWALK_CB_NOP); } if (psett->pd2) { - CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER); - CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP); + CALLBACK_INVOKE(psett->pd2->tex, IDWALK_CB_USER); + CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_CB_NOP); } if (psett->boids) { @@ -767,11 +810,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u for (rule = state->rules.first; rule; rule = rule->next) { if (rule->type == eBoidRuleType_Avoid) { BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - CALLBACK_INVOKE(gabr->ob, IDWALK_NOP); + CALLBACK_INVOKE(gabr->ob, IDWALK_CB_NOP); } else if (rule->type == eBoidRuleType_FollowLeader) { BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - CALLBACK_INVOKE(flbr->ob, IDWALK_NOP); + CALLBACK_INVOKE(flbr->ob, IDWALK_CB_NOP); } } } @@ -787,19 +830,19 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MovieTrackingTrack *track; MovieTrackingPlaneTrack *plane_track; - CALLBACK_INVOKE(clip->gpd, IDWALK_USER); + CALLBACK_INVOKE(clip->gpd, IDWALK_CB_USER); for (track = tracking->tracks.first; track; track = track->next) { - CALLBACK_INVOKE(track->gpd, IDWALK_USER); + CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); } for (object = tracking->objects.first; object; object = object->next) { for (track = object->tracks.first; track; track = track->next) { - CALLBACK_INVOKE(track->gpd, IDWALK_USER); + CALLBACK_INVOKE(track->gpd, IDWALK_CB_USER); } } for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) { - CALLBACK_INVOKE(plane_track->image, IDWALK_USER); + CALLBACK_INVOKE(plane_track->image, IDWALK_CB_USER); } break; } @@ -814,7 +857,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u for (mask_spline = mask_layer->splines.first; mask_spline; mask_spline = mask_spline->next) { for (i = 0; i < mask_spline->tot_point; i++) { MaskSplinePoint *point = &mask_spline->points[i]; - CALLBACK_INVOKE_ID(point->parent.id, IDWALK_USER); + CALLBACK_INVOKE_ID(point->parent.id, IDWALK_CB_USER); } } } @@ -832,14 +875,14 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } if (linestyle->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - library_foreach_ID_as_subdata_link((ID *)linestyle->nodetree, callback, user_data, flag, &data); + library_foreach_ID_as_subdata_link((ID **)&linestyle->nodetree, callback, user_data, flag, &data); } for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)lsm; if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_NOP); + CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); } } } @@ -847,7 +890,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)lsm; if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_NOP); + CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); } } } @@ -855,7 +898,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)lsm; if (p->target) { - CALLBACK_INVOKE(p->target, IDWALK_NOP); + CALLBACK_INVOKE(p->target, IDWALK_CB_NOP); } } } @@ -866,7 +909,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u bAction *act = (bAction *) id; for (TimeMarker *marker = act->markers.first; marker; marker = marker->next) { - CALLBACK_INVOKE(marker->camera, IDWALK_NOP); + CALLBACK_INVOKE(marker->camera, IDWALK_CB_NOP); } break; } @@ -889,7 +932,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u break; } - } while ((id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL)); + } FOREACH_FINALIZE: if (data.ids_handled) { @@ -907,13 +950,13 @@ FOREACH_FINALIZE: /** * re-usable function, use when replacing ID's */ -void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag) +void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cb_flag) { - if (cd_flag & IDWALK_USER) { + if (cb_flag & IDWALK_CB_USER) { id_us_min(id_src); id_us_plus(id_dst); } - else if (cd_flag & IDWALK_USER_ONE) { + else if (cb_flag & IDWALK_CB_USER_ONE) { id_us_ensure_real(id_dst); } } @@ -943,7 +986,7 @@ bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id /* 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 + ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC /* + constraints, modifiers and game logic ID types... */); #else return true; @@ -1047,7 +1090,7 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID * (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 - if (cb_flag & IDWALK_INDIRECT_USAGE) { + if (cb_flag & IDWALK_CB_INDIRECT_USAGE) { iter->count_indirect++; } else { @@ -1078,7 +1121,7 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used) iter.curr_id = id_user; iter.count_direct = iter.count_indirect = 0; - BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP); + BKE_library_foreach_ID_link(NULL, iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_READONLY); return iter.count_direct + iter.count_indirect; } @@ -1107,7 +1150,7 @@ static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked) } iter.curr_id = id_curr; BKE_library_foreach_ID_link( - id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY); is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0); } @@ -1158,7 +1201,7 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo continue; } iter.curr_id = id_curr; - BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + BKE_library_foreach_ID_link(bmain, id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_READONLY); is_defined = (iter.count_direct != 0 && iter.count_indirect != 0); } @@ -1235,7 +1278,8 @@ void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag) /* Unused ID (so far), no need to check it further. */ continue; } - BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); + BKE_library_foreach_ID_link( + bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY); } } } @@ -1262,7 +1306,8 @@ void BKE_library_indirectly_used_data_tag_clear(Main *bmain) /* Local or non-indirectly-used ID (so far), no need to check it further. */ continue; } - BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); + BKE_library_foreach_ID_link( + bmain, id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_READONLY); } } } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index d7d566a9ec0..9946d1cc81f 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -71,6 +71,7 @@ #include "BKE_brush.h" #include "BKE_camera.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" #include "BKE_fcurve.h" @@ -158,6 +159,10 @@ enum { static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id_p, int cb_flag) { + if (cb_flag & IDWALK_CB_PRIVATE) { + return IDWALK_RET_NOP; + } + IDRemap *id_remap_data = user_data; ID *old_id = id_remap_data->old_id; ID *new_id = id_remap_data->new_id; @@ -169,14 +174,14 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id } if (*id_p && (*id_p == old_id)) { - const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0; + const bool is_indirect = (cb_flag & IDWALK_CB_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_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); - const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && + const bool is_never_null = ((cb_flag & IDWALK_CB_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; @@ -185,7 +190,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id 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)) { + if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { id->tag |= LIB_TAG_DOIT; } @@ -203,10 +208,10 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id else { BLI_assert(0); } - if (cb_flag & IDWALK_USER) { + if (cb_flag & IDWALK_CB_USER) { id_remap_data->skipped_refcounted++; } - else if (cb_flag & IDWALK_USER_ONE) { + else if (cb_flag & IDWALK_CB_USER_ONE) { /* No need to count number of times this happens, just a flag is enough. */ id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED; } @@ -216,13 +221,13 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id *id_p = new_id; DAG_id_tag_update_ex(id_remap_data->bmain, id_self, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } - if (cb_flag & IDWALK_USER) { + if (cb_flag & IDWALK_CB_USER) { id_us_min(old_id); /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */ if (new_id) new_id->us++; } - else if (cb_flag & IDWALK_USER_ONE) { + else if (cb_flag & IDWALK_CB_USER_ONE) { id_us_ensure_real(new_id); /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed, * that extra user is processed in final handling... */ @@ -238,7 +243,7 @@ static int foreach_libblock_remap_callback(void *user_data, ID *id_self, ID **id /* 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) + IDRemap *r_id_remap_data, Scene *sce, BaseLegacy *base, const bool skip_indirect, const bool is_indirect) { if (skip_indirect && is_indirect) { r_id_remap_data->skipped_indirect++; @@ -254,6 +259,22 @@ static void libblock_remap_data_preprocess_scene_base_unlink( } } +/* Some remapping unfortunately require extra and/or specific handling, tackle those here. */ +static void libblock_remap_data_preprocess_scene_object_unlink( + IDRemap *r_id_remap_data, Scene *sce, Object *ob, 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 { + BKE_collections_object_remove(r_id_remap_data->bmain, sce, ob, false); + 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)) { @@ -268,7 +289,16 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) /* In case we are unlinking... */ if (!r_id_remap_data->old_id) { /* ... everything from scene. */ - Base *base, *base_next; + Object *ob_iter; + FOREACH_SCENE_OBJECT(sce, ob_iter) + { + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, ob_iter, skip_indirect, is_indirect); + } + FOREACH_SCENE_OBJECT_END + + + BaseLegacy *base, *base_next; for (base = sce->base.first; base; base = base_next) { base_next = base->next; libblock_remap_data_preprocess_scene_base_unlink( @@ -278,8 +308,11 @@ static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) 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); + libblock_remap_data_preprocess_scene_object_unlink( + r_id_remap_data, sce, old_ob, skip_indirect, is_indirect); + + BaseLegacy *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); @@ -325,7 +358,7 @@ static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, } 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); + BKE_group_object_unlink(group, NULL); } } else { @@ -338,23 +371,17 @@ static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmai { /* 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; - } + for (BaseLegacy *base = sce->base.first; base; base = base->next) { + 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 (!(ob->flag & OB_FROMGROUP)) { - base->flag &= ~OB_FROMGROUP; + if (!grp) { + ob->flag &= ~OB_FROMGROUP; } } } @@ -434,7 +461,7 @@ ATTR_NONNULL(1) static void libblock_remap_data( #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); + BKE_library_foreach_ID_link(NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); } else { i = set_listbasepointers(bmain, lb_array); @@ -456,7 +483,7 @@ ATTR_NONNULL(1) static void libblock_remap_data( 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); + NULL, id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); } } } @@ -685,13 +712,17 @@ void BKE_libblock_relink_ex( } } -static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag) +static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cb_flag) { + if (cb_flag & IDWALK_CB_PRIVATE) { + return IDWALK_RET_NOP; + } + ID *id = *id_pointer; if (id) { /* See: NEW_ID macro */ if (id->newid) { - BKE_library_update_ID_link_user(id->newid, id, cd_flag); + BKE_library_update_ID_link_user(id->newid, id, cb_flag); *id_pointer = id->newid; } else if (id->tag & LIB_TAG_NEW) { @@ -711,7 +742,7 @@ void BKE_libblock_relink_to_newid(ID *id) if (ID_IS_LINKED_DATABLOCK(id)) return; - BKE_library_foreach_ID_link(id, id_relink_to_newid_looper, NULL, 0); + BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0); } void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 54945242fe4..435504859a4 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -111,6 +111,12 @@ void BKE_material_free(Material *ma) BKE_icon_id_delete((ID *)ma); BKE_previewimg_free(&ma->preview); + + for (MaterialEngineSettings *mes = ma->engines_settings.first; mes; mes = mes->next) { + if (mes->data) + MEM_SAFE_FREE(mes->data); + } + BLI_freelistN(&ma->engines_settings); } void BKE_material_init(Material *ma) @@ -248,6 +254,8 @@ Material *BKE_material_copy(Main *bmain, Material *ma) BLI_listbase_clear(&man->gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ + BKE_id_copy_ensure_local(bmain, &ma->id, &man->id); return man; @@ -279,6 +287,8 @@ Material *localize_material(Material *ma) man->nodetree = ntreeLocalize(ma->nodetree); BLI_listbase_clear(&man->gpumaterial); + + /* TODO Duplicate Engine Settings and set runtime to NULL */ return man; } @@ -1698,6 +1708,7 @@ void copy_matcopybuf(Material *ma) matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false); matcopybuf.preview = NULL; BLI_listbase_clear(&matcopybuf.gpumaterial); + /* TODO Duplicate Engine Settings and set runtime to NULL */ matcopied = 1; } diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 97033a9555d..2632acea58b 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -316,7 +316,7 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2) void BKE_mball_properties_copy(Scene *scene, Object *active_object) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *ob; MetaBall *active_mball = (MetaBall *)active_object->data; int basisnr, obnr; @@ -359,27 +359,25 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object) */ Object *BKE_mball_basis_find(Scene *scene, Object *basis) { - Scene *sce_iter = scene; - Base *base; - Object *ob, *bob = basis; + Object *bob = basis; int basisnr, obnr; char basisname[MAX_ID_NAME], obname[MAX_ID_NAME]; - SceneBaseIter iter; - EvaluationContext *eval_ctx = G.main->eval_ctx; BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.'); - BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL); - while (BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 1, &base, &ob)) { - if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { - if (ob != bob) { - BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); - - /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ - if (STREQ(obname, basisname)) { - if (obnr < basisnr) { - basis = ob; - basisnr = obnr; + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (Base *base = sl->object_bases.first; base; base = base->next) { + Object *ob = base->object; + if ((ob->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) { + if (ob != bob) { + BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.'); + + /* object ob has to be in same "group" ... it means, that it has to have same base of its name */ + if (STREQ(obname, basisname)) { + if (obnr < basisnr) { + basis = ob; + basisnr = obnr; + } } } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 5c0b09f0ff0..144a885ffd4 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1080,7 +1080,7 @@ static void polygonize(PROCESS *process) static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scene, Object *ob) { Scene *sce_iter = scene; - Base *base; + BaseLegacy *base; Object *bob; MetaBall *mb; const MetaElem *ml; @@ -1102,7 +1102,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen zero_size = 0; ml = NULL; - if (bob == ob && (base->flag & OB_FROMDUPLI) == 0) { + if (bob == ob && (base->flag_legacy & OB_FROMDUPLI) == 0) { mb = ob->data; if (mb->editelems) ml = mb->editelems->first; diff --git a/source/blender/blenkernel/intern/mesh_render.c b/source/blender/blenkernel/intern/mesh_render.c index 4118208d32f..fd0f49810fb 100644 --- a/source/blender/blenkernel/intern/mesh_render.c +++ b/source/blender/blenkernel/intern/mesh_render.c @@ -47,7 +47,7 @@ /* Mesh Interface */ #define MESH_RENDER_FUNCTION(func_name) \ - if (me->edit_btmesh) { \ + if (me->edit_btmesh && me->edit_btmesh->derivedFinal) { \ return mesh_bmesh_##func_name(me); \ } \ else { \ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3f3b4896653..05422a01dbf 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3776,3 +3776,20 @@ bool BKE_node_tree_iter_step(struct NodeTreeIterStore *ntreeiter, return true; } + +/* -------------------------------------------------------------------- */ +/* NodeTree kernel functions */ + +void BKE_nodetree_remove_layer_n(bNodeTree *ntree, Scene *scene, const int layer_index) +{ + for (bNode *node = ntree->nodes.first; node; node = node->next) { + if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { + if (node->custom1 == layer_index) { + node->custom1 = 0; + } + else if (node->custom1 > layer_index) { + node->custom1--; + } + } + } +} diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 171c369b3b0..c0540192422 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -91,6 +91,7 @@ #include "BKE_icons.h" #include "BKE_key.h" #include "BKE_lamp.h" +#include "BKE_layer.h" #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" @@ -153,7 +154,7 @@ void BKE_object_workob_clear(Object *workob) void BKE_object_update_base_layer(struct Scene *scene, Object *ob) { - Base *base = scene->base.first; + BaseLegacy *base = scene->base.first; while (base) { if (base->object == ob) base->lay = ob->lay; @@ -458,6 +459,11 @@ void BKE_object_free(Object *ob) } BKE_previewimg_free(&ob->preview); + + if (ob->collection_settings) { + BKE_layer_collection_engine_settings_free(ob->collection_settings); + MEM_freeN(ob->collection_settings); + } } /* actual check for internal data, not context or flags */ @@ -677,23 +683,25 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name) /* general add: to scene, with layer from area and default name */ /* creates minimum required data, but without vertices etc. */ Object *BKE_object_add( - Main *bmain, Scene *scene, + Main *bmain, Scene *scene, SceneLayer *sl, int type, const char *name) { Object *ob; Base *base; + LayerCollection *lc; ob = BKE_object_add_only_object(bmain, type, name); ob->data = BKE_object_obdata_add_from_type(bmain, type, name); - ob->lay = scene->lay; - - base = BKE_scene_base_add(scene, ob); - BKE_scene_base_deselect_all(scene); - BKE_scene_base_select(scene, base); - DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); + lc = BKE_layer_collection_active(sl); + BKE_collection_object_add(scene, lc->scene_collection, ob); + base = BKE_scene_layer_base_find(sl, ob); + BKE_scene_layer_base_deselect_all(sl); + BKE_scene_layer_base_select(sl, base); + + DAG_id_tag_update_ex(bmain, &ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); return ob; } @@ -1204,7 +1212,7 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con if (lib_local || is_local) { if (!is_lib) { id_clear_lib_data(bmain, &ob->id); - BKE_id_expand_local(&ob->id); + BKE_id_expand_local(bmain, &ob->id); if (clear_proxy) { if (ob->proxy_from != NULL) { ob->proxy_from->proxy = NULL; @@ -2236,18 +2244,6 @@ void BKE_boundbox_minmax(const BoundBox *bb, float obmat[4][4], float r_min[3], } } -void BKE_boundbox_scale(struct BoundBox *bb_dst, const struct BoundBox *bb_src, float scale) -{ - float cent[3]; - BKE_boundbox_calc_center_aabb(bb_src, cent); - - for (int i = 0; i < ARRAY_SIZE(bb_dst->vec); i++) { - bb_dst->vec[i][0] = ((bb_src->vec[i][0] - cent[0]) * scale) + cent[0]; - bb_dst->vec[i][1] = ((bb_src->vec[i][1] - cent[1]) * scale) + cent[1]; - bb_dst->vec[i][2] = ((bb_src->vec[i][2] - cent[2]) * scale) + cent[2]; - } -} - /** * Returns a BBox which each dimensions are at least epsilon. * \note In case a given dimension needs to be enlarged, its final value will be in [epsilon, 3 * epsilon] range. @@ -2554,11 +2550,11 @@ void BKE_scene_foreach_display_point( Scene *scene, View3D *v3d, const short flag, void (*func_cb)(const float[3], void *), void *user_data) { - Base *base; + BaseLegacy *base; Object *ob; for (base = FIRSTBASE; base; base = base->next) { - if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag & flag) == flag) { + if (BASE_VISIBLE_BGMODE(v3d, scene, base) && (base->flag_legacy & flag) == flag) { ob = base->object; if ((ob->transflag & OB_DUPLI) == 0) { @@ -2816,45 +2812,6 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc, return 1; } -/* - * Test a bounding box for ray intersection - * assumes the ray is already local to the boundbox space - */ -bool BKE_boundbox_ray_hit_check( - const struct BoundBox *bb, - const float ray_start[3], const float ray_normal[3], - float *r_lambda) -{ - const int triangle_indexes[12][3] = { - {0, 1, 2}, {0, 2, 3}, - {3, 2, 6}, {3, 6, 7}, - {1, 2, 6}, {1, 6, 5}, - {5, 6, 7}, {4, 5, 7}, - {0, 3, 7}, {0, 4, 7}, - {0, 1, 5}, {0, 4, 5}}; - - bool result = false; - int i; - - for (i = 0; i < 12 && (!result || r_lambda); i++) { - float lambda; - int v1, v2, v3; - v1 = triangle_indexes[i][0]; - v2 = triangle_indexes[i][1]; - v3 = triangle_indexes[i][2]; - if (isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL) && - (!r_lambda || *r_lambda > lambda)) - { - result = true; - if (r_lambda) { - *r_lambda = lambda; - } - } - } - - return result; -} - static int pc_cmp(const void *a, const void *b) { const LinkData *ad = a, *bd = b; @@ -3402,7 +3359,7 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS { LinkNode *links = NULL; - Base *base; + BaseLegacy *base; /* Remove markers from all objects */ for (base = scene->base.first; base; base = base->next) { @@ -3446,7 +3403,7 @@ LinkNode *BKE_object_relational_superset(struct Scene *scene, eObjectSet objectS /* child relationship */ if (includeFilter & (OB_REL_CHILDREN | OB_REL_CHILDREN_RECURSIVE)) { - Base *local_base; + BaseLegacy *local_base; for (local_base = scene->base.first; local_base; local_base = local_base->next) { if (BASE_EDITABLE_BGMODE(((View3D *)NULL), scene, local_base)) { @@ -3492,18 +3449,11 @@ struct LinkNode *BKE_object_groups(Object *ob) return group_linknode; } -void BKE_object_groups_clear(Scene *scene, Base *base, Object *object) +void BKE_object_groups_clear(Object *ob) { Group *group = NULL; - - BLI_assert((base == NULL) || (base->object == object)); - - if (scene && base == NULL) { - base = BKE_scene_base_find(scene, object); - } - - while ((group = BKE_group_object_find(group, base->object))) { - BKE_group_object_unlink(group, object, scene, base); + while ((group = BKE_group_object_find(group, ob))) { + BKE_group_object_unlink(group, ob); } } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index e3b801b3193..26af1c48afb 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -241,7 +241,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild else { unsigned int lay = ctx->scene->lay; int baseid = 0; - Base *base; + BaseLegacy *base; for (base = ctx->scene->base.first; base; base = base->next, baseid++) { Object *ob = base->object; diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 1ea27558545..228ae6afaba 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -633,8 +633,9 @@ void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], floa data->childcachebufs.last = psys->childcachebufs.last; data->totchildcache = psys->totchildcache; - if (psmd->dm_final) - data->dm = CDDM_copy(psmd->dm_final); + if (psmd->dm_final) { + data->dm = CDDM_copy_with_tessface(psmd->dm_final); + } data->totdmvert = psmd->totdmvert; data->totdmedge = psmd->totdmedge; data->totdmface = psmd->totdmface; diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index ee435051151..8531c7c9df9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2896,7 +2896,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, cons ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; - Base *base; + BaseLegacy *base; int distr=0, alloc=0, skip=0; if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET) @@ -4328,12 +4328,12 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, { ParticleTarget *pt; - func(psys, (ID **)&psys->part, userdata, IDWALK_USER | IDWALK_NEVER_NULL); - func(psys, (ID **)&psys->target_ob, userdata, IDWALK_NOP); - func(psys, (ID **)&psys->parent, userdata, IDWALK_NOP); + func(psys, (ID **)&psys->part, userdata, IDWALK_CB_USER | IDWALK_CB_NEVER_NULL); + func(psys, (ID **)&psys->target_ob, userdata, IDWALK_CB_NOP); + func(psys, (ID **)&psys->parent, userdata, IDWALK_CB_NOP); for (pt = psys->targets.first; pt; pt = pt->next) { - func(psys, (ID **)&pt->ob, userdata, IDWALK_NOP); + func(psys, (ID **)&pt->ob, userdata, IDWALK_CB_NOP); } /* Even though psys->part should never be NULL, this can happen as an exception during deletion. @@ -4343,7 +4343,7 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, int p; for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++) { - func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_NOP); + func(psys, (ID **)&pa->boid->ground, userdata, IDWALK_CB_NOP); } } } diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 30eb8dcb287..c3f2107c5af 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3541,7 +3541,7 @@ void BKE_ptcache_bake(PTCacheBaker *baker) Main *bmain = baker->main; Scene *scene = baker->scene; Scene *sce_iter; /* SETLOOPER macro only */ - Base *base; + BaseLegacy *base; ListBase pidlist; PTCacheID *pid = &baker->pid; PointCache *cache = NULL; diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 6f86c68dc07..73fe5ae6cb8 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -974,14 +974,14 @@ void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) { - func(rbw, (ID **)&rbw->group, userdata, IDWALK_NOP); - func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_NOP); - func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_NOP); + func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP); + func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP); + func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP); if (rbw->objects) { int i; for (i = 0; i < rbw->numbodies; i++) { - func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_NOP); + func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP); } } } diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index fa221348932..7920d8b5696 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -992,19 +992,19 @@ void BKE_sca_sensors_id_loop(ListBase *senslist, SCASensorIDFunc func, void *use bSensor *sensor; for (sensor = senslist->first; sensor; sensor = sensor->next) { - func(sensor, (ID **)&sensor->ob, userdata, IDWALK_NOP); + func(sensor, (ID **)&sensor->ob, userdata, IDWALK_CB_NOP); switch (sensor->type) { case SENS_TOUCH: /* DEPRECATED */ { bTouchSensor *ts = sensor->data; - func(sensor, (ID **)&ts->ma, userdata, IDWALK_NOP); + func(sensor, (ID **)&ts->ma, userdata, IDWALK_CB_NOP); break; } case SENS_MESSAGE: { bMessageSensor *ms = sensor->data; - func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_NOP); + func(sensor, (ID **)&ms->fromObject, userdata, IDWALK_CB_NOP); break; } case SENS_ALWAYS: @@ -1035,7 +1035,7 @@ void BKE_sca_controllers_id_loop(ListBase *contlist, SCAControllerIDFunc func, v case CONT_PYTHON: { bPythonCont *pc = controller->data; - func(controller, (ID **)&pc->text, userdata, IDWALK_NOP); + func(controller, (ID **)&pc->text, userdata, IDWALK_CB_NOP); break; } case CONT_LOGIC_AND: @@ -1056,89 +1056,89 @@ void BKE_sca_actuators_id_loop(ListBase *actlist, SCAActuatorIDFunc func, void * bActuator *actuator; for (actuator = actlist->first; actuator; actuator = actuator->next) { - func(actuator, (ID **)&actuator->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&actuator->ob, userdata, IDWALK_CB_NOP); switch (actuator->type) { case ACT_ADD_OBJECT: /* DEPRECATED */ { bAddObjectActuator *aoa = actuator->data; - func(actuator, (ID **)&aoa->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&aoa->ob, userdata, IDWALK_CB_NOP); break; } case ACT_ACTION: { bActionActuator *aa = actuator->data; - func(actuator, (ID **)&aa->act, userdata, IDWALK_NOP); + func(actuator, (ID **)&aa->act, userdata, IDWALK_CB_NOP); break; } case ACT_SOUND: { bSoundActuator *sa = actuator->data; - func(actuator, (ID **)&sa->sound, userdata, IDWALK_NOP); + func(actuator, (ID **)&sa->sound, userdata, IDWALK_CB_NOP); break; } case ACT_EDIT_OBJECT: { bEditObjectActuator *eoa = actuator->data; - func(actuator, (ID **)&eoa->ob, userdata, IDWALK_NOP); - func(actuator, (ID **)&eoa->me, userdata, IDWALK_NOP); + func(actuator, (ID **)&eoa->ob, userdata, IDWALK_CB_NOP); + func(actuator, (ID **)&eoa->me, userdata, IDWALK_CB_NOP); break; } case ACT_SCENE: { bSceneActuator *sa = actuator->data; - func(actuator, (ID **)&sa->scene, userdata, IDWALK_NOP); - func(actuator, (ID **)&sa->camera, userdata, IDWALK_NOP); + func(actuator, (ID **)&sa->scene, userdata, IDWALK_CB_NOP); + func(actuator, (ID **)&sa->camera, userdata, IDWALK_CB_NOP); break; } case ACT_PROPERTY: { bPropertyActuator *pa = actuator->data; - func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP); break; } case ACT_OBJECT: { bObjectActuator *oa = actuator->data; - func(actuator, (ID **)&oa->reference, userdata, IDWALK_NOP); + func(actuator, (ID **)&oa->reference, userdata, IDWALK_CB_NOP); break; } case ACT_CAMERA: { bCameraActuator *ca = actuator->data; - func(actuator, (ID **)&ca->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&ca->ob, userdata, IDWALK_CB_NOP); break; } case ACT_MESSAGE: { bMessageActuator *ma = actuator->data; - func(actuator, (ID **)&ma->toObject, userdata, IDWALK_NOP); + func(actuator, (ID **)&ma->toObject, userdata, IDWALK_CB_NOP); break; } case ACT_2DFILTER: { bTwoDFilterActuator *tdfa = actuator->data; - func(actuator, (ID **)&tdfa->text, userdata, IDWALK_NOP); + func(actuator, (ID **)&tdfa->text, userdata, IDWALK_CB_NOP); break; } case ACT_PARENT: { bParentActuator *pa = actuator->data; - func(actuator, (ID **)&pa->ob, userdata, IDWALK_NOP); + func(actuator, (ID **)&pa->ob, userdata, IDWALK_CB_NOP); break; } case ACT_ARMATURE: { bArmatureActuator *aa = actuator->data; - func(actuator, (ID **)&aa->target, userdata, IDWALK_NOP); - func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_NOP); + func(actuator, (ID **)&aa->target, userdata, IDWALK_CB_NOP); + func(actuator, (ID **)&aa->subtarget, userdata, IDWALK_CB_NOP); break; } case ACT_STEERING: { bSteeringActuator *sa = actuator->data; - func(actuator, (ID **)&sa->target, userdata, IDWALK_NOP); - func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_NOP); + func(actuator, (ID **)&sa->target, userdata, IDWALK_CB_NOP); + func(actuator, (ID **)&sa->navmesh, userdata, IDWALK_CB_NOP); break; } /* Note: some types seems to be non-implemented? ACT_LAMP, ACT_MATERIAL... */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a1338b4ea10..dc81dac134b 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -67,6 +67,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_cachefile.h" +#include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_depsgraph.h" #include "BKE_editmesh.h" @@ -78,6 +79,7 @@ #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_image.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_linestyle.h" @@ -107,6 +109,7 @@ const char *RE_engine_id_BLENDER_RENDER = "BLENDER_RENDER"; const char *RE_engine_id_BLENDER_GAME = "BLENDER_GAME"; +const char *RE_engine_id_BLENDER_CLAY = "BLENDER_CLAY"; const char *RE_engine_id_CYCLES = "CYCLES"; void free_avicodecdata(AviCodecData *acd) @@ -154,13 +157,66 @@ static void remove_sequencer_fcurves(Scene *sce) } } +/* copy SceneCollection tree but keep pointing to the same objects */ +static void scene_collection_copy(SceneCollection *scn, SceneCollection *sc) +{ + BLI_duplicatelist(&scn->objects, &sc->objects); + for (LinkData *link = scn->objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->filter_objects, &sc->filter_objects); + for (LinkData *link = scn->filter_objects.first; link; link = link->next) { + id_us_plus(link->data); + } + + BLI_duplicatelist(&scn->scene_collections, &sc->scene_collections); + SceneCollection *nscn = scn->scene_collections.first; /* nested SceneCollection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + scene_collection_copy(nscn, nsc); + nscn = nscn->next; + } +} + +/* Find the equivalent SceneCollection in the new tree */ +static SceneCollection *scene_collection_from_new_tree(SceneCollection *sc_reference, SceneCollection *scn, SceneCollection *sc) +{ + if (sc == sc_reference) { + return scn; + } + + SceneCollection *nscn = scn->scene_collections.first; /* nested master collection new */ + for (SceneCollection *nsc = sc->scene_collections.first; nsc; nsc = nsc->next) { + + SceneCollection *found = scene_collection_from_new_tree(sc_reference, nscn, nsc); + if (found) { + return found; + } + nscn = nscn->next; + } + return NULL; +} + +/* recreate the LayerCollection tree */ +static void layer_collections_recreate(SceneLayer *sl, ListBase *lb, SceneCollection *mcn, SceneCollection *mc) +{ + for (LayerCollection *lc = lb->first; lc; lc = lc->next) { + + SceneCollection *sc = scene_collection_from_new_tree(lc->scene_collection, mcn, mc); + BLI_assert(sc); + + /* instead of syncronizing both trees we simply re-create it */ + BKE_collection_link(sl, sc); + } +} + Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; FreestyleLineSet *lineset; ToolSettings *ts; - Base *base, *obase; + BaseLegacy *legacy_base, *olegacy_base; if (type == SCE_COPY_EMPTY) { ListBase rl, rv; @@ -214,14 +270,14 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); } - obase = sce->base.first; - base = scen->base.first; - while (base) { - id_us_plus(&base->object->id); - if (obase == sce->basact) scen->basact = base; + olegacy_base = sce->base.first; + legacy_base = scen->base.first; + while (legacy_base) { + id_us_plus(&legacy_base->object->id); + if (olegacy_base == sce->basact) scen->basact = legacy_base; - obase = obase->next; - base = base->next; + olegacy_base = olegacy_base->next; + legacy_base = legacy_base->next; } /* copy action and remove animation used by sequencer */ @@ -244,6 +300,36 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } new_srl = new_srl->next; } + + /* layers and collections */ + scen->collection = MEM_dupallocN(sce->collection); + SceneCollection *mcn = BKE_collection_master(scen); + SceneCollection *mc = BKE_collection_master(sce); + + /* recursively creates a new SceneCollection tree */ + scene_collection_copy(mcn, mc); + + BLI_duplicatelist(&scen->render_layers, &sce->render_layers); + SceneLayer *new_sl = scen->render_layers.first; + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + + /* we start fresh with no overrides and no visibility flags set + * instead of syncing both trees we simply unlink and relink the scene collection */ + BLI_listbase_clear(&new_sl->layer_collections); + BLI_listbase_clear(&new_sl->object_bases); + layer_collections_recreate(new_sl, &sl->layer_collections, mcn, mc); + + if (sl->basact) { + Object *active_ob = sl->basact->object; + for (Base *base = new_sl->object_bases.first; base; base = base->next) { + if (base->object == active_ob) { + new_sl->basact = base; + break; + } + } + } + new_sl = new_sl->next; + } } /* copy color management settings */ @@ -471,6 +557,23 @@ void BKE_scene_free(Scene *sce) BKE_previewimg_free(&sce->preview); curvemapping_free_data(&sce->r.mblur_shutter_curve); + + for (SceneLayer *sl = sce->render_layers.first; sl; sl = sl->next) { + BKE_scene_layer_free(sl); + } + BLI_freelistN(&sce->render_layers); + + /* Master Collection */ + BKE_collection_master_free(sce); + MEM_freeN(sce->collection); + sce->collection = NULL; + + /* Runtime Engine Data */ + for (RenderEngineSettings *res = sce->engines_settings.first; res; res = res->next) { + if (res->data) + MEM_freeN(res->data); + } + BLI_freelistN(&sce->engines_settings); } void BKE_scene_init(Scene *sce) @@ -820,6 +923,12 @@ void BKE_scene_init(Scene *sce) sce->toolsettings->gpencil_v2d_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_seq_align = GP_PROJECT_VIEWSPACE; sce->toolsettings->gpencil_ima_align = GP_PROJECT_VIEWSPACE; + + /* Master Collection */ + sce->collection = MEM_callocN(sizeof(SceneCollection), "Master Collection"); + BLI_strncpy(sce->collection->name, "Master Collection", sizeof(sce->collection->name)); + + BKE_scene_layer_add(sce, "Render Layer"); } Scene *BKE_scene_add(Main *bmain, const char *name) @@ -835,9 +944,9 @@ Scene *BKE_scene_add(Main *bmain, const char *name) return sce; } -Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) +BaseLegacy *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) { - Base *base; + BaseLegacy *base; for (base = scene->base.first; base; base = base->next) { if (STREQ(base->object->id.name + 2, name)) { @@ -848,9 +957,9 @@ Base *BKE_scene_base_find_by_name(struct Scene *scene, const char *name) return base; } -Base *BKE_scene_base_find(Scene *scene, Object *ob) +BaseLegacy *BKE_scene_base_find(Scene *scene, Object *ob) { - return BLI_findptr(&scene->base, ob, offsetof(Base, object)); + return BLI_findptr(&scene->base, ob, offsetof(BaseLegacy, object)); } /** @@ -861,11 +970,10 @@ Base *BKE_scene_base_find(Scene *scene, Object *ob) void BKE_scene_set_background(Main *bmain, Scene *scene) { Scene *sce; - Base *base; + BaseLegacy *base; Object *ob; Group *group; GroupObject *go; - int flag; /* check for cyclic sets, for reading old files but also for definite security (py?) */ BKE_scene_validate_setscene(bmain, scene); @@ -897,13 +1005,7 @@ void BKE_scene_set_background(Main *bmain, Scene *scene) ob->lay = base->lay; /* group patch... */ - base->flag &= ~(OB_FROMGROUP); - flag = ob->flag & (OB_FROMGROUP); - base->flag |= flag; - - /* not too nice... for recovering objects with lost data */ - //if (ob->pose == NULL) base->flag &= ~OB_POSEMODE; - ob->flag = base->flag; + BKE_scene_base_flag_sync_from_base(base); } /* no full animation update, this to enable render code to work (render code calls own animation updates) */ } @@ -924,7 +1026,7 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, - Scene **scene, int val, Base **base, Object **ob) + Scene **scene, int val, BaseLegacy **base, Object **ob) { bool run_again = true; @@ -1006,7 +1108,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } /* handle dupli's */ if (iter->dupob) { - (*base)->flag |= OB_FROMDUPLI; + (*base)->flag_legacy |= OB_FROMDUPLI; *ob = iter->dupob->ob; iter->phase = F_DUPLI; @@ -1025,7 +1127,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, } else if (iter->phase == F_DUPLI) { iter->phase = F_SCENE; - (*base)->flag &= ~OB_FROMDUPLI; + (*base)->flag_legacy &= ~OB_FROMDUPLI; if (iter->dupli_refob) { /* Restore last object's real matrix. */ @@ -1052,7 +1154,7 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Object *BKE_scene_camera_find(Scene *sc) { - Base *base; + BaseLegacy *base; for (base = sc->base.first; base; base = base->next) if (base->object->type == OB_CAMERA) @@ -1154,47 +1256,54 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) return best_marker ? best_marker->name : NULL; } +void BKE_scene_remove_rigidbody_object(Scene *scene, Object *ob) +{ + /* remove rigid body constraint from world before removing object */ + if (ob->rigidbody_constraint) + BKE_rigidbody_remove_constraint(scene, ob); + /* remove rigid body object from world before removing object */ + if (ob->rigidbody_object) + BKE_rigidbody_remove_object(scene, ob); +} -Base *BKE_scene_base_add(Scene *sce, Object *ob) +BaseLegacy *BKE_scene_base_add(Scene *sce, Object *ob) { - Base *b = MEM_callocN(sizeof(*b), __func__); + BaseLegacy *b = MEM_callocN(sizeof(*b), __func__); BLI_addhead(&sce->base, b); b->object = ob; - b->flag = ob->flag; + b->flag_legacy = ob->flag; b->lay = ob->lay; return b; } -void BKE_scene_base_unlink(Scene *sce, Base *base) +void BKE_scene_base_unlink(Scene *sce, BaseLegacy *base) { - /* remove rigid body constraint from world before removing object */ - if (base->object->rigidbody_constraint) - BKE_rigidbody_remove_constraint(sce, base->object); - /* remove rigid body object from world before removing object */ - if (base->object->rigidbody_object) - BKE_rigidbody_remove_object(sce, base->object); - + BKE_scene_remove_rigidbody_object(sce, base->object); + BLI_remlink(&sce->base, base); if (sce->basact == base) sce->basact = NULL; } +/* deprecated, use BKE_scene_layer_base_deselect_all */ void BKE_scene_base_deselect_all(Scene *sce) { - Base *b; + BaseLegacy *b; for (b = sce->base.first; b; b = b->next) { - b->flag &= ~SELECT; - b->object->flag = b->flag; + b->flag_legacy &= ~SELECT; + int flag = b->object->flag & (OB_FROMGROUP); + b->object->flag = b->flag_legacy; + b->object->flag |= flag; } } -void BKE_scene_base_select(Scene *sce, Base *selbase) +void BKE_scene_base_select(Scene *sce, BaseLegacy *selbase) { - selbase->flag |= SELECT; - selbase->object->flag = selbase->flag; + selbase->flag_legacy |= SELECT; + selbase->object->flag = selbase->flag_legacy; sce->basact = selbase; } @@ -1492,15 +1601,7 @@ bool BKE_scene_remove_render_layer(Main *bmain, Scene *scene, SceneRenderLayer * for (sce = bmain->scene.first; sce; sce = sce->id.next) { if (sce->nodetree) { - bNode *node; - for (node = sce->nodetree->nodes.first; node; node = node->next) { - if (node->type == CMP_NODE_R_LAYERS && (Scene *)node->id == scene) { - if (node->custom1 == act) - node->custom1 = 0; - else if (node->custom1 > act) - node->custom1--; - } - } + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act); } } @@ -1588,7 +1689,7 @@ float get_render_aosss_error(const RenderData *r, float error) } /* helper function for the SETLOOPER macro */ -Base *_setlooper_base_step(Scene **sce_iter, Base *base) +BaseLegacy *_setlooper_base_step(Scene **sce_iter, BaseLegacy *base) { if (base && base->next) { /* common case, step to the next */ @@ -1596,12 +1697,12 @@ Base *_setlooper_base_step(Scene **sce_iter, Base *base) } else if (base == NULL && (*sce_iter)->base.first) { /* first time looping, return the scenes first base */ - return (Base *)(*sce_iter)->base.first; + return (BaseLegacy *)(*sce_iter)->base.first; } else { /* reached the end, get the next base in the set */ while ((*sce_iter = (*sce_iter)->set)) { - base = (Base *)(*sce_iter)->base.first; + base = (BaseLegacy *)(*sce_iter)->base.first; if (base) { return base; } @@ -1646,23 +1747,55 @@ bool BKE_scene_uses_blender_game(const Scene *scene) return STREQ(scene->r.engine, RE_engine_id_BLENDER_GAME); } -void BKE_scene_base_flag_to_objects(struct Scene *scene) +void BKE_scene_base_flag_to_objects(SceneLayer *sl) { - Base *base = scene->base.first; + Base *base = sl->object_bases.first; while (base) { - base->object->flag = base->flag; + BKE_scene_object_base_flag_sync_from_base(base); base = base->next; } } -void BKE_scene_base_flag_from_objects(struct Scene *scene) +void BKE_scene_base_flag_sync_from_base(BaseLegacy *base) { - Base *base = scene->base.first; + BKE_scene_object_base_flag_sync_from_base(base); +} - while (base) { - base->flag = base->object->flag; - base = base->next; +void BKE_scene_base_flag_sync_from_object(BaseLegacy *base) +{ + BKE_scene_object_base_flag_sync_from_object(base); +} + +void BKE_scene_object_base_flag_sync_from_base(Base *base) +{ + Object *ob = base->object; + + /* keep the object only flags untouched */ + int flag = ob->flag & OB_FROMGROUP; + + ob->flag = base->flag; + ob->flag |= flag; + + if ((base->flag & BASE_SELECTED) != 0) { + ob->flag |= SELECT; + } + else { + ob->flag &= ~SELECT; + } +} + +void BKE_scene_object_base_flag_sync_from_object(Base *base) +{ + Object *ob = base->object; + base->flag = ob->flag; + + if ((ob->flag & SELECT) != 0) { + base->flag |= BASE_SELECTED; + BLI_assert((base->flag & BASE_SELECTABLED) != 0); + } + else { + base->flag &= ~BASE_SELECTED; } } diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 1d2f5aee440..6a491ba5ec4 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -480,55 +480,74 @@ void BKE_sequencer_editing_free(Scene *scene) static void sequencer_imbuf_assign_spaces(Scene *scene, ImBuf *ibuf) { - if (ibuf->rect_float) { + if (ibuf->rect != NULL) { + IMB_colormanagement_assign_rect_colorspace(ibuf, scene->sequencer_colorspace_settings.name); + } + if (ibuf->rect_float != NULL) { IMB_colormanagement_assign_float_colorspace(ibuf, scene->sequencer_colorspace_settings.name); } } void BKE_sequencer_imbuf_to_sequencer_space(Scene *scene, ImBuf *ibuf, bool make_float) { - const char *from_colorspace = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_SCENE_LINEAR); + /* Early output check: if both buffers are NULL we have nothing to convert. */ + if (ibuf->rect_float == NULL && ibuf->rect == NULL) { + return; + } + /* Get common conversion settings. */ const char *to_colorspace = scene->sequencer_colorspace_settings.name; - const char *float_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); - - if (!ibuf->rect_float) { - if (ibuf->rect) { - const char *byte_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); - if (make_float || !STREQ(to_colorspace, byte_colorspace)) { - /* If byte space is not in sequencer's working space, we deliver float color space, - * this is to to prevent data loss. - */ - - /* when converting byte buffer to float in sequencer we need to make float - * buffer be in sequencer's working space, which is currently only doable - * from linear space. - */ - - /* - * OCIO_TODO: would be nice to support direct single transform from byte to sequencer's - */ - - IMB_float_from_rect(ibuf); - } - else { - return; - } + /* Perform actual conversion logic. */ + if (ibuf->rect_float == NULL) { + /* We are not requested to give float buffer and byte buffer is already + * in thee required colorspace. Can skip doing anything here. + */ + const char *from_colorspace = IMB_colormanagement_get_rect_colorspace(ibuf); + if (!make_float && STREQ(from_colorspace, to_colorspace)) { + return; + } + if (false) { + /* The idea here is to provide as fast playback as possible and + * enforcing float buffer here (a) uses more cache memory (b) might + * make some other effects slower to apply. + * + * However, this might also have negative effect by adding weird + * artifacts which will then not happen in final render. + */ + IMB_colormanagement_transform_byte_threaded( + (unsigned char*)ibuf->rect, ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace); } else { - return; + /* We perform conversion to a float buffer so we don't worry about + * precision loss. + */ + imb_addrectfloatImBuf(ibuf); + IMB_colormanagement_transform_from_byte_threaded( + ibuf->rect_float, (unsigned char*)ibuf->rect, + ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace); + /* We don't need byte buffer anymore. */ + imb_freerectImBuf(ibuf); } } - - if (from_colorspace && from_colorspace[0] != '\0') { - if (ibuf->rect) + else { + const char *from_colorspace = IMB_colormanagement_get_float_colorspace(ibuf); + /* Unknown input color space, can't perform conversion. */ + if (from_colorspace == NULL || from_colorspace[0] == '\0') { + return; + } + /* We don't want both byte and float buffers around: they'll either run + * out of sync or conversion of byte buffer will loose precision in there. + */ + if (ibuf->rect != NULL) { imb_freerectImBuf(ibuf); - - if (!STREQ(float_colorspace, to_colorspace)) { - IMB_colormanagement_transform_threaded(ibuf->rect_float, ibuf->x, ibuf->y, ibuf->channels, - from_colorspace, to_colorspace, true); - sequencer_imbuf_assign_spaces(scene, ibuf); } + IMB_colormanagement_transform_threaded(ibuf->rect_float, + ibuf->x, ibuf->y, ibuf->channels, + from_colorspace, to_colorspace, + true); } + sequencer_imbuf_assign_spaces(scene, ibuf); } void BKE_sequencer_imbuf_from_sequencer_space(Scene *scene, ImBuf *ibuf) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index d0ef5cfc092..f1ce69d3945 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -698,7 +698,7 @@ static float calc_voxel_transp(float *result, float *input, int res[3], int *pix static int get_lamp(Scene *scene, float *light) { - Base *base_tmp = NULL; + BaseLegacy *base_tmp = NULL; int found_lamp = 0; // try to find a lamp, preferably local diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 660107eb2e6..e7df1d810c9 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -530,7 +530,7 @@ static void ccd_build_deflector_hash(Scene *scene, Group *group, Object *vertexo } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { /*Only proceed for mesh object in same layer */ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { ob= base->object; @@ -576,7 +576,7 @@ static void ccd_update_deflector_hash(Scene *scene, Group *group, Object *vertex } } else { - for (Base *base = scene->base.first; base; base = base->next) { + for (BaseLegacy *base = scene->base.first; base; base = base->next) { /*Only proceed for mesh object in same layer */ if (base->object->type == OB_MESH && (base->lay & vertexowner->lay)) { ob= base->object; @@ -986,7 +986,7 @@ static bool are_there_deflectors(Scene *scene, Group *group, unsigned int layer) } } else { - for (Base *base = scene->base.first; base; base= base->next) { + for (BaseLegacy *base = scene->base.first; base; base= base->next) { if ( (base->lay & layer) && base->object->pd) { if (base->object->pd->deflect) return 1; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 22288127119..fe4bcc738c6 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -147,12 +147,12 @@ void BKE_sound_free(bSound *sound) BKE_sound_free_waveform(sound); +#endif /* WITH_AUDASPACE */ if (sound->spinlock) { BLI_spin_end(sound->spinlock); MEM_freeN(sound->spinlock); sound->spinlock = NULL; - } -#endif /* WITH_AUDASPACE */ + } } void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local) @@ -782,7 +782,7 @@ void BKE_sound_read_waveform(bSound *sound, short *stop) void BKE_sound_update_scene(Main *bmain, struct Scene *scene) { Object *ob; - Base *base; + BaseLegacy *base; NlaTrack *track; NlaStrip *strip; Speaker *speaker; diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 88575c7d3be..298790a9e9b 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1935,7 +1935,7 @@ void txt_do_undo(Text *text) int op = text->undo_buf[text->undo_pos]; int prev_flags; unsigned int linep; - unsigned int uchar; + unsigned int uni_char; unsigned int curln, selln; unsigned short curc, selc; unsigned short charp; @@ -1971,14 +1971,14 @@ void txt_do_undo(Text *text) case UNDO_BS_3: case UNDO_BS_4: charp = op - UNDO_BS_1 + 1; - uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); /* get and restore the cursors */ txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uchar); + txt_add_char(text, uni_char); text->undo_pos--; break; @@ -1988,14 +1988,14 @@ void txt_do_undo(Text *text) case UNDO_DEL_3: case UNDO_DEL_4: charp = op - UNDO_DEL_1 + 1; - uchar = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_char = txt_undo_read_unicode(text->undo_buf, &text->undo_pos, charp); /* get and restore the cursors */ txt_undo_read_cur(text->undo_buf, &text->undo_pos, &curln, &curc); txt_move_to(text, curln, curc, 0); txt_move_to(text, curln, curc, 1); - txt_add_char(text, uchar); + txt_add_char(text, uni_char); txt_move_left(text, 0); @@ -2163,7 +2163,7 @@ void txt_do_redo(Text *text) char *buf; unsigned int linep; unsigned short charp; - unsigned int uchar; + unsigned int uni_uchar; unsigned int curln, selln; unsigned short curc, selc; @@ -2190,9 +2190,9 @@ void txt_do_redo(Text *text) txt_move_to(text, curln, curc, 1); charp = op - UNDO_INSERT_1 + 1; - uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp); + uni_uchar = txt_redo_read_unicode(text->undo_buf, &text->undo_pos, charp); - txt_add_char(text, uchar); + txt_add_char(text, uni_uchar); break; case UNDO_BS_1: diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 2d3ecad19ad..60990c03b0e 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -1485,9 +1485,11 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture) /* ------------------------------------------------------------------------- */ -void BKE_texture_get_value( +void BKE_texture_get_value_ex( const Scene *scene, Tex *texture, - float *tex_co, TexResult *texres, bool use_color_management) + float *tex_co, TexResult *texres, + struct ImagePool *pool, + bool use_color_management) { int result_type; bool do_color_manage = false; @@ -1497,7 +1499,7 @@ void BKE_texture_get_value( } /* no node textures for now */ - result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false); + result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false); /* if the texture gave an RGB value, we assume it didn't give a valid * intensity, since this is in the context of modifiers don't use perceptual color conversion. @@ -1510,3 +1512,10 @@ void BKE_texture_get_value( copy_v3_fl(&texres->tr, texres->tin); } } + +void BKE_texture_get_value( + const Scene *scene, Tex *texture, + float *tex_co, TexResult *texres, bool use_color_management) +{ + BKE_texture_get_value_ex(scene, texture, tex_co, texres, NULL, use_color_management); +} |