diff options
Diffstat (limited to 'source/blender/blenkernel/intern/layer.c')
-rw-r--r-- | source/blender/blenkernel/intern/layer.c | 1014 |
1 files changed, 678 insertions, 336 deletions
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index ef4816af54d..caa60450133 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -24,14 +24,18 @@ * \ingroup bke */ +#include <string.h> + #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_depsgraph.h" +#include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_node.h" @@ -42,25 +46,29 @@ #include "DNA_node_types.h" #include "DNA_scene_types.h" +#include "DRW_engine.h" + #include "MEM_guardedalloc.h" +#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH) printf + /* 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 *layer_collection_add(SceneLayer *sl, LayerCollection *parent, 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 IDProperty *collection_engine_settings_create(struct CollectionEngineSettingsCB_Type *ces_type, const bool populate); +static IDProperty *collection_engine_get(IDProperty *root, const int type, const char *engine_name); +static void collection_engine_settings_init(IDProperty *root, const bool populate); static void object_bases_Iterator_next(Iterator *iter, const int flag); /* RenderLayer */ /** * Returns the SceneLayer to be used for rendering + * Most of the time BKE_scene_layer_context_active should be used instead */ -SceneLayer *BKE_scene_layer_active(struct Scene *scene) +SceneLayer *BKE_scene_layer_render_active(const Scene *scene) { SceneLayer *sl = BLI_findlink(&scene->render_layers, scene->active_layer); BLI_assert(sl); @@ -68,6 +76,17 @@ SceneLayer *BKE_scene_layer_active(struct Scene *scene) } /** + * Returns the SceneLayer to be used for drawing, outliner, and + * other context related areas. + */ +SceneLayer *BKE_scene_layer_context_active(Scene *scene) +{ + /* waiting for workspace to get the layer from context*/ + TODO_LAYER_CONTEXT; + return BKE_scene_layer_render_active(scene); +} + +/** * Add a new renderlayer * by default, a renderlayer has the master collection */ @@ -87,7 +106,7 @@ SceneLayer *BKE_scene_layer_add(Scene *scene, const char *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); + layer_collection_add(sl, NULL, sc); return sl; } @@ -129,6 +148,13 @@ bool BKE_scene_layer_remove(Main *bmain, Scene *scene, SceneLayer *sl) void BKE_scene_layer_free(SceneLayer *sl) { sl->basact = NULL; + + for (Base *base = sl->object_bases.first; base; base = base->next) { + if (base->collection_properties) { + IDP_FreeProperty(base->collection_properties); + MEM_freeN(base->collection_properties); + } + } BLI_freelistN(&sl->object_bases); for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { @@ -176,7 +202,7 @@ static bool find_scene_collection_in_scene_collections(ListBase *lb, const Layer /** * Find the SceneLayer a LayerCollection belongs to */ -SceneLayer *BKE_scene_layer_find_from_collection(Scene *scene, LayerCollection *lc) +SceneLayer *BKE_scene_layer_find_from_collection(const 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)) { @@ -210,7 +236,7 @@ void BKE_scene_layer_base_select(struct SceneLayer *sl, Base *selbase) } } -static void scene_layer_object_base_unref(SceneLayer* sl, Base *base) +static void scene_layer_object_base_unref(SceneLayer *sl, Base *base) { base->refcount--; @@ -220,125 +246,14 @@ static void scene_layer_object_base_unref(SceneLayer* sl, Base *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 (base->collection_properties) { + IDP_FreeProperty(base->collection_properties); + MEM_freeN(base->collection_properties); } - 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; - } + BLI_remlink(&sl->object_bases, base); + MEM_freeN(base); } - - sl->flag &= ~SCENE_LAYER_ENGINE_DIRTY; } /** @@ -356,7 +271,11 @@ static Base *object_base_add(SceneLayer *sl, Object *ob) /* do not bump user count, leave it for SceneCollections */ base->object = ob; BLI_addtail(&sl->object_bases, base); + + IDPropertyTemplate val = {0}; + base->collection_properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); } + base->refcount++; return base; } @@ -377,7 +296,16 @@ static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) BLI_freelistN(&lc->object_bases); BLI_freelistN(&lc->overrides); - layer_collection_engine_settings_free(lc); + + if (lc->properties) { + IDP_FreeProperty(lc->properties); + MEM_freeN(lc->properties); + } + + if (lc->properties_evaluated) { + IDP_FreeProperty(lc->properties_evaluated); + MEM_freeN(lc->properties_evaluated); + } for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { layer_collection_free(sl, nlc); @@ -450,7 +378,7 @@ int BKE_layer_collection_count(SceneLayer *sl) /** * Recursively get the index for a given collection */ -static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i) +static int index_from_collection(ListBase *lb, const LayerCollection *lc, int *i) { for (LayerCollection *lcol = lb->first; lcol; lcol = lcol->next) { if (lcol == lc) { @@ -470,19 +398,364 @@ static int index_from_collection(ListBase *lb, LayerCollection *lc, int *i) /** * Return -1 if not found */ -int BKE_layer_collection_findindex(SceneLayer *sl, LayerCollection *lc) +int BKE_layer_collection_findindex(SceneLayer *sl, const LayerCollection *lc) { int i = 0; return index_from_collection(&sl->layer_collections, lc, &i); } /** + * Lookup the listbase that contains \a lc. + */ +static ListBase *layer_collection_listbase_find(ListBase *lb, LayerCollection *lc) +{ + for (LayerCollection *lc_iter = lb->first; lc_iter; lc_iter = lc_iter->next) { + if (lc_iter == lc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = layer_collection_listbase_find(&lc_iter->layer_collections, lc))) { + return lb_child_result; + } + } + + return NULL; +} + +#if 0 +/** + * Lookup the listbase that contains \a sc. + */ +static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *sc) +{ + for (SceneCollection *sc_iter = lb->first; sc_iter; sc_iter = sc_iter->next) { + if (sc_iter == sc) { + return lb; + } + + ListBase *lb_child_result; + if ((lb_child_result = scene_collection_listbase_find(&sc_iter->scene_collections, sc))) { + return lb_child_result; + } + } + + return NULL; +} +#endif + +/* ---------------------------------------------------------------------- */ +/* Outliner drag and drop */ + +/** + * Nest a LayerCollection into another one + * Both collections must be from the same SceneLayer, return true if succeded. + * + * The LayerCollection will effectively be moved into the + * new (nested) position. So all the settings, overrides, ... go with it, and + * if the collection was directly linked to the SceneLayer it's then unlinked. + * + * For the other SceneLayers we simply resync the tree, without changing directly + * linked collections (even if they link to the same SceneCollection) + * + * \param lc_src LayerCollection to nest into \a lc_dst + * \param lc_dst LayerCollection to have \a lc_src inserted into + */ + +static void layer_collection_swap( + SceneLayer *sl, ListBase *lb_a, ListBase *lb_b, + LayerCollection *lc_a, LayerCollection *lc_b) +{ + if (lb_a == NULL) { + lb_a = layer_collection_listbase_find(&sl->layer_collections, lc_a); + } + + if (lb_b == NULL) { + lb_b = layer_collection_listbase_find(&sl->layer_collections, lc_b); + } + + BLI_assert(lb_a); + BLI_assert(lb_b); + + BLI_listbases_swaplinks(lb_a, lb_b, lc_a, lc_b); +} + +/** + * Move \a lc_src into \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + bool is_directly_linked = false; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* We can't nest the collection into itself */ + if (lc_src->scene_collection == lc_dst->scene_collection) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->layer_collections.last == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->scene_collection->scene_collections.last == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->layer_collections.last; + layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_dst->layer_collections.last, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + else { + LayerCollection *lc_temp; + is_directly_linked = BLI_findindex(&sl->layer_collections, lc_src) != -1; + + if (!is_directly_linked) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_into(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = BLI_findptr(&lc_dst->layer_collections, lc_src->scene_collection, offsetof(LayerCollection, scene_collection)); + BLI_assert(lc_new); + layer_collection_swap(sl, &lc_dst->layer_collections, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +/** + * Move \a lc_src above \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1; + const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->prev == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->prev && lc_dst->prev->scene_collection == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->prev; + layer_collection_swap(sl, NULL, NULL, lc_dst->prev, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + /* We don't allow to move above/below a directly linked collection + * unless the source collection is also directly linked */ + else if (is_directly_linked_dst) { + /* Both directly linked to the SceneLayer, just need to swap */ + if (is_directly_linked_src) { + BLI_remlink(&sl->layer_collections, lc_src); + BLI_insertlinkbefore(&sl->layer_collections, lc_dst, lc_src); + return true; + } + else { + return false; + } + } + else { + LayerCollection *lc_temp; + + if (!is_directly_linked_src) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_above(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked_src) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = lc_dst->prev; + BLI_assert(lc_new); + layer_collection_swap(sl, NULL, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +/** + * Move \a lc_src below \a lc_dst. Both have to be stored in \a sl. + * If \a lc_src is directly linked to the SceneLayer it's unlinked + */ +bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + SceneLayer *sl = BKE_scene_layer_find_from_collection(scene, lc_src); + const bool is_directly_linked_src = BLI_findindex(&sl->layer_collections, lc_src) != -1; + const bool is_directly_linked_dst = BLI_findindex(&sl->layer_collections, lc_dst) != -1; + + if ((!sl) || (sl != BKE_scene_layer_find_from_collection(scene, lc_dst))) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (lc_dst->next == lc_src) { + return false; + } + + /* Collection is already where we want it to be in the scene tree + * but we want to swap it in the layer tree still */ + if (lc_dst->next && lc_dst->next->scene_collection == lc_src->scene_collection) { + LayerCollection *lc_swap = lc_dst->next; + layer_collection_swap(sl, NULL, NULL, lc_dst->next, lc_src); + + if (BLI_findindex(&sl->layer_collections, lc_swap) != -1) { + BKE_collection_unlink(sl, lc_swap); + } + return true; + } + /* We don't allow to move above/below a directly linked collection + * unless the source collection is also directly linked */ + else if (is_directly_linked_dst) { + /* Both directly linked to the SceneLayer, just need to swap */ + if (is_directly_linked_src) { + BLI_remlink(&sl->layer_collections, lc_src); + BLI_insertlinkafter(&sl->layer_collections, lc_dst, lc_src); + return true; + } + else { + return false; + } + } + else { + LayerCollection *lc_temp; + + if (!is_directly_linked_src) { + /* lc_src will be invalid after BKE_collection_move_into! + * so we swap it with lc_temp to preserve its settings */ + lc_temp = BKE_collection_link(sl, lc_src->scene_collection); + layer_collection_swap(sl, &sl->layer_collections, NULL, lc_temp, lc_src); + } + + if (!BKE_collection_move_below(scene, lc_dst->scene_collection, lc_src->scene_collection)) { + if (!is_directly_linked_src) { + /* Swap back and remove */ + layer_collection_swap(sl, NULL, NULL, lc_temp, lc_src); + BKE_collection_unlink(sl, lc_temp); + } + return false; + } + } + + LayerCollection *lc_new = lc_dst->next; + BLI_assert(lc_new); + layer_collection_swap(sl, NULL, NULL, lc_new, lc_src); + + /* If it's directly linked, unlink it after the swap */ + if (BLI_findindex(&sl->layer_collections, lc_new) != -1) { + BKE_collection_unlink(sl, lc_new); + } + + return true; +} + +static bool layer_collection_resync(SceneLayer *sl, LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + ListBase collections = {NULL}; + BLI_movelisttolist(&collections, &lc->layer_collections); + + for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { + LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection)); + if (lc_nested) { + BLI_remlink(&collections, lc_nested); + BLI_addtail(&lc->layer_collections, lc_nested); + } + else { + layer_collection_add(sl, lc, sc_nested); + } + } + + for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) { + layer_collection_free(sl, lc_nested); + } + BLI_freelistN(&collections); + + BLI_assert(BLI_listbase_count(&lc->layer_collections) == + BLI_listbase_count(&sc->scene_collections)); + + return true; + } + + for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) { + if (layer_collection_resync(sl, lc_nested, sc)) { + return true; + } + } + + return false; +} + +/** + * Update the scene layers so that any LayerCollection that points + * to \a sc is re-synced again + */ +void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_resync(sl, lc, sc); + } + } +} + +/* ---------------------------------------------------------------------- */ + +/** * 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); + LayerCollection *lc = layer_collection_add(sl, NULL, sc); sl->active_collection = BKE_layer_collection_findindex(sl, lc); return lc; } @@ -494,9 +767,6 @@ LayerCollection *BKE_collection_link(SceneLayer *sl, SceneCollection *sc) 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; @@ -514,9 +784,6 @@ static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Obj } 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) @@ -544,30 +811,39 @@ static void layer_collection_populate(SceneLayer *sl, LayerCollection *lc, Scene 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); + layer_collection_add(sl, lc, nsc); } } -static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, SceneCollection *sc) +static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc) { + IDPropertyTemplate val = {0}; LayerCollection *lc = MEM_callocN(sizeof(LayerCollection), "Collection Base"); - BLI_addtail(lb, lc); lc->scene_collection = sc; - lc->flag = COLLECTION_VISIBLE + COLLECTION_SELECTABLE + COLLECTION_FOLDED; + lc->flag = COLLECTION_VISIBLE | COLLECTION_SELECTABLE; + + lc->properties = IDP_New(IDP_GROUP, &val, ROOT_PROP); + collection_engine_settings_init(lc->properties, false); + + if (parent != NULL) { + BLI_addtail(&parent->layer_collections, lc); + } + else { + BLI_addtail(&sl->layer_collections, lc); + } - 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) +bool BKE_scene_layer_has_collection(SceneLayer *sl, const SceneCollection *sc) { for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { if (find_layer_collection_by_scene_collection(lc, sc) != NULL) { @@ -619,7 +895,7 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc 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); + layer_collection_add(sl, lc_parent, sc); } } } @@ -628,7 +904,7 @@ void BKE_layer_sync_new_scene_collection(Scene *scene, const SceneCollection *sc /** * Add a corresponding ObjectBase to all the equivalent LayerCollection */ -void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *ob) +void BKE_layer_sync_object_link(const 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) { @@ -644,7 +920,7 @@ void BKE_layer_sync_object_link(Scene *scene, SceneCollection *sc, Object *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) +void BKE_layer_sync_object_unlink(const 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) { @@ -653,8 +929,6 @@ void BKE_layer_sync_object_unlink(Scene *scene, SceneCollection *sc, Object *ob) layer_collection_object_remove(sl, found, ob); } } - BKE_scene_layer_base_flag_recalculate(sl); - BKE_scene_layer_engine_settings_object_recalculate(sl, ob); } } @@ -683,14 +957,24 @@ typedef struct CollectionEngineSettingsCB_Type { } CollectionEngineSettingsCB_Type; +static void create_engine_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type) +{ + if (collection_engine_get(scene->collection_properties, COLLECTION_MODE_NONE, ces_type->name)) { + return; + } + + IDProperty *props = collection_engine_settings_create(ces_type, true); + IDP_AddToGroup(scene->collection_properties, props); +} + static void create_engine_settings_layer_collection(LayerCollection *lc, CollectionEngineSettingsCB_Type *ces_type) { - if (BKE_layer_collection_engine_get(lc, ces_type->name)) { + if (BKE_layer_collection_engine_get(lc, COLLECTION_MODE_NONE, ces_type->name)) { return; } - CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); - BLI_addtail(&lc->engine_settings, ces); + IDProperty *props = collection_engine_settings_create(ces_type, false); + IDP_AddToGroup(lc->properties, props); for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { create_engine_settings_layer_collection(lcn, ces_type); @@ -699,6 +983,9 @@ static void create_engine_settings_layer_collection(LayerCollection *lc, Collect static void create_engines_settings_scene(Scene *scene, CollectionEngineSettingsCB_Type *ces_type) { + /* populate the scene with the new settings */ + create_engine_settings_scene(scene, 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); @@ -712,7 +999,8 @@ void BKE_layer_collection_engine_settings_callback_register( CollectionEngineSettingsCB_Type *ces_type; /* cleanup in case it existed */ - ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); + 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); @@ -737,257 +1025,214 @@ 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 + * Create a root IDProperty for this engine * - * Usually we would pass LayerCollection->engine_settings - * But depsgraph uses this for Object->collection_settings + * \param populate whether we want to pre-fill the collection with the default properties */ -CollectionEngineSettings *BKE_layer_collection_engine_settings_create(const char *engine_name) +static IDProperty *collection_engine_settings_create(CollectionEngineSettingsCB_Type *ces_type, const bool populate) { - CollectionEngineSettingsCB_Type *ces_type; - ces_type = BLI_findstring(&R_engines_settings_callbacks, engine_name, offsetof(CollectionEngineSettingsCB_Type, name)); - BLI_assert(ces_type); + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, ces_type->name); + props->subtype = IDP_GROUP_SUB_ENGINE_RENDER; + + /* properties */ + if (populate) { + ces_type->callback(NULL, props); + } - CollectionEngineSettings *ces = collection_engine_settings_create(ces_type); - return ces; + return props; } -/** - * Free the CollectionEngineSettings - */ -void BKE_layer_collection_engine_settings_free(CollectionEngineSettings *ces) +static void layer_collection_create_mode_settings_object(IDProperty *root, const bool populate) { - BLI_freelistN(&ces->properties); + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "ObjectMode"); + props->subtype = IDP_GROUP_SUB_MODE_OBJECT; + + /* properties */ + if (populate) { + OBJECT_collection_settings_create(props); + } + + IDP_AddToGroup(root, props); } -static void layer_collection_engine_settings_free(LayerCollection *lc) +static void layer_collection_create_mode_settings_edit(IDProperty *root, const bool populate) { - for (CollectionEngineSettings *ces = lc->engine_settings.first; ces; ces = ces->next) { - BKE_layer_collection_engine_settings_free(ces); + IDProperty *props; + IDPropertyTemplate val = {0}; + + props = IDP_New(IDP_GROUP, &val, "EditMode"); + props->subtype = IDP_GROUP_SUB_MODE_EDIT; + + /* properties */ + if (populate) { + EDIT_MESH_collection_settings_create(props); } - BLI_freelistN(&lc->engine_settings); + + IDP_AddToGroup(root, props); } -/** - * Initialize the render settings for a single LayerCollection - */ -static void layer_collection_create_engine_settings(LayerCollection *lc) +static void collection_create_render_settings(IDProperty *root, const bool populate) { 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); + IDProperty *props = collection_engine_settings_create(ces_type, populate); + IDP_AddToGroup(root, props); } } -/** - * Return layer collection engine settings for specified engine - */ -CollectionEngineSettings *BKE_layer_collection_engine_get(LayerCollection *lc, const char *engine_name) +static void collection_create_mode_settings(IDProperty *root, const bool populate) { - CollectionEngineSettings *ces; - ces = BLI_findstring(&lc->engine_settings, engine_name, offsetof(CollectionEngineSettings, name)); - return ces; + /* XXX TODO: put all those engines in the R_engines_settings_callbacks + * and have IDP_AddToGroup outside the callbacks */ + layer_collection_create_mode_settings_object(root, populate); + layer_collection_create_mode_settings_edit(root, populate); } -/* ---------------------------------------------------------------------- */ -/* Engine Settings Properties */ - -void BKE_collection_engine_property_add_float(CollectionEngineSettings *ces, const char *name, float value) +static int idproperty_group_subtype(const int mode_type) { - 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); -} + int idgroup_type; -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); + switch (mode_type) { + case COLLECTION_MODE_OBJECT: + idgroup_type = IDP_GROUP_SUB_MODE_OBJECT; + break; + case COLLECTION_MODE_EDIT: + idgroup_type = IDP_GROUP_SUB_MODE_EDIT; + break; + default: + case COLLECTION_MODE_NONE: + return IDP_GROUP_SUB_ENGINE_RENDER; + break; + } + + return idgroup_type; } -CollectionEngineProperty *BKE_collection_engine_property_get(CollectionEngineSettings *ces, const char *name) +/** + * Return collection enginne settings for either Object s of LayerCollection s + */ +static IDProperty *collection_engine_get( + IDProperty *root, const int type, const char *engine_name) { - return BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); + const int subtype = idproperty_group_subtype(type); + + if (subtype == IDP_GROUP_SUB_ENGINE_RENDER) { + return IDP_GetPropertyFromGroup(root, engine_name); + } + else { + IDProperty *prop; + for (prop = root->data.group.first; prop; prop = prop->next) { + if (prop->subtype == subtype) { + return prop; + } + } + } + + BLI_assert(false); + return NULL; } -int BKE_collection_engine_property_value_get_int(CollectionEngineSettings *ces, const char *name) +/** + * Return collection engine settings from Object for specified engine of mode + */ +IDProperty *BKE_object_collection_engine_get(Object *ob, const int type, const char *engine_name) { - CollectionEnginePropertyInt *prop; - prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); - return prop->value; + return collection_engine_get(ob->base_collection_properties, type, engine_name); } - -float BKE_collection_engine_property_value_get_float(CollectionEngineSettings *ces, const char *name) +/** + * Return layer collection engine settings for specified engine + */ +IDProperty *BKE_layer_collection_engine_get(LayerCollection *lc, const int type, const char *engine_name) { - CollectionEnginePropertyFloat *prop; - prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); - return prop->value; + return collection_engine_get(lc->properties, type, engine_name); } -void BKE_collection_engine_property_value_set_int(CollectionEngineSettings *ces, const char *name, int value) +/* ---------------------------------------------------------------------- */ +/* Engine Settings Properties */ + +void BKE_collection_engine_property_add_float(IDProperty *props, const char *name, float value) { - CollectionEnginePropertyInt *prop; - prop = (CollectionEnginePropertyInt *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); - prop->value = value; - prop->data.flag |= COLLECTION_PROP_USE; + IDPropertyTemplate val = {0}; + val.f = value; + IDP_AddToGroup(props, IDP_New(IDP_FLOAT, &val, name)); } -void BKE_collection_engine_property_value_set_float(CollectionEngineSettings *ces, const char *name, float value) +void BKE_collection_engine_property_add_int(IDProperty *props, const char *name, int value) { - CollectionEnginePropertyFloat *prop; - prop = (CollectionEnginePropertyFloat *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); - prop->value = value; - prop->data.flag |= COLLECTION_PROP_USE; + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name)); } -bool BKE_collection_engine_property_use_get(CollectionEngineSettings *ces, const char *name) +void BKE_collection_engine_property_add_bool(IDProperty *props, const char *name, bool value) { - CollectionEngineProperty *prop; - prop = (CollectionEngineProperty *)BLI_findstring(&ces->properties, name, offsetof(CollectionEngineProperty, name)); - return ((prop->flag & COLLECTION_PROP_USE) != 0); + IDPropertyTemplate val = {0}; + val.i = value; + IDP_AddToGroup(props, IDP_New(IDP_INT, &val, name)); } -void BKE_collection_engine_property_use_set(CollectionEngineSettings *ces, const char *name, bool value) +int BKE_collection_engine_property_value_get_int(IDProperty *props, const char *name) { - 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; - } + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? idprop->data.val : 0; } -/* Engine Settings recalculate */ - -static void collection_engine_settings_init(CollectionEngineSettings *ces, const char *engine_name) +float BKE_collection_engine_property_value_get_float(IDProperty *props, const char *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); + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? *((float *)&idprop->data.val) : 0.0f; } -static void collection_engine_settings_copy(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src) +bool BKE_collection_engine_property_value_get_bool(IDProperty *props, const char *name) { - 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); - } + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + return idprop ? idprop->data.val : 0; } -/** - * 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; - } - } +void BKE_collection_engine_property_value_set_int(IDProperty *props, const char *name, int value) +{ + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + idprop->data.val = value; } -static void collection_engine_settings_merge(CollectionEngineSettings *ces_dst, CollectionEngineSettings *ces_src) +void BKE_collection_engine_property_value_set_float(IDProperty *props, const char *name, float value) { - 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); - } + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + *(float *)&idprop->data.val = value; } -static void layer_collection_engine_settings_update( - LayerCollection *lc, CollectionEngineSettings *ces_parent, - Base *base, CollectionEngineSettings *ces_ob) +void BKE_collection_engine_property_value_set_bool(IDProperty *props, const char *name, bool value) { - 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); + IDProperty *idprop = IDP_GetPropertyFromGroup(props, name); + idprop->data.val = value; +} - if (BLI_findptr(&lc->object_bases, base, offsetof(LinkData, data)) != NULL) { - collection_engine_settings_merge(ces_ob, &ces); - } +/* Engine Settings recalculate */ - /* do it recursively */ - for (LayerCollection *lcn = lc->layer_collections.first; lcn; lcn = lcn->next) { - layer_collection_engine_settings_update(lcn, &ces, base, ces_ob); - } +/* get all the default settings defined in scene and merge them here */ +static void collection_engine_settings_init(IDProperty *root, const bool populate) +{ + /* render engines */ + collection_create_render_settings(root, populate); - BKE_layer_collection_engine_settings_free(&ces); + /* mode engines */ + collection_create_mode_settings(root, populate); } /** - * Update the collection settings pointer allocated in the object - * This is to be flushed from the Depsgraph + * Initialize the render setings + * It's used mainly for scenes */ -static void scene_layer_engine_settings_update(SceneLayer *sl, Object *ob, const char *engine_name) +void BKE_layer_collection_engine_settings_create(IDProperty *root) { - 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; + collection_engine_settings_init(root, true); } /* ---------------------------------------------------------------------- */ @@ -1094,3 +1339,100 @@ void BKE_visible_bases_Iterator_end(Iterator *UNUSED(iter)) { /* do nothing */ } + +/* Evaluation */ + +/** + * Reset props + * + * If props_ref is pasted, copy props from it + */ +static void idproperty_reset(IDProperty **props, IDProperty *props_ref) +{ + IDPropertyTemplate val = {0}; + + if (*props) { + IDP_FreeProperty(*props); + MEM_freeN(*props); + } + *props = IDP_New(IDP_GROUP, &val, ROOT_PROP); + + if (props_ref) { + IDP_MergeGroup(*props, props_ref, true); + } +} + +void BKE_layer_eval_layer_collection_pre(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, SceneLayer *scene_layer) +{ + DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name); + for (Base *base = scene_layer->object_bases.first; base != NULL; base = base->next) { + base->flag &= ~(BASE_VISIBLED | BASE_SELECTABLED); + idproperty_reset(&base->collection_properties, scene->collection_properties); + } + + /* TODO(sergey): Is it always required? */ + scene_layer->flag |= SCENE_LAYER_ENGINE_DIRTY; +} + +void BKE_layer_eval_layer_collection(EvaluationContext *UNUSED(eval_ctx), + Scene *scene, + LayerCollection *layer_collection, + LayerCollection *parent_layer_collection) +{ + DEBUG_PRINT("%s on %s, parent %s\n", + __func__, + layer_collection->scene_collection->name, + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE"); + + /* visibility */ + layer_collection->flag_evaluated = layer_collection->flag; + bool is_visible = (layer_collection->flag & COLLECTION_VISIBLE) != 0; + bool is_selectable = is_visible && ((layer_collection->flag & COLLECTION_SELECTABLE) != 0); + + if (parent_layer_collection != NULL) { + is_visible &= (parent_layer_collection->flag_evaluated & COLLECTION_VISIBLE) != 0; + is_selectable &= (parent_layer_collection->flag_evaluated & COLLECTION_SELECTABLE) != 0; + layer_collection->flag_evaluated &= parent_layer_collection->flag_evaluated; + } + + /* overrides */ + if (parent_layer_collection != NULL) { + idproperty_reset(&layer_collection->properties_evaluated, parent_layer_collection->properties_evaluated); + } + else if (layer_collection->prev != NULL) { + idproperty_reset(&layer_collection->properties_evaluated, NULL); + } + else { + idproperty_reset(&layer_collection->properties_evaluated, scene->collection_properties); + } + + if (is_visible) { + IDP_MergeGroup(layer_collection->properties_evaluated, layer_collection->properties, true); + } + + for (LinkData *link = layer_collection->object_bases.first; link != NULL; link = link->next) { + Base *base = link->data; + + if (is_visible) { + IDP_SyncGroupValues(base->collection_properties, layer_collection->properties_evaluated); + base->flag |= BASE_VISIBLED; + } + + if (is_selectable) { + base->flag |= BASE_SELECTABLED; + } + } +} + +void BKE_layer_eval_layer_collection_post(EvaluationContext *UNUSED(eval_ctx), + SceneLayer *scene_layer) +{ + DEBUG_PRINT("%s on %s\n", __func__, scene_layer->name); + /* if base is not selectabled, clear select */ + for (Base *base = scene_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) == 0) { + base->flag &= ~BASE_SELECTED; + } + } +} |