From 2bb004e03d11e7d7a0f930ecad66c1d3b744eb39 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 9 Jun 2017 17:16:39 +0200 Subject: Fix crash when deleting active workspace render-layer Also fixes some failing unit-tests for render-layers. --- source/blender/blenkernel/BKE_layer.h | 2 - source/blender/blenkernel/intern/layer.c | 35 ++----------- source/blender/blenkernel/intern/scene.c | 6 ++- source/blender/blenloader/intern/versioning_280.c | 3 +- source/blender/editors/include/ED_scene.h | 11 ++-- source/blender/editors/include/ED_screen.h | 2 + source/blender/editors/render/render_shading.c | 8 +-- source/blender/editors/scene/scene_edit.c | 64 +++++++++++++++++++++++ source/blender/editors/screen/workspace_edit.c | 10 ++++ source/blender/makesrna/intern/rna_scene.c | 13 ++--- 10 files changed, 99 insertions(+), 55 deletions(-) (limited to 'source/blender') diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 17ab0bf0d2b..578cc97466a 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -64,8 +64,6 @@ struct SceneLayer *BKE_scene_layer_context_active_ex(const struct Main *bmain, c struct SceneLayer *BKE_scene_layer_context_active(const struct Scene *scene); struct SceneLayer *BKE_scene_layer_add(struct Scene *scene, const char *name); -bool BKE_scene_layer_remove(struct Main *bmain, struct Scene *scene, struct SceneLayer *sl); - void BKE_scene_layer_free(struct SceneLayer *sl); void BKE_scene_layer_engine_set(struct SceneLayer *sl, const char *engine); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index b088c7b4745..d600f753d75 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -128,39 +128,8 @@ SceneLayer *BKE_scene_layer_add(Scene *scene, const char *name) 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). + * Free (or release) any data used by this SceneLayer. */ void BKE_scene_layer_free(SceneLayer *sl) { @@ -200,6 +169,8 @@ void BKE_scene_layer_free(SceneLayer *sl) BLI_freelistN(&sl->drawdata); MEM_SAFE_FREE(sl->stats); + + MEM_freeN(sl); } /** diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 2f7c9db2de1..fbb24a8ccb5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -581,10 +581,12 @@ 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) { + for (SceneLayer *sl = sce->render_layers.first, *sl_next; sl; sl = sl_next) { + sl_next = sl->next; + + BLI_remlink(&sce->render_layers, sl); BKE_scene_layer_free(sl); } - BLI_freelistN(&sce->render_layers); /* Master Collection */ BKE_collection_master_free(sce); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 8ff156d381c..b0a0d885654 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -79,6 +79,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain) for (bScreen *screen = bmain->screen.first; screen; screen = screen->id.next) { const bScreen *screen_parent = screen_parent_find(screen); WorkSpace *workspace; + SceneLayer *layer = BKE_scene_layer_render_active(screen->scene); ListBase *transform_orientations; if (screen_parent) { @@ -91,7 +92,7 @@ static void do_version_workspaces_create_from_screens(Main *bmain) workspace = BKE_workspace_add(bmain, screen->id.name + 2); } BKE_workspace_layout_add(workspace, screen, screen->id.name + 2); - BKE_workspace_render_layer_set(workspace, screen->scene->render_layers.first); + BKE_workspace_render_layer_set(workspace, layer); transform_orientations = BKE_workspace_transform_orientations_get(workspace); BLI_duplicatelist(transform_orientations, &screen->scene->transform_spaces); diff --git a/source/blender/editors/include/ED_scene.h b/source/blender/editors/include/ED_scene.h index 2f67f7befae..6a4ebf68d3d 100644 --- a/source/blender/editors/include/ED_scene.h +++ b/source/blender/editors/include/ED_scene.h @@ -29,11 +29,14 @@ enum eSceneCopyMethod; -struct Scene *ED_scene_add(struct Main *bmain, bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL(); -bool ED_scene_delete(bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL(); -void ED_scene_exit(bContext *C) ATTR_NONNULL(); -void ED_scene_changed_update(struct Main *bmain, bContext *C, struct Scene *scene_new, +struct Scene *ED_scene_add(struct Main *bmain, struct bContext *C, struct wmWindow *win, enum eSceneCopyMethod method) ATTR_NONNULL(); +bool ED_scene_delete(struct bContext *C, struct Main *bmain, struct wmWindow *win, struct Scene *scene) ATTR_NONNULL(); +void ED_scene_exit(struct bContext *C) ATTR_NONNULL(); +void ED_scene_changed_update(struct Main *bmain, struct bContext *C, struct Scene *scene_new, const struct bScreen *active_screen) ATTR_NONNULL(); +bool ED_scene_render_layer_delete( + struct Main *bmain, struct Scene *scene, struct SceneLayer *layer, + struct ReportList *reports) ATTR_NONNULL(1, 2, 3); void ED_operatortypes_scene(void); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index dec8bf7d615..524ee01c30f 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -143,6 +143,8 @@ bool ED_workspace_delete( struct wmWindowManager *wm, struct wmWindow *win) ATTR_NONNULL(); void ED_workspace_scene_data_sync( struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL(); +void ED_workspace_render_layer_unset( + const struct Main *bmain, const SceneLayer *layer_unset, SceneLayer *layer_new) ATTR_NONNULL(1, 2); struct WorkSpaceLayout *ED_workspace_layout_add( struct WorkSpace *workspace, struct wmWindow *win, diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 5da3da98e6d..43e66fae56c 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -84,6 +84,7 @@ #include "ED_mesh.h" #include "ED_node.h" #include "ED_render.h" +#include "ED_scene.h" #include "ED_screen.h" #include "RNA_define.h" @@ -653,17 +654,16 @@ void SCENE_OT_render_layer_add(wmOperatorType *ot) static int render_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); SceneLayer *sl = BKE_scene_layer_context_active(scene); - if (!BKE_scene_layer_remove(CTX_data_main(C), scene, sl)) { + if (!ED_scene_render_layer_delete(bmain, scene, sl, NULL)) { return OPERATOR_CANCELLED; } - DEG_id_tag_update(&scene->id, 0); - DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); - + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index 776e96bac2c..00a56f3dbc7 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -26,18 +26,24 @@ #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library_remap.h" #include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_report.h" #include "BKE_scene.h" #include "BKE_workspace.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "BLI_compiler_attrs.h" #include "BLI_listbase.h" #include "BLT_translation.h" +#include "DNA_workspace_types.h" + #include "ED_object.h" #include "ED_render.h" #include "ED_scene.h" @@ -128,6 +134,64 @@ void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const b WM_event_add_notifier(C, NC_WINDOW, NULL); } +static bool scene_render_layer_remove_poll( + const Scene *scene, const SceneLayer *layer) +{ + const int act = BLI_findindex(&scene->render_layers, layer); + + if (act == -1) { + return false; + } + else if ((scene->render_layers.first == scene->render_layers.last) && + (scene->render_layers.first == layer)) + { + /* ensure 1 layer is kept */ + return false; + } + + return true; +} + +static void scene_render_layer_remove_unset_nodetrees(const Main *bmain, Scene *scene, SceneLayer *layer) +{ + int act_layer_index = BLI_findindex(&scene->render_layers, layer); + + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + if (sce->nodetree) { + BKE_nodetree_remove_layer_n(sce->nodetree, scene, act_layer_index); + } + } +} + +bool ED_scene_render_layer_delete( + Main *bmain, Scene *scene, SceneLayer *layer, + ReportList *reports) +{ + if (scene_render_layer_remove_poll(scene, layer) == false) { + if (reports) { + BKE_reportf(reports, RPT_ERROR, "Render layer '%s' could not be removed from scene '%s'", + layer->name, scene->id.name + 2); + } + + return false; + } + + BLI_remlink(&scene->render_layers, layer); + BLI_assert(BLI_listbase_is_empty(&scene->render_layers) == false); + scene->active_layer = 0; + + ED_workspace_render_layer_unset(bmain, layer, scene->render_layers.first); + scene_render_layer_remove_unset_nodetrees(bmain, scene, layer); + + BKE_scene_layer_free(layer); + + DEG_id_tag_update(&scene->id, 0); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER | NA_REMOVED, scene); + + return true; +} + static int scene_new_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index d82b84ebede..34def82f16e 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -269,6 +269,16 @@ void ED_workspace_scene_data_sync( BKE_screen_view3d_scene_sync(screen, scene); } +void ED_workspace_render_layer_unset( + const Main *bmain, const SceneLayer *layer_unset, SceneLayer *layer_new) +{ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if (BKE_workspace_render_layer_get(workspace) == layer_unset) { + BKE_workspace_render_layer_set(workspace, layer_new); + } + } +} + /** \} Workspace API */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ee99e295feb..b800cb90d8c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -488,6 +488,7 @@ EnumPropertyItem rna_enum_layer_collection_mode_settings_type_items[] = { #include "ED_mesh.h" #include "ED_keyframing.h" #include "ED_image.h" +#include "ED_scene.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -3092,17 +3093,9 @@ static void rna_SceneLayer_remove( Scene *scene = (Scene *)id; SceneLayer *sl = sl_ptr->data; - if (!BKE_scene_layer_remove(bmain, scene, sl)) { - BKE_reportf(reports, RPT_ERROR, "Render layer '%s' could not be removed from scene '%s'", - sl->name, scene->id.name + 2); - return; + if (ED_scene_render_layer_delete(bmain, scene, sl, reports)) { + RNA_POINTER_INVALIDATE(sl_ptr); } - - RNA_POINTER_INVALIDATE(sl_ptr); - - DEG_id_tag_update(&scene->id, 0); - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } static void rna_ObjectBase_select_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) -- cgit v1.2.3