From ff7940640433d65ef3fc9e4662ffc8a171b4a07b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 12 Sep 2017 11:27:22 +0500 Subject: [PATCH 01/11] Fix T52653: Render output of linked scenes conflicts with other scenes with the same name The issue was caused by render result identifier only consist of scene name, which could indeed cause conflicts. On the one hand, there are quite some areas in Blender where we need identifier to be unique to properly address things. Usually this is required for sub-data of IDs, like bones. On another hand, it's not that hard to support this particular case and avoid possible frustration. The idea is, we add library name to render identifier for linked scenes. We use library name and not pointer so we preserve render results through undo stack. Reviewers: campbellbarton, mont29, brecht Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2836 --- source/blender/blenkernel/intern/image.c | 10 ++--- source/blender/blenkernel/intern/sequencer.c | 4 +- .../compositor/nodes/COM_CompositorNode.cpp | 1 + .../compositor/nodes/COM_RenderLayersNode.cpp | 2 +- .../operations/COM_CompositorOperation.cpp | 5 ++- .../operations/COM_CompositorOperation.h | 4 ++ .../operations/COM_RenderLayersProg.cpp | 4 +- .../blender/editors/object/object_bake_api.c | 2 +- .../blender/editors/render/render_internal.c | 4 +- source/blender/editors/render/render_opengl.c | 2 +- .../blender/editors/space_image/image_draw.c | 2 +- .../blender/editors/space_image/image_ops.c | 2 +- source/blender/editors/space_node/node_edit.c | 2 +- .../BlenderStrokeRenderer.cpp | 2 +- .../render/extern/include/RE_pipeline.h | 4 ++ .../blender/render/intern/source/pipeline.c | 39 ++++++++++++++++--- .../bad_level_call_stubs/stubs.c | 2 + source/creator/creator_args.c | 4 +- 18 files changed, 68 insertions(+), 27 deletions(-) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 902076c2d14..f8ed4843a99 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1735,7 +1735,7 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d } { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderStats *stats = re ? RE_GetStats(re) : NULL; if (stats && (scene->r.stamp & R_STAMP_RENDERTIME)) { @@ -2929,7 +2929,7 @@ RenderResult *BKE_image_acquire_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - rr = RE_AcquireResultRead(RE_GetRender(scene->id.name)); + rr = RE_AcquireResultRead(RE_GetSceneRender(scene)); else rr = ima->renders[ima->render_slot]; @@ -2947,7 +2947,7 @@ void BKE_image_release_renderresult(Scene *scene, Image *ima) } else if (ima->type == IMA_TYPE_R_RESULT) { if (ima->render_slot == ima->last_render_slot) - RE_ReleaseResult(RE_GetRender(scene->id.name)); + RE_ReleaseResult(RE_GetSceneRender(scene)); } } @@ -2967,7 +2967,7 @@ void BKE_image_backup_render(Scene *scene, Image *ima, bool free_current_slot) { /* called right before rendering, ima->renders contains render * result pointers for everything but the current render */ - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); int slot = ima->render_slot, last = ima->last_render_slot; if (slot != last) { @@ -3692,7 +3692,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **r_loc if (!r_lock) return NULL; - re = RE_GetRender(iuser->scene->id.name); + re = RE_GetSceneRender(iuser->scene); channels = 4; layer = iuser->layer; diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 05ce9c4bbb6..9b0db300e6d 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -3320,7 +3320,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq } } else { - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); const int totviews = BKE_scene_multiview_num_views_get(&scene->r); int i; ImBuf **ibufs_arr; @@ -3337,7 +3337,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq */ if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) { if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BKE_scene_update_for_newframe(context->eval_ctx, context->bmain, scene, scene->lay); RE_BlenderFrame(re, context->bmain, scene, NULL, camera, scene->lay, frame, false); diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cpp index 9e8b40d8af4..4754f23a167 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cpp @@ -41,6 +41,7 @@ void CompositorNode::convertToOperations(NodeConverter &converter, const Composi NodeInput *depthSocket = this->getInputSocket(2); CompositorOperation *compositorOperation = new CompositorOperation(); + compositorOperation->setScene(context.getScene()); compositorOperation->setSceneName(context.getScene()->id.name); compositorOperation->setRenderData(context.getRenderData()); compositorOperation->setViewName(context.getViewName()); diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp index 9a11ddbbceb..2286db81860 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp @@ -176,7 +176,7 @@ void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { Scene *scene = (Scene *)this->getbNode()->id; - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; if (re != NULL) { testRenderLink(converter, context, re); diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp index 76f74c144f6..15ffff2fc90 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp @@ -51,6 +51,7 @@ CompositorOperation::CompositorOperation() : NodeOperation() this->m_useAlphaInput = false; this->m_active = false; + this->m_scene = NULL; this->m_sceneName[0] = '\0'; this->m_viewName = NULL; } @@ -78,7 +79,7 @@ void CompositorOperation::deinitExecution() return; if (!isBreaked()) { - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); RenderResult *rr = RE_AcquireResultWrite(re); if (rr) { @@ -217,7 +218,7 @@ void CompositorOperation::determineResolution(unsigned int resolution[2], unsign // check actual render resolution with cropping it may differ with cropped border.rendering // FIX for: [31777] Border Crop gives black (easy) - Render *re = RE_GetRender(this->m_sceneName); + Render *re = RE_GetSceneRender(this->m_scene); if (re) { RenderResult *rr = RE_AcquireResultRead(re); if (rr) { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.h b/source/blender/compositor/operations/COM_CompositorOperation.h index e81ba520695..269a065a793 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.h +++ b/source/blender/compositor/operations/COM_CompositorOperation.h @@ -26,11 +26,14 @@ #include "BLI_rect.h" #include "BLI_string.h" +struct Scene; + /** * @brief Compositor output operation */ class CompositorOperation : public NodeOperation { private: + const struct Scene *m_scene; /** * @brief Scene name, used for getting the render output, includes 'SC' prefix. */ @@ -84,6 +87,7 @@ public: CompositorOperation(); const bool isActiveCompositorOutput() const { return this->m_active; } void executeRegion(rcti *rect, unsigned int tileNumber); + void setScene(const struct Scene *scene) { m_scene = scene; } void setSceneName(const char *sceneName) { BLI_strncpy(this->m_sceneName, sceneName, sizeof(this->m_sceneName)); } void setViewName(const char *viewName) { this->m_viewName = viewName; } void setRenderData(const RenderData *rd) { this->m_rd = rd; } diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp index 26654b31e16..d1c654ddb6c 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp @@ -48,7 +48,7 @@ RenderLayersProg::RenderLayersProg(const char *passName, DataType type, int elem void RenderLayersProg::initExecution() { Scene *scene = this->getScene(); - Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL; + Render *re = (scene) ? RE_GetSceneRender(scene) : NULL; RenderResult *rr = NULL; if (re) @@ -179,7 +179,7 @@ void RenderLayersProg::deinitExecution() void RenderLayersProg::determineResolution(unsigned int resolution[2], unsigned int /*preferredResolution*/[2]) { Scene *sce = this->getScene(); - Render *re = (sce) ? RE_GetRender(sce->id.name) : NULL; + Render *re = (sce) ? RE_GetSceneRender(sce) : NULL; RenderResult *rr = NULL; resolution[0] = 0; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index d25730d7c10..122330f7ede 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -1161,7 +1161,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->result = OPERATOR_CANCELLED; - bkr->render = RE_NewRender(bkr->scene->id.name); + bkr->render = RE_NewSceneRender(bkr->scene); /* XXX hack to force saving to always be internal. Whether (and how) to support * external saving will be addressed later */ diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index da14e72f887..26c863d8514 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -305,7 +305,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); lay_override = (v3d && v3d->lay != scene->lay) ? v3d->lay : 0; G.is_break = false; @@ -964,7 +964,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even rj->image = ima; /* setup new render */ - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_update_cb(re, rj, image_rect_update); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 01050eda70b..a27026878e1 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -681,7 +681,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) } /* create render */ - oglrender->re = RE_NewRender(scene->id.name); + oglrender->re = RE_NewSceneRender(scene); /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index e810f4db7dd..8cb23c9e021 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -88,7 +88,7 @@ static void draw_render_info(const bContext *C, float zoomy) { RenderResult *rr; - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd = RE_engine_get_render_data(re); Scene *stats_scene = ED_render_job_get_scene(C); if (stats_scene == NULL) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 3c64d1ebb71..eb01b1856e4 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3632,7 +3632,7 @@ static int render_border_exec(bContext *C, wmOperator *op) { ARegion *ar = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); - Render *re = RE_GetRender(scene->id.name); + Render *re = RE_GetSceneRender(scene); RenderData *rd; rctf border; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 5f8f839025f..e91fd1ee575 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -1321,7 +1321,7 @@ static int node_read_fullsamplelayers_exec(bContext *C, wmOperator *UNUSED(op)) Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); Scene *curscene = CTX_data_scene(C); - Render *re = RE_NewRender(curscene->id.name); + Render *re = RE_NewSceneRender(curscene); WM_cursor_wait(1); RE_MergeFullSample(re, bmain, curscene, snode->nodetree); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 1dbac1848b7..9c478c203e7 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -957,7 +957,7 @@ Render *BlenderStrokeRenderer::RenderScene(Render * /*re*/, bool render) } #endif - Render *freestyle_render = RE_NewRender(freestyle_scene->id.name); + Render *freestyle_render = RE_NewSceneRender(freestyle_scene); RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene, render && get_stroke_count() > 0); diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 0d2e29ba4c8..cf9298bdb9e 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -194,6 +194,10 @@ typedef struct RenderStats { struct Render *RE_NewRender(const char *name); struct Render *RE_GetRender(const char *name); +struct Scene; +struct Render *RE_NewSceneRender(const struct Scene *scene); +struct Render *RE_GetSceneRender(const struct Scene *scene); + /* assign default dummy callbacks */ void RE_InitRenderCB(struct Render *re); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index e078365e1ed..a0ebe241569 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -307,7 +307,6 @@ Render *RE_GetRender(const char *name) return re; } - /* if you want to know exactly what has been done */ RenderResult *RE_AcquireResultRead(Render *re) { @@ -514,6 +513,36 @@ Render *RE_NewRender(const char *name) return re; } +/* MAX_ID_NAME + sizeof(Library->name) + space + null-terminator. */ +#define MAX_SCENE_RENDER_NAME (MAX_ID_NAME + 1024 + 2) + +static void scene_render_name_get(const Scene *scene, + const size_t max_size, + char *render_name) +{ + if (ID_IS_LINKED_DATABLOCK(scene)) { + BLI_snprintf(render_name, max_size, "%s %s", + scene->id.lib->id.name, scene->id.name); + } + else { + BLI_snprintf(render_name, max_size, "%s", scene->id.name); + } +} + +Render *RE_GetSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_GetRender(render_name); +} + +Render *RE_NewSceneRender(const Scene *scene) +{ + char render_name[MAX_SCENE_RENDER_NAME]; + scene_render_name_get(scene, sizeof(render_name), render_name); + return RE_NewRender(render_name); +} + /* called for new renders and when finishing rendering so * we always have valid callbacks on a render */ void RE_InitRenderCB(Render *re) @@ -1913,7 +1942,7 @@ static void do_render_fields_blur_3d(Render *re) */ static void render_scene(Render *re, Scene *sce, int cfra) { - Render *resc = RE_NewRender(sce->id.name); + Render *resc = RE_NewSceneRender(sce); int winx = re->winx, winy = re->winy; sce->r.cfra = cfra; @@ -2348,7 +2377,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) tag_scenes_for_render(re); for (sce = re->main->scene.first; sce; sce = sce->id.next) { if (sce->id.tag & LIB_TAG_DOIT) { - re1 = RE_GetRender(sce->id.name); + re1 = RE_GetSceneRender(sce); if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) { if (sample) { @@ -3858,9 +3887,9 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) scene = scenode; /* get render: it can be called from UI with draw callbacks */ - re = RE_GetRender(scene->id.name); + re = RE_GetSceneRender(scene); if (re == NULL) - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); RE_InitState(re, NULL, &scene->r, NULL, winx, winy, &disprect); re->scene = scene; re->scene_color_manage = BKE_scene_check_color_management_enabled(scene); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 8bc3f709551..6afb6c103e0 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -271,6 +271,7 @@ void RE_sample_material_color( int tri_index, struct DerivedMesh *orcoDm, struct Object *ob) RET_NONE /* nodes */ struct Render *RE_GetRender(const char *name) RET_NULL +struct Render *RE_GetSceneRender(const struct Scene *scene) RET_NULL struct Object *RE_GetCamera(struct Render *re) RET_NULL float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO const float (*RE_object_instance_get_matrix(struct ObjectInstanceRen *obi, int matrix_id))[4] RET_NULL @@ -296,6 +297,7 @@ float texture_value_blend(float tex, float out, float fact, float facg, int blen void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE double elbeemEstimateMemreq(int res, float sx, float sy, float sz, int refine, char *retstr) RET_ZERO struct Render *RE_NewRender(const char *name) RET_NULL +struct Render *RE_NewSceneRender(const struct Scene *scene) RET_NULL void RE_SwapResult(struct Render *re, struct RenderResult **rr) RET_NONE void RE_BlenderFrame(struct Render *re, struct Main *bmain, struct Scene *scene, struct SceneRenderLayer *srl, struct Object *camera_override, unsigned int lay_override, int frame, const bool write_still) RET_NONE bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]) RET_ZERO diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 658a0b2db08..74ae97bfcb8 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1362,7 +1362,7 @@ static int arg_handle_render_frame(int argc, const char **argv, void *data) return 1; } - re = RE_NewRender(scene->id.name); + re = RE_NewSceneRender(scene); BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); @@ -1404,7 +1404,7 @@ static int arg_handle_render_animation(int UNUSED(argc), const char **UNUSED(arg Scene *scene = CTX_data_scene(C); if (scene) { Main *bmain = CTX_data_main(C); - Render *re = RE_NewRender(scene->id.name); + Render *re = RE_NewSceneRender(scene); ReportList reports; BLI_begin_threaded_malloc(); BKE_reports_init(&reports, RPT_STORE); From 7aafa32c09bb93b44f746743b67735b1ae73ab21 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 13 Sep 2017 20:12:19 +0500 Subject: [PATCH 02/11] Fix T51416: Blender Crashes while moving Sliders The issue here was that removing datablock from main database will poke editors update, which includes buttons context to free users of texture. Since Cycles will free datablocks from job thread, it might crash Blender since main thread might be in the middle of drawing. Solved by exposing extra arguments to bpy.data.foo.remove() which indicates whether we want to perform ID user count and interface updates. While scripts shouldn't be using those normally, this is the only way to allow Cycles to skip interface update when removing datablock. Reviewers: mont29 Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2840 --- intern/cycles/blender/blender_mesh.cpp | 4 +- source/blender/makesrna/intern/rna_main_api.c | 111 +++++++++++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 430e1066303..ba95fd84e86 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1080,7 +1080,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -1300,7 +1300,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh, false); + b_data.meshes.remove(b_mesh, false, true, false); } CCL_NAMESPACE_END diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index c110dbff6c4..871f50e992e 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -123,7 +123,8 @@ static void rna_idname_validate(const char *name, char *r_name) } -static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, + int do_unlink, int do_id_user, int do_ui_user) { ID *id = id_ptr->data; if (do_unlink) { @@ -131,7 +132,7 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ RNA_POINTER_INVALIDATE(id_ptr); } else if (ID_REAL_USERS(id) <= 0) { - BKE_libblock_free(bmain, id); + BKE_libblock_free_ex(bmain, id, do_id_user, do_ui_user); RNA_POINTER_INVALIDATE(id_ptr); } else { @@ -184,7 +185,7 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports } } - rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink, true, true); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -661,6 +662,10 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this camera"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this camera"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -739,6 +744,10 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this object"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this object"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -776,6 +785,10 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this material"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this material"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -820,6 +833,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this node tree"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this node tree"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -881,6 +898,10 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mesh data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mesh data"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -921,6 +942,10 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lamp data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lamp data"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1037,6 +1062,10 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this image"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this image"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1076,6 +1105,10 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this lattice data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this lattice data"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1116,6 +1149,10 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this curve data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this curve data"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1154,6 +1191,10 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this metaball data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this metaball data"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1192,6 +1233,10 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this font"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this font"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1230,6 +1275,10 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this texture"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this texture"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1267,6 +1316,10 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this brush"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this brush"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1304,6 +1357,10 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this world"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this world"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1341,6 +1398,10 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this group"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this group"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1380,6 +1441,10 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this speaker data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this speaker data"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1417,6 +1482,10 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this text"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this text"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1467,6 +1536,10 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this sound"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this sound"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1506,6 +1579,10 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this armature data"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this armature data"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1542,6 +1619,10 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this action"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this action"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1578,6 +1659,10 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this particle settings"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this particle settings"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1614,6 +1699,10 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this palette"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this palette"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1694,6 +1783,10 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this grease pencil"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this grease pencil"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1723,6 +1816,10 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this movie clip"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this movie clip"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1775,6 +1872,10 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this mask"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this mask"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1812,6 +1913,10 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); + RNA_def_boolean(func, "do_id_user", true, "", + "Decrement user counter of all datablocks used by this line style"); + RNA_def_boolean(func, "do_ui_user", true, "", + "Make sure interface does not reference this line style"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); From 8c21003248673764128eac7863b8e5b3c196a221 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 14 Sep 2017 22:56:48 +1000 Subject: [PATCH 03/11] Fix T52748: Select shortest face path fails --- source/blender/bmesh/tools/bmesh_path.c | 38 ++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 30b083cacda..9e1ea2e7196 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -38,7 +38,12 @@ /* -------------------------------------------------------------------- */ /* Generic Helpers */ -static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3[3]) +/** + * Use skip options when we want to start measuring from a boundary. + */ +static float step_cost_3_v3_ex( + const float v1[3], const float v2[3], const float v3[3], + bool skip_12, bool skip_23) { float cost, d1[3], d2[3]; @@ -46,7 +51,8 @@ static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3 /* The cost is based on the simple sum of the length of the two edgees... */ sub_v3_v3v3(d1, v2, v1); sub_v3_v3v3(d2, v3, v2); - cost = normalize_v3(d1) + normalize_v3(d2); + cost = ((skip_12 ? 0.0f : normalize_v3(d1)) + + (skip_23 ? 0.0f : normalize_v3(d2))); /* but is biased to give higher values to sharp turns, so that it will take * paths with fewer "turns" when selecting between equal-weighted paths between @@ -56,6 +62,11 @@ static float step_cost_3_v3(const float v1[3], const float v2[3], const float v3 return cost; } +static float step_cost_3_v3( + const float v1[3], const float v2[3], const float v3[3]) +{ + return step_cost_3_v3_ex(v1, v2, v3, false, false); +} /* -------------------------------------------------------------------- */ @@ -364,7 +375,7 @@ LinkNode *BM_mesh_calc_path_edge( /* -------------------------------------------------------------------- */ /* BM_mesh_calc_path_face */ -static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) +static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -392,10 +403,12 @@ static float facetag_cut_cost_edge(BMFace *f_a, BMFace *f_b, BMEdge *e) } #endif - return step_cost_3_v3(f_a_cent, e_cent, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, e_cent, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } -static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) +static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v, const void * const f_endpoints[2]) { float f_a_cent[3]; float f_b_cent[3]; @@ -403,12 +416,14 @@ static float facetag_cut_cost_vert(BMFace *f_a, BMFace *f_b, BMVert *v) BM_face_calc_center_mean_weighted(f_a, f_a_cent); BM_face_calc_center_mean_weighted(f_b, f_b_cent); - return step_cost_3_v3(f_a_cent, v->co, f_b_cent); + return step_cost_3_v3_ex( + f_a_cent, v->co, f_b_cent, + (f_a == f_endpoints[0]), (f_b == f_endpoints[1])); } static void facetag_add_adjacent( Heap *heap, BMFace *f_a, BMFace **faces_prev, float *cost, - const struct BMCalcPathParams *params) + const void * const f_endpoints[2], const struct BMCalcPathParams *params) { const int f_a_index = BM_elem_index_get(f_a); @@ -427,7 +442,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e); + 1.0f : facetag_cut_cost_edge(f_a, f_b, l_iter->e, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -454,7 +469,7 @@ static void facetag_add_adjacent( /* we know 'f_b' is not visited, check it out! */ const int f_b_index = BM_elem_index_get(f_b); const float cost_cut = params->use_topology_distance ? - 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v); + 1.0f : facetag_cut_cost_vert(f_a, f_b, l_a->v, f_endpoints); const float cost_new = cost[f_a_index] + cost_cut; if (cost[f_b_index] > cost_new) { @@ -482,6 +497,9 @@ LinkNode *BM_mesh_calc_path_face( BMFace **faces_prev; int i, totface; + /* Start measuring face path at the face edges, ignoring their centers. */ + const void * const f_endpoints[2] = {f_src, f_dst}; + /* note, would pass BM_EDGE except we are looping over all faces anyway */ // BM_mesh_elem_index_ensure(bm, BM_VERT /* | BM_EDGE */); // NOT NEEDED FOR FACETAG @@ -522,7 +540,7 @@ LinkNode *BM_mesh_calc_path_face( if (!BM_elem_flag_test(f, BM_ELEM_TAG)) { BM_elem_flag_enable(f, BM_ELEM_TAG); - facetag_add_adjacent(heap, f, faces_prev, cost, params); + facetag_add_adjacent(heap, f, faces_prev, cost, f_endpoints, params); } } From fc7ac0bc4995472b2485add560cb380418c62a24 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 14 Sep 2017 23:04:01 +1000 Subject: [PATCH 04/11] Correct error in last commit --- source/blender/bmesh/tools/bmesh_path.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_path.c b/source/blender/bmesh/tools/bmesh_path.c index 9e1ea2e7196..85c591b6684 100644 --- a/source/blender/bmesh/tools/bmesh_path.c +++ b/source/blender/bmesh/tools/bmesh_path.c @@ -45,21 +45,20 @@ static float step_cost_3_v3_ex( const float v1[3], const float v2[3], const float v3[3], bool skip_12, bool skip_23) { - float cost, d1[3], d2[3]; - + float d1[3], d2[3]; /* The cost is based on the simple sum of the length of the two edgees... */ sub_v3_v3v3(d1, v2, v1); sub_v3_v3v3(d2, v3, v2); - cost = ((skip_12 ? 0.0f : normalize_v3(d1)) + - (skip_23 ? 0.0f : normalize_v3(d2))); + const float cost_12 = normalize_v3(d1); + const float cost_23 = normalize_v3(d2); + const float cost = ((skip_12 ? 0.0f : cost_12) + + (skip_23 ? 0.0f : cost_23)); /* but is biased to give higher values to sharp turns, so that it will take * paths with fewer "turns" when selecting between equal-weighted paths between * the two edges */ - cost = cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); - - return cost; + return cost * (1.0f + 0.5f * (2.0f - sqrtf(fabsf(dot_v3v3(d1, d2))))); } static float step_cost_3_v3( From a22590a62ce513752d1ca08b532ad66e36d35898 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 14 Sep 2017 18:55:08 +0500 Subject: [PATCH 05/11] Fix T52537: Dyntopo "detail flood fill" doesn't work in some cases Mainly when object origin is not at the geometry bounding box center. Seems to be straightforward to fix, hopefully it doesn't break some obscure case where this was a desired behavior. --- source/blender/editors/sculpt_paint/sculpt.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index f0c1203004e..c415e6b007e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5530,7 +5530,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; float size; - float bb_min[3], bb_max[3]; + float bb_min[3], bb_max[3], center[3], dim[3]; int i, totnodes; PBVHNode **nodes; @@ -5542,11 +5542,12 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) for (i = 0; i < totnodes; i++) { BKE_pbvh_node_mark_topology_update(nodes[i]); } - /* get the bounding box, store the size to bb_max and center (zero) to bb_min */ + /* get the bounding box, it's center and size */ BKE_pbvh_bounding_box(ob->sculpt->pbvh, bb_min, bb_max); - sub_v3_v3(bb_max, bb_min); - zero_v3(bb_min); - size = max_fff(bb_max[0], bb_max[1], bb_max[2]); + add_v3_v3v3(center, bb_min, bb_max); + mul_v3_fl(center, 0.5f); + sub_v3_v3v3(dim, bb_max, bb_min); + size = max_fff(dim[0], dim[1], dim[2]); /* update topology size */ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); @@ -5556,7 +5557,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) while (BKE_pbvh_bmesh_update_topology( ss->pbvh, PBVH_Collapse | PBVH_Subdivide, - bb_min, NULL, size)) + center, NULL, size)) { for (i = 0; i < totnodes; i++) BKE_pbvh_node_mark_topology_update(nodes[i]); From 3c1c3b64c532182ee9273929e89005f2c195b2be Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 14 Sep 2017 16:34:05 +0200 Subject: [PATCH 06/11] Fix T52729: Decimals not showing over 100m or 100 feet Use same 5 digits precision as we already use for e.g. Object's location, for Object's dimensions too. To be backported to 2.79a, should we do it. --- source/blender/makesrna/intern/rna_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index a167ab03ba1..1f018a6ddfc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2392,7 +2392,7 @@ static void rna_def_object(BlenderRNA *brna) /* only for the transform-panel and conflicts with animating scale */ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_float_funcs(prop, "rna_Object_dimensions_get", "rna_Object_dimensions_set", NULL); - RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, 3); + RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, RNA_TRANSLATION_PREC_DEFAULT); RNA_def_property_ui_text(prop, "Dimensions", "Absolute bounding box dimensions of the object"); RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Object_internal_update"); From c75bd25cd87e8648749f4b19bc90c269b2431251 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 14 Sep 2017 19:43:00 +0500 Subject: [PATCH 07/11] Fix T52732: Particle system volume grid particles out of volume Use more watertight and robust intersection test. It uses now ray to triangle intersection, but it's all fine because segment was covering the whole bounding box anyway. --- .../blenkernel/intern/particle_distribute.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index fe84504327c..1ef4d005f0d 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -39,6 +39,7 @@ #include "BLI_jitter.h" #include "BLI_kdtree.h" #include "BLI_math.h" +#include "BLI_math_geom.h" #include "BLI_rand.h" #include "BLI_sort.h" #include "BLI_task.h" @@ -213,14 +214,22 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) copy_v3_v3(co2, co1); co2[a] += delta[a] + 0.001f*d; co1[a] -= 0.001f*d; - + + struct IsectRayPrecalc isect_precalc; + float ray_direction[3]; + sub_v3_v3v3(ray_direction, co2, co1); + isect_ray_tri_watertight_v3_precalc(&isect_precalc, ray_direction); + /* lets intersect the faces */ for (i=0; iv1].co); copy_v3_v3(v2, mvert[mface->v2].co); copy_v3_v3(v3, mvert[mface->v3].co); - bool intersects_tri = isect_axial_line_segment_tri_v3(a, co1, co2, v2, v3, v1, &lambda); + bool intersects_tri = isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v2, v3, + &lambda, NULL); if (intersects_tri) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; @@ -231,7 +240,10 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) if (mface->v4 && (!intersects_tri || from==PART_FROM_VOLUME)) { copy_v3_v3(v4, mvert[mface->v4].co); - if (isect_axial_line_segment_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) { + if (isect_ray_tri_watertight_v3(co1, + &isect_precalc, + v1, v2, v3, + &lambda, NULL)) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; else From 909da553e347679bf69c7fb0b3ed7570451cf050 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Sep 2017 05:46:30 +1000 Subject: [PATCH 08/11] Fix bpy.utils.resource_path('SYSTEM') output Would return the test path for developer builds: {blender-dirname/release} Now return an empty string when no path is found. --- source/blender/blenkernel/intern/appdir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index f39d8006f76..d059310a0f8 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -329,10 +329,12 @@ static bool get_path_system( return true; } } - /* try EXECUTABLE_DIR/release/folder_name */ - if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) + if (test_path(targetpath, targetpath_len, bprogdir, "release", relfolder)) { return true; + } + /* never use if not existing. */ + targetpath[0] = '\0'; /* end developer overrides */ From 2aa2bec43a7f1fa214833c73d033ae1785c600f3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 15 Sep 2017 05:46:43 +1000 Subject: [PATCH 09/11] Fix T52442: bl_app_templates_system not working Portable builds LOCAL files need to be treated as system instead of using as a fallback to USER templates. --- release/scripts/modules/bpy/utils/__init__.py | 35 +++++++++---------- source/blender/blenkernel/intern/appdir.c | 3 ++ 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 185a0e73279..c3175f93f4e 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -400,27 +400,26 @@ def app_template_paths(subdir=None): :return: app template paths. :rtype: generator """ + # Note: keep in sync with: Blender's BKE_appdir_app_template_any - # note: LOCAL, USER, SYSTEM order matches script resolution order. subdir_tuple = (subdir,) if subdir is not None else () - path = _os.path.join(*( - resource_path('LOCAL'), "scripts", "startup", - "bl_app_templates_user", *subdir_tuple)) - if _os.path.isdir(path): - yield path - else: - path = _os.path.join(*( - resource_path('USER'), "scripts", "startup", - "bl_app_templates_user", *subdir_tuple)) - if _os.path.isdir(path): - yield path - - path = _os.path.join(*( - resource_path('SYSTEM'), "scripts", "startup", - "bl_app_templates_system", *subdir_tuple)) - if _os.path.isdir(path): - yield path + # Avoid adding 'bl_app_templates_system' twice. + # Either we have a portable build or an installed system build. + for resource_type, module_name in ( + ('USER', "bl_app_templates_user"), + ('LOCAL', "bl_app_templates_system"), + ('SYSTEM', "bl_app_templates_system"), + ): + path = resource_path(resource_type) + if path: + path = _os.path.join( + *(path, "scripts", "startup", module_name, *subdir_tuple)) + if _os.path.isdir(path): + yield path + # Only load LOCAL or SYSTEM (never both). + if resource_type == 'LOCAL': + break def preset_paths(subdir): diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index d059310a0f8..6dd852c7875 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -691,13 +691,16 @@ bool BKE_appdir_program_python_search( return is_found; } +/** Keep in sync with `bpy.utils.app_template_paths()` */ static const char *app_template_directory_search[2] = { "startup" SEP_STR "bl_app_templates_user", "startup" SEP_STR "bl_app_templates_system", }; static const int app_template_directory_id[2] = { + /* Only 'USER' */ BLENDER_USER_SCRIPTS, + /* Covers 'LOCAL' & 'SYSTEM'. */ BLENDER_SYSTEM_SCRIPTS, }; From 95a8e73d40004461aa17a60695c29106749325ec Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 15 Sep 2017 11:35:00 +0500 Subject: [PATCH 10/11] Fix copy-paste error in recent particles fix Was intersecting same triangle twice. --- source/blender/blenkernel/intern/particle_distribute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 1ef4d005f0d..9a7980827ad 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -242,7 +242,7 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys) if (isect_ray_tri_watertight_v3(co1, &isect_precalc, - v1, v2, v3, + v1, v3, v4, &lambda, NULL)) { if (from==PART_FROM_FACE) (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST; From 8b3ad25862e47fca9e4ec923f4e9157b278173ed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 15 Sep 2017 12:25:57 +0500 Subject: [PATCH 11/11] Transform: Enable recursion dependency check for new depsgraph --- source/blender/blenkernel/intern/depsgraph.c | 1 + source/blender/depsgraph/DEG_depsgraph.h | 3 +++ .../blender/depsgraph/intern/depsgraph_tag.cc | 17 +++++++++++------ .../editors/transform/transform_conversions.c | 4 ---- 4 files changed, 15 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 019e0df1623..3ddf0f43d30 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2018,6 +2018,7 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho int lasttime; if (!DEG_depsgraph_use_legacy()) { + DEG_scene_flush_update(bmain, sce); return; } diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 945a4785b9c..59b10b95d49 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -134,6 +134,9 @@ void DEG_ids_clear_recalc(struct Main *bmain); /* Flush updates for all IDs */ void DEG_ids_flush_tagged(struct Main *bmain); +/* Flush updates for IDs in a single scene. */ +void DEG_scene_flush_update(struct Main *bmain, struct Scene *scene); + /* Check if something was changed in the database and inform * editors about this. */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index f73bb65e5dc..5adcb3a11b3 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -277,15 +277,20 @@ void DEG_ids_flush_tagged(Main *bmain) scene != NULL; scene = (Scene *)scene->id.next) { - /* TODO(sergey): Only visible scenes? */ - if (scene->depsgraph != NULL) { - DEG::deg_graph_flush_updates( - bmain, - reinterpret_cast(scene->depsgraph)); - } + DEG_scene_flush_update(bmain, scene); } } +void DEG_scene_flush_update(Main *bmain, Scene *scene) +{ + if (scene->depsgraph == NULL) { + return; + } + DEG::deg_graph_flush_updates( + bmain, + reinterpret_cast(scene->depsgraph)); +} + /* Update dependency graph when visible scenes/layers changes. */ void DEG_graph_on_visible_update(Main *bmain, Scene *scene) { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 521179fc1d9..ca49cde4b7a 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5606,9 +5606,7 @@ static void set_trans_object_base_flags(TransInfo *t) } /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */ @@ -5687,9 +5685,7 @@ static int count_proportional_objects(TransInfo *t) /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ DAG_scene_relations_update(G.main, t->scene); -#ifdef WITH_LEGACY_DEPSGRAPH DAG_scene_flush_update(G.main, t->scene, -1, 0); -#endif /* and we store them temporal in base (only used for transform code) */ /* this because after doing updates, the object->recalc is cleared */