diff options
author | Jacques Lucke <mail@jlucke.com> | 2019-12-12 13:17:04 +0300 |
---|---|---|
committer | Jacques Lucke <mail@jlucke.com> | 2019-12-12 13:17:04 +0300 |
commit | ee52b2f7d8dde3e9ed56925776d7ad2551388ca0 (patch) | |
tree | 3468488adf3636dccbf8e1f5395e15cc92617e0b /source | |
parent | 6d3cd34bd518220f3fa3bc9bc687836a490fcb8b (diff) | |
parent | 059f7413c4cf2fed8a4189ade4a609f9758f6022 (diff) |
Merge branch 'master' into functions
Diffstat (limited to 'source')
33 files changed, 2094 insertions, 104 deletions
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 536268c067e..fdd3bd7cd86 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -265,7 +265,10 @@ typedef struct SculptSession { float cursor_location[3]; float cursor_normal[3]; float cursor_view_normal[3]; + + /* TODO(jbakker): Replace rv3d adn v3d with ViewContext */ struct RegionView3D *rv3d; + struct View3D *v3d; /* Dynamic mesh preview */ int *preview_vert_index_list; diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index b305e919e76..70fa633eeac 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -93,7 +93,6 @@ enum { /* Use a priority queue to process nodes in the optimal order (for slow callbacks) */ BVH_OVERLAP_USE_THREADING = (1 << 0), BVH_OVERLAP_RETURN_PAIRS = (1 << 1), - BVH_OVERLAP_BREAK_ON_FIRST = (1 << 2), }; enum { /* Use a priority queue to process nodes in the optimal order (for slow callbacks) */ @@ -167,7 +166,8 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex( /* optional callback to test the overlap before adding (must be thread-safe!) */ BVHTree_OverlapCallback callback, void *userdata, - int flag); + const uint max_interactions, + const int flag); BVHTreeOverlap *BLI_bvhtree_overlap(const BVHTree *tree1, const BVHTree *tree2, unsigned int *r_overlap_tot, diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index ae862c5ece5..71f276bc68f 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -122,6 +122,7 @@ typedef struct BVHOverlapData_Shared { typedef struct BVHOverlapData_Thread { BVHOverlapData_Shared *shared; struct BLI_Stack *overlap; /* store BVHTreeOverlap */ + uint max_interactions; /* use for callbacks */ int thread; } BVHOverlapData_Thread; @@ -1186,9 +1187,9 @@ static void tree_overlap_traverse_cb(BVHOverlapData_Thread *data_thread, /** * a version of #tree_overlap_traverse_cb that that break on first true return. */ -static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread, - const BVHNode *node1, - const BVHNode *node2) +static bool tree_overlap_num_recursive(BVHOverlapData_Thread *data_thread, + const BVHNode *node1, + const BVHNode *node2) { BVHOverlapData_Shared *data = data_thread->shared; int j; @@ -1213,20 +1214,23 @@ static bool tree_overlap_traverse_first_cb(BVHOverlapData_Thread *data_thread, overlap->indexA = node1->index; overlap->indexB = node2->index; } - return true; + return (--data_thread->max_interactions) == 0; } } else { for (j = 0; j < node2->totnode; j++) { - if (tree_overlap_traverse_first_cb(data_thread, node1, node2->children[j])) { + if (tree_overlap_num_recursive(data_thread, node1, node2->children[j])) { return true; } } } } else { + const uint max_interactions = data_thread->max_interactions; for (j = 0; j < node1->totnode; j++) { - tree_overlap_traverse_first_cb(data_thread, node1->children[j], node2); + if (tree_overlap_num_recursive(data_thread, node1->children[j], node2)) { + data_thread->max_interactions = max_interactions; + } } } } @@ -1262,17 +1266,16 @@ static void bvhtree_overlap_task_cb(void *__restrict userdata, } } -static void bvhtree_overlap_first_task_cb(void *__restrict userdata, - const int j, - const TaskParallelTLS *__restrict UNUSED(tls)) +static void bvhtree_overlap_num_task_cb(void *__restrict userdata, + const int j, + const TaskParallelTLS *__restrict UNUSED(tls)) { BVHOverlapData_Thread *data = &((BVHOverlapData_Thread *)userdata)[j]; BVHOverlapData_Shared *data_shared = data->shared; - tree_overlap_traverse_first_cb( - data, - data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j], - data_shared->tree2->nodes[data_shared->tree2->totleaf]); + tree_overlap_num_recursive(data, + data_shared->tree1->nodes[data_shared->tree1->totleaf]->children[j], + data_shared->tree2->nodes[data_shared->tree2->totleaf]); } BVHTreeOverlap *BLI_bvhtree_overlap_ex( @@ -1282,14 +1285,14 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex( /* optional callback to test the overlap before adding (must be thread-safe!) */ BVHTree_OverlapCallback callback, void *userdata, - int flag) + const uint max_interactions, + const int flag) { bool use_threading = (flag & BVH_OVERLAP_USE_THREADING) != 0; bool overlap_pairs = (flag & BVH_OVERLAP_RETURN_PAIRS) != 0; - bool break_on_first = (flag & BVH_OVERLAP_BREAK_ON_FIRST) != 0; - /* `RETURN_PAIRS` was not implemented without `BREAK_ON_FIRST`. */ - BLI_assert(overlap_pairs || break_on_first); + /* `RETURN_PAIRS` was not implemented without `max_interations`. */ + BLI_assert(overlap_pairs || max_interactions); const int thread_num = BLI_bvhtree_overlap_thread_num(tree1); int j; @@ -1328,6 +1331,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex( /* init BVHOverlapData_Thread */ data[j].shared = &data_shared; data[j].overlap = overlap_pairs ? BLI_stack_new(sizeof(BVHTreeOverlap), __func__) : NULL; + data[j].max_interactions = max_interactions; /* for callback */ data[j].thread = j; @@ -1339,7 +1343,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap_ex( BLI_task_parallel_range(0, thread_num, data, - break_on_first ? bvhtree_overlap_first_task_cb : bvhtree_overlap_task_cb, + max_interactions ? bvhtree_overlap_num_task_cb : bvhtree_overlap_task_cb, &settings); if (overlap_pairs) { @@ -1374,6 +1378,7 @@ BVHTreeOverlap *BLI_bvhtree_overlap( r_overlap_tot, callback, userdata, + 0, BVH_OVERLAP_USE_THREADING | BVH_OVERLAP_RETURN_PAIRS); } diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index ffdcf179491..82e2151dc01 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -604,7 +604,7 @@ static void bvhtree_overlap_thread_safe(const BVHTree *tree1, BVHTree_OverlapCallback callback, void *userdata) { - BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, BVH_OVERLAP_BREAK_ON_FIRST); + BLI_bvhtree_overlap_ex(tree1, tree2, NULL, callback, userdata, 1, 0); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h index fb456611b15..c8ddffa57c7 100644 --- a/source/blender/depsgraph/DEG_depsgraph_query.h +++ b/source/blender/depsgraph/DEG_depsgraph_query.h @@ -26,6 +26,8 @@ #ifndef __DEG_DEPSGRAPH_QUERY_H__ #define __DEG_DEPSGRAPH_QUERY_H__ +#include "BLI_iterator.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 5edfadd7f41..b9e7908b3ef 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -134,6 +134,7 @@ void DRW_draw_depth_loop_gpencil(struct Depsgraph *depsgraph, struct View3D *v3d, struct GPUViewport *viewport); void DRW_draw_depth_object(struct ARegion *ar, + struct View3D *v3d, struct GPUViewport *viewport, struct Object *object); void DRW_draw_select_id(struct Depsgraph *depsgraph, diff --git a/source/blender/draw/engines/overlay/overlay_edit_mesh.c b/source/blender/draw/engines/overlay/overlay_edit_mesh.c index c8f98702e60..56fbc3cca01 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_mesh.c +++ b/source/blender/draw/engines/overlay/overlay_edit_mesh.c @@ -360,7 +360,9 @@ void OVERLAY_edit_mesh_draw(OVERLAY_Data *vedata) OVERLAY_PrivateData *pd = vedata->stl->pd; OVERLAY_FramebufferList *fbl = vedata->fbl; - GPU_framebuffer_bind(fbl->overlay_default_fb); + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(fbl->overlay_default_fb); + } DRW_draw_pass(psl->edit_mesh_weight_ps); DRW_draw_pass(psl->edit_mesh_analysis_ps); diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index 41d099772ee..06044ff92b3 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -74,7 +74,7 @@ static void OVERLAY_engine_init(void *vedata) } pd->wireframe_mode = (v3d->shading.type == OB_WIRE); - pd->clipping_state = (rv3d->rflag & RV3D_CLIPPING) ? DRW_STATE_CLIP_PLANES : 0; + pd->clipping_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0; pd->xray_enabled = XRAY_ACTIVE(v3d); pd->xray_enabled_and_not_wire = pd->xray_enabled && v3d->shading.type > OB_WIRE; pd->clear_in_front = (v3d->shading.type != OB_SOLID); diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 42375f29d4d..f07b21ebcc2 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -116,6 +116,8 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->preferences = &U; View3D *v3d = draw_ctx->v3d; + RegionView3D *rv3d = draw_ctx->rv3d; + if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) { wpd->shading = scene->display.shading; wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); @@ -193,22 +195,19 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wd->curvature_valley = 0.7f / max_ff(SQUARE(wpd->shading.curvature_valley_factor), 1e-4f); /* Will be NULL when rendering. */ - if (draw_ctx->rv3d != NULL) { - RegionView3D *rv3d = draw_ctx->rv3d; - if (rv3d->rflag & RV3D_CLIPPING) { - wpd->world_clip_planes = rv3d->clip; - UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color); - if (wpd->use_color_management) { - srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color); - } - else { - copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color); - } + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { + wpd->world_clip_planes = rv3d->clip; + UI_GetThemeColor4fv(TH_V3D_CLIPPING_BORDER, wpd->world_clip_planes_color); + if (wpd->use_color_management) { + srgb_to_linearrgb_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color); } else { - wpd->world_clip_planes = NULL; + copy_v3_v3(wpd->world_clip_planes_color, wpd->world_clip_planes_color); } } + else { + wpd->world_clip_planes = NULL; + } workbench_world_data_update_shadow_direction_vs(wpd); workbench_world_data_ubo_ensure(scene, wpd); diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c index da5ab0c3122..8e61750da38 100644 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ b/source/blender/draw/engines/workbench/workbench_deferred.c @@ -716,7 +716,7 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata) } DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - if (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb) { + if (RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) { GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND); grp = DRW_shgroup_create(shader, psl->background_pass); wpd->world_clip_planes_batch = DRW_draw_background_clipping_batch_from_rv3d(draw_ctx->rv3d); diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c index 87f3b28c665..dbd7ebfe0d1 100644 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ b/source/blender/draw/engines/workbench/workbench_forward.c @@ -421,7 +421,7 @@ void workbench_forward_engine_init(WORKBENCH_Data *vedata) /* TODO(campbell): displays but masks geometry, * only use with wire or solid-without-xray for now. */ if ((wpd->shading.type != OB_WIRE && !XRAY_FLAG_ENABLED(wpd)) && - (draw_ctx->rv3d && (draw_ctx->rv3d->rflag & RV3D_CLIPPING) && draw_ctx->rv3d->clipbb)) { + RV3D_CLIPPING_ENABLED(draw_ctx->v3d, draw_ctx->rv3d)) { psl->background_pass = DRW_pass_create("Background", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR_BACKGROUND); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 4bfae75848b..5832db31c4e 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -584,7 +584,7 @@ static void drw_context_state_init(void) } DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_DEFAULT; - if (DST.draw_ctx.rv3d && DST.draw_ctx.rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(DST.draw_ctx.v3d, DST.draw_ctx.rv3d)) { DST.draw_ctx.sh_cfg = GPU_SHADER_CFG_CLIPPED; } } @@ -1235,7 +1235,7 @@ static void drw_engines_draw_text(void) PROFILE_START(stime); if (data->text_draw_cache) { - DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar); + DRW_text_cache_draw(data->text_draw_cache, DST.draw_ctx.ar, DST.draw_ctx.v3d); } PROFILE_END_UPDATE(data->render_time, stime); @@ -2571,7 +2571,7 @@ static void draw_world_clip_planes_from_rv3d(GPUBatch *batch, const float world_ /** * Clears the Depth Buffer and draws only the specified object. */ -void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) +void DRW_draw_depth_object(ARegion *ar, View3D *v3d, GPUViewport *viewport, Object *object) { RegionView3D *rv3d = ar->regiondata; @@ -2588,7 +2588,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) GPU_depth_test(true); const float(*world_clip_planes)[4] = NULL; - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_set(rv3d); ED_view3d_clipping_local(rv3d, object->obmat); world_clip_planes = rv3d->clip_local; @@ -2625,7 +2625,7 @@ void DRW_draw_depth_object(ARegion *ar, GPUViewport *viewport, Object *object) break; } - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_disable(); } diff --git a/source/blender/draw/intern/draw_manager_text.c b/source/blender/draw/intern/draw_manager_text.c index b6dab0b2077..9462a0d8072 100644 --- a/source/blender/draw/intern/draw_manager_text.c +++ b/source/blender/draw/intern/draw_manager_text.c @@ -119,7 +119,7 @@ void DRW_text_cache_add(DRWTextStore *dt, } } -void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar) +void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar, struct View3D *v3d) { RegionView3D *rv3d = ar->regiondata; ViewCachedString *vos; @@ -147,7 +147,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar) if (tot) { int col_pack_prev = 0; - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_disable(); } @@ -185,7 +185,7 @@ void DRW_text_cache_draw(DRWTextStore *dt, ARegion *ar) GPU_matrix_pop(); GPU_matrix_projection_set(original_proj); - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_enable(); } } diff --git a/source/blender/draw/intern/draw_manager_text.h b/source/blender/draw/intern/draw_manager_text.h index 5e9692ff490..a8eb45ee8f5 100644 --- a/source/blender/draw/intern/draw_manager_text.h +++ b/source/blender/draw/intern/draw_manager_text.h @@ -41,7 +41,7 @@ void DRW_text_cache_add(struct DRWTextStore *dt, short flag, const uchar col[4]); -void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar); +void DRW_text_cache_draw(struct DRWTextStore *dt, struct ARegion *ar, struct View3D *v3d); void DRW_text_edit_mesh_measure_stats(struct ARegion *ar, struct View3D *v3d, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 1adbbe30286..4c4aa4214b2 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1460,7 +1460,8 @@ static bool point_is_visible(KnifeTool_OpData *kcd, BMFace *f_hit; /* If box clipping on, make sure p is not clipped */ - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING && ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d) && + ED_view3d_clipping_test(kcd->vc.rv3d, p, true)) { return false; } @@ -1484,7 +1485,7 @@ static bool point_is_visible(KnifeTool_OpData *kcd, dist = kcd->vc.v3d->clip_end * 2.0f; } - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { float view_clip[2][3]; /* note: view_clip[0] should never get clipped */ copy_v3_v3(view_clip[0], p_ofs); @@ -1935,7 +1936,7 @@ static int knife_sample_screen_density(KnifeTool_OpData *kcd, const float radius dis_sq = len_squared_v2v2(kfv->sco, sco); if (dis_sq < radius_sq) { - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { c++; } @@ -2045,7 +2046,7 @@ static KnifeEdge *knife_find_closest_edge( /* now we have 'lambda' calculated (in screen-space) */ knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda); - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { /* check we're in the view */ if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) { continue; @@ -2152,7 +2153,7 @@ static KnifeVert *knife_find_closest_vert( dis_sq = len_squared_v2v2(kfv->sco, sco); if (dis_sq < curdis_sq && dis_sq < maxdist_sq) { - if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(kcd->vc.v3d, kcd->vc.rv3d)) { if (ED_view3d_clipping_test(kcd->vc.rv3d, kfv->cageco, true) == 0) { curv = kfv; curdis_sq = dis_sq; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 510d734451b..c57490041bc 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -887,7 +887,7 @@ static bool project_bucket_point_occluded(const ProjPaintState *ps, const float pixelScreenCo[4]) { int isect_ret; - const bool do_clip = ps->rv3d ? (ps->rv3d->rflag & RV3D_CLIPPING) != 0 : 0; + const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d); /* we could return 0 for 1 face buckets, as long as this function assumes * that the point its testing is only every originated from an existing face */ @@ -3024,7 +3024,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const bool is_ortho = ps->is_ortho; const bool is_flip_object = ps->is_flip_object; const bool do_backfacecull = ps->do_backfacecull; - const bool do_clip = ps->rv3d ? ps->rv3d->rflag & RV3D_CLIPPING : 0; + const bool do_clip = RV3D_CLIPPING_ENABLED(ps->v3d, ps->rv3d); vCo[0] = ps->mvert_eval[lt_vtri[0]].co; vCo[1] = ps->mvert_eval[lt_vtri[1]].co; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index f813be7d0a2..b26d706bbf4 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1013,6 +1013,7 @@ void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar, Object *ob) void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) { RegionView3D *rv3d = ss->cache ? ss->cache->vc->rv3d : ss->rv3d; + View3D *v3d = ss->cache ? ss->cache->vc->v3d : ss->v3d; test->radius_squared = ss->cache ? ss->cache->radius_squared : ss->cursor_radius * ss->cursor_radius; @@ -1033,7 +1034,7 @@ void sculpt_brush_test_init(SculptSession *ss, SculptBrushTest *test) test->mirror_symmetry_pass = ss->cache ? ss->cache->mirror_symmetry_pass : 0; - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { test->clip_rv3d = rv3d; } else { @@ -6896,6 +6897,7 @@ static float sculpt_raycast_init(ViewContext *vc, float dist; Object *ob = vc->obact; RegionView3D *rv3d = vc->ar->regiondata; + View3D *v3d = vc->v3d; /* TODO: what if the segment is totally clipped? (return == 0) */ ED_view3d_win_to_segment_clipped( @@ -6910,7 +6912,7 @@ static float sculpt_raycast_init(ViewContext *vc, if ((rv3d->is_persp == false) && /* if the ray is clipped, don't adjust its start/end */ - ((rv3d->rflag & RV3D_CLIPPING) == 0)) { + RV3D_CLIPPING_ENABLED(v3d, rv3d)) { BKE_pbvh_raycast_project_ray_root(ob->sculpt->pbvh, original, ray_start, ray_end, ray_normal); /* recalculate the normal */ @@ -7005,6 +7007,7 @@ bool sculpt_cursor_geometry_info_update(bContext *C, copy_v3_v3(ss->cursor_normal, srd.face_normal); copy_v3_v3(ss->cursor_location, out->location); ss->rv3d = vc.rv3d; + ss->v3d = vc.v3d; if (!BKE_brush_use_locked_size(scene, brush)) { radius = paint_calc_object_space_radius(&vc, out->location, BKE_brush_size_get(scene, brush)); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 0e408077206..9a6f685f5fc 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2172,6 +2172,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eModifierType_Wireframe: data.icon = ICON_MOD_WIREFRAME; break; + case eModifierType_Weld: + data.icon = ICON_AUTOMERGE_OFF; /* XXX, needs own icon */ + break; case eModifierType_LaplacianDeform: data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ break; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 6235f994272..061977d0c91 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -796,7 +796,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a GPU_clear(GPU_DEPTH_BIT); - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_set(rv3d); } /* get surface depth without bias */ @@ -817,7 +817,7 @@ void ED_view3d_draw_depth(Depsgraph *depsgraph, ARegion *ar, View3D *v3d, bool a WM_draw_region_viewport_unbind(ar); - if (rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { ED_view3d_clipping_disable(); } rv3d->rflag &= ~RV3D_ZOFFSET_DISABLED; diff --git a/source/blender/editors/space_view3d/view3d_draw_legacy.c b/source/blender/editors/space_view3d/view3d_draw_legacy.c index 17b575cedae..38cb5ad8651 100644 --- a/source/blender/editors/space_view3d/view3d_draw_legacy.c +++ b/source/blender/editors/space_view3d/view3d_draw_legacy.c @@ -228,7 +228,7 @@ void ED_view3d_backbuf_depth_validate(ViewContext *vc) if (obact_eval && ((obact_eval->base_flag & BASE_VISIBLE_DEPSGRAPH) != 0)) { GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0); - DRW_draw_depth_object(vc->ar, viewport, obact_eval); + DRW_draw_depth_object(vc->ar, vc->v3d, viewport, obact_eval); } vc->v3d->flag &= ~V3D_INVALID_BACKBUF; diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index d7f7e96ba08..8b4012d6547 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1099,7 +1099,7 @@ int view3d_opengl_select(ViewContext *vc, GPU_depth_test(true); } - if (vc->rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(vc->v3d, vc->rv3d)) { ED_view3d_clipping_set(vc->rv3d); } @@ -1167,7 +1167,7 @@ int view3d_opengl_select(ViewContext *vc, GPU_depth_test(false); } - if (vc->rv3d->rflag & RV3D_CLIPPING) { + if (RV3D_CLIPPING_ENABLED(v3d, vc->rv3d)) { ED_view3d_clipping_disable(); } diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index 336f9974e7d..f19147baa89 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -1743,6 +1743,13 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) RegionView3D *rv3d = ar->regiondata; struct TransformBounds tbounds; + if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { + gzgroup->use_fallback_keymap = true; + } + else { + gzgroup->use_fallback_keymap = false; + } + if (ggd->use_twtype_refresh) { ggd->twtype = v3d->gizmo_show_object & ggd->twtype_init; if (ggd->twtype != ggd->twtype_prev) { @@ -1829,13 +1836,6 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup) for (int i = MAN_AXIS_RANGE_ROT_START; i < MAN_AXIS_RANGE_ROT_END; i++) { ggd->gizmos[i]->select_bias = rotate_select_bias; } - - if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { - gzgroup->use_fallback_keymap = true; - } - else { - gzgroup->use_fallback_keymap = false; - } } static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C, @@ -2176,6 +2176,13 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr struct TransformBounds tbounds; + if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { + gzgroup->use_fallback_keymap = true; + } + else { + gzgroup->use_fallback_keymap = false; + } + const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene, SCE_ORIENT_SCALE); @@ -2231,13 +2238,6 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgr /* Needed to test view orientation changes. */ copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv); - - if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { - gzgroup->use_fallback_keymap = true; - } - else { - gzgroup->use_fallback_keymap = false; - } } static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C, @@ -2388,6 +2388,16 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata; struct TransformBounds tbounds; + if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { + gzgroup->use_fallback_keymap = true; + } + else { + gzgroup->use_fallback_keymap = false; + } + + /* Needed to test view orientation changes. */ + copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv); + const TransformOrientationSlot *orient_slot = BKE_scene_orientation_slot_get(scene, SCE_ORIENT_ROTATE); @@ -2440,16 +2450,6 @@ static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzg WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, false); } } - - /* Needed to test view orientation changes. */ - copy_m3_m4(xgzgroup->prev.viewinv_m3, rv3d->viewinv); - - if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) { - gzgroup->use_fallback_keymap = true; - } - else { - gzgroup->use_fallback_keymap = false; - } } static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C, diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 75a860de053..1c986c3c260 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -86,11 +86,12 @@ typedef enum ModifierType { eModifierType_MeshSequenceCache = 52, eModifierType_SurfaceDeform = 53, eModifierType_WeightedNormal = 54, - eModifierType_FunctionDeform = 55, + eModifierType_Weld = 55, eModifierType_FunctionPoints = 56, eModifierType_BParticles = 57, eModifierType_BParticlesOutput = 58, - NUM_MODIFIER_TYPES + eModifierType_FunctionDeform = 59, + NUM_MODIFIER_TYPES, } ModifierType; typedef enum ModifierMode { @@ -1814,6 +1815,16 @@ enum { MOD_WIREFRAME_CREASE = (1 << 5), }; +typedef struct WeldModifierData { + ModifierData modifier; + + /* the limit below which to merge vertices in adjacent duplicates */ + float merge_dist; + unsigned int max_interactions; + /** Name of vertex group to use to mask, MAX_VGROUP_NAME. */ + char defgrp_name[64]; +} WeldModifierData; + typedef struct DataTransferModifierData { ModifierData modifier; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index a9a20980677..93b93bbdbf7 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -376,6 +376,9 @@ typedef struct View3D { #define RV3D_VIEW_CAMERA 8 #define RV3D_VIEW_IS_AXIS(view) (((view) >= RV3D_VIEW_FRONT) && ((view) <= RV3D_VIEW_BOTTOM)) +#define RV3D_CLIPPING_ENABLED(v3d, rv3d) \ + (rv3d && v3d && (rv3d->rflag & RV3D_CLIPPING) && ELEM(v3d->shading.type, OB_WIRE, OB_SOLID) && \ + rv3d->clipbb) /** #View3D.flag2 (int) */ #define V3D_HIDE_OVERLAYS (1 << 2) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 46403d40e9d..00491f25b17 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -742,6 +742,7 @@ extern StructRNA RNA_Window; extern StructRNA RNA_WindowManager; extern StructRNA RNA_WipeSequence; extern StructRNA RNA_WireframeModifier; +extern StructRNA RNA_WeldModifier; extern StructRNA RNA_WoodTexture; extern StructRNA RNA_WorkSpace; extern StructRNA RNA_World; diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index a22b261368c..7c9b4254e4d 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -27,7 +27,7 @@ #include "BLI_utildefines.h" #include "BLI_string.h" -#define DEBUG_OVERRIDE_TIMEIT +// #define DEBUG_OVERRIDE_TIMEIT #ifdef DEBUG_OVERRIDE_TIMEIT # include "PIL_time_utildefines.h" @@ -598,7 +598,6 @@ bool RNA_struct_override_matches(Main *bmain, const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0; const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0; -//#define DEBUG_OVERRIDE_TIMEIT #ifdef DEBUG_OVERRIDE_TIMEIT static float _sum_time_global = 0.0f; static float _num_time_global = 0.0f; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index ca4ca07fe73..7c9ac6a2072 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -187,6 +187,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = { ICON_MOD_WIREFRAME, "Wireframe", "Convert faces into thickened edges"}, + {eModifierType_Weld, + "WELD", + ICON_AUTOMERGE_OFF, + "Weld", + "Finds groups of vertices closer then dist and merges them together"}, {eModifierType_FunctionPoints, "FUNCTION_POINTS", ICON_NONE, "Function Points", ""}, {0, "", 0, N_("Deform"), ""}, {eModifierType_Armature, @@ -704,6 +709,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr) return &RNA_LaplacianDeformModifier; case eModifierType_Wireframe: return &RNA_WireframeModifier; + case eModifierType_Weld: + return &RNA_WeldModifier; case eModifierType_DataTransfer: return &RNA_DataTransferModifier; case eModifierType_NormalEdit: @@ -815,6 +822,7 @@ RNA_MOD_VGROUP_NAME_SET(WeightVGMix, mask_defgrp_name); RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, defgrp_name); RNA_MOD_VGROUP_NAME_SET(WeightVGProximity, mask_defgrp_name); RNA_MOD_VGROUP_NAME_SET(WeightedNormal, defgrp_name); +RNA_MOD_VGROUP_NAME_SET(Weld, defgrp_name); RNA_MOD_VGROUP_NAME_SET(Wireframe, defgrp_name); static void rna_ExplodeModifier_vgroup_get(PointerRNA *ptr, char *value) @@ -5671,6 +5679,40 @@ static void rna_def_modifier_wireframe(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Modifier_update"); } +static void rna_def_modifier_weld(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "WeldModifier", "Modifier"); + RNA_def_struct_ui_text(srna, "Weld Modifier", "Weld modifier"); + RNA_def_struct_sdna(srna, "WeldModifierData"); + RNA_def_struct_ui_icon(srna, ICON_AUTOMERGE_OFF); + + prop = RNA_def_property(srna, "merge_threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "merge_dist"); + RNA_def_property_range(prop, 0, FLT_MAX); + RNA_def_property_ui_range(prop, 0, 1, 0.001, 6); + RNA_def_property_ui_text(prop, "Merge Distance", "Limit below which to merge vertices"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "max_interactions", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_sdna(prop, NULL, "max_interactions"); + RNA_def_property_ui_text( + prop, + "Duplicate Limit", + "For a better performance, limits the number of elements found per vertex. " + "(0 makes it infinite)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + + prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "defgrp_name"); + RNA_def_property_ui_text( + prop, "Vertex Group", "Vertex group name for selecting the affected areas"); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_WeldModifier_defgrp_name_set"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); +} + static void rna_def_modifier_datatransfer(BlenderRNA *brna) { StructRNA *srna; @@ -6488,6 +6530,7 @@ void RNA_def_modifier(BlenderRNA *brna) rna_def_modifier_meshcache(brna); rna_def_modifier_laplaciandeform(brna); rna_def_modifier_wireframe(brna); + rna_def_modifier_weld(brna); rna_def_modifier_datatransfer(brna); rna_def_modifier_normaledit(brna); rna_def_modifier_meshseqcache(brna); diff --git a/source/blender/makesrna/intern/rna_workspace_api.c b/source/blender/makesrna/intern/rna_workspace_api.c index f244a674e57..5cc55bfad8a 100644 --- a/source/blender/makesrna/intern/rna_workspace_api.c +++ b/source/blender/makesrna/intern/rna_workspace_api.c @@ -63,8 +63,8 @@ static void rna_WorkSpaceTool_setup(ID *id, STRNCPY(tref_rt.op, op_idname); tref_rt.index = index; - STRNCPY(tref_rt.idname_fallback, idname_fallback ? idname_fallback : NULL); - STRNCPY(tref_rt.keymap_fallback, keymap_fallback ? keymap_fallback : NULL); + STRNCPY(tref_rt.idname_fallback, idname_fallback); + STRNCPY(tref_rt.keymap_fallback, keymap_fallback); WM_toolsystem_ref_set_from_runtime(C, (WorkSpace *)id, tref, &tref_rt, idname); } diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index f6b98f43029..e0232431930 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -109,6 +109,7 @@ set(SRC intern/MOD_weightvgedit.c intern/MOD_weightvgmix.c intern/MOD_weightvgproximity.c + intern/MOD_weld.c intern/MOD_wireframe.c MOD_modifiertypes.h diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h index 10f8d83b5bc..0560ed86c75 100644 --- a/source/blender/modifiers/MOD_modifiertypes.h +++ b/source/blender/modifiers/MOD_modifiertypes.h @@ -75,6 +75,7 @@ extern ModifierTypeInfo modifierType_UVWarp; extern ModifierTypeInfo modifierType_MeshCache; extern ModifierTypeInfo modifierType_LaplacianDeform; extern ModifierTypeInfo modifierType_Wireframe; +extern ModifierTypeInfo modifierType_Weld; extern ModifierTypeInfo modifierType_DataTransfer; extern ModifierTypeInfo modifierType_NormalEdit; extern ModifierTypeInfo modifierType_CorrectiveSmooth; diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c index 723ad779864..45ec79d7801 100644 --- a/source/blender/modifiers/intern/MOD_util.c +++ b/source/blender/modifiers/intern/MOD_util.c @@ -301,6 +301,7 @@ void modifier_type_init(ModifierTypeInfo *types[]) INIT_TYPE(MeshCache); INIT_TYPE(LaplacianDeform); INIT_TYPE(Wireframe); + INIT_TYPE(Weld); INIT_TYPE(DataTransfer); INIT_TYPE(NormalEdit); INIT_TYPE(CorrectiveSmooth); diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.c new file mode 100644 index 00000000000..ca6998b9aa4 --- /dev/null +++ b/source/blender/modifiers/intern/MOD_weld.c @@ -0,0 +1,1910 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 by the Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup modifiers + * + * Weld modifier: Remove doubles. + */ + +/* TODOs: + * - Review weight and vertex color interpolation.; + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" + +#include "BLI_alloca.h" +#include "BLI_kdopbvh.h" +#include "BLI_math.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_deform.h" +#include "BKE_bvhutils.h" +#include "BKE_modifier.h" +#include "BKE_mesh.h" + +#include "DEG_depsgraph.h" + +//#define USE_WELD_DEBUG +//#define USE_WELD_NORMALS + +/* Indicates when the element was not computed. */ +#define OUT_OF_CONTEXT (uint)(-1) +/* Indicates if the edge or face will be collapsed. */ +#define ELEM_COLLAPSED (uint)(-2) +/* indicates whether an edge or vertex in groups_map will be merged. */ +#define ELEM_MERGED (uint)(-2) + +/* Used to indicate a range in an array specifying a group. */ +struct WeldGroup { + uint len; + uint ofs; +}; + +/* Edge groups that will be merged. Final vertices are also indicated. */ +struct WeldGroupEdge { + struct WeldGroup group; + uint v1; + uint v2; +}; + +typedef struct WeldVert { + /* Indexes relative to the original Mesh. */ + uint vert_dest; + uint vert_orig; +} WeldVert; + +typedef struct WeldEdge { + union { + uint flag; + struct { + /* Indexes relative to the original Mesh. */ + uint edge_dest; + uint edge_orig; + uint vert_a; + uint vert_b; + }; + }; +} WeldEdge; + +typedef struct WeldLoop { + union { + uint flag; + struct { + /* Indexes relative to the original Mesh. */ + uint vert; + uint edge; + uint loop_orig; + uint loop_skip_to; + }; + }; +} WeldLoop; + +typedef struct WeldPoly { + union { + uint flag; + struct { + /* Indexes relative to the original Mesh. */ + uint poly_dst; + uint poly_orig; + uint loop_start; + uint loop_end; + /* Final Polygon Size. */ + uint len; + /* Group of loops that will be affected. */ + struct WeldGroup loops; + }; + }; +} WeldPoly; + +typedef struct WeldMesh { + /* Group of vertices to be merged. */ + struct WeldGroup *vert_groups; + uint *vert_groups_buffer; + /* From the original index of the vertex, this indicates which group it is or is going to be + * merged. */ + uint *vert_groups_map; + + /* Group of edges to be merged. */ + struct WeldGroupEdge *edge_groups; + uint *edge_groups_buffer; + /* From the original index of the vertex, this indicates which group it is or is going to be + * merged. */ + uint *edge_groups_map; + + /* References all polygons and loops that will be affected. */ + WeldLoop *wloop; + WeldPoly *wpoly; + WeldPoly *wpoly_new; + uint wloop_len; + uint wpoly_len; + uint wpoly_new_len; + + /* From the actual index of the element in the mesh, it indicates what is the index of the Weld + * element above. */ + uint *loop_map; + uint *poly_map; + + uint vert_kill_tot; + uint edge_kill_tot; + uint loop_kill_tot; + uint poly_kill_tot; /* Including the new polygons. */ + + /* Size of the affected polygon with more sides. */ + uint max_poly_len; +} WeldMesh; + +typedef struct WeldLoopOfPolyIter { + uint loop_start; + uint loop_end; + const WeldLoop *wloop; + const MLoop *mloop; + const uint *loop_map; + /* Weld group. */ + uint *group; + + uint l_curr; + uint l_next; + + /* Return */ + uint group_len; + uint v; + uint e; + char type; +} WeldLoopOfPolyIter; + +/* -------------------------------------------------------------------- */ +/** \name Debug Utils + * \{ */ + +#ifdef USE_WELD_DEBUG +static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, + const WeldPoly *wp, + const WeldLoop *wloop, + const MLoop *mloop, + const uint *loop_map, + uint *group_buffer); + +static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter); + +static void weld_assert_vert_dest_map_setup(const BVHTreeOverlap *overlap, + const uint overlap_tot, + const uint *vert_dest_map) +{ + const BVHTreeOverlap *overlap_iter = &overlap[0]; + for (uint i = overlap_tot; i--; overlap_iter++) { + uint indexA = overlap_iter->indexA; + uint indexB = overlap_iter->indexB; + uint va_dst = vert_dest_map[indexA]; + uint vb_dst = vert_dest_map[indexB]; + + BLI_assert(va_dst == vb_dst); + } +} + +static void weld_assert_edge_kill_len(const WeldEdge *wedge, + const uint wedge_len, + const uint supposed_kill_tot) +{ + uint kills = 0; + const WeldEdge *we = &wedge[0]; + for (uint i = wedge_len; i--; we++) { + uint edge_dest = we->edge_dest; + /* Magically includes collapsed edges. */ + if (edge_dest != OUT_OF_CONTEXT) { + kills++; + } + } + BLI_assert(kills == supposed_kill_tot); +} + +static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly, + const WeldPoly *wpoly_new, + const uint wpoly_new_len, + const WeldLoop *wloop, + const MLoop *mloop, + const uint *loop_map, + const uint *poly_map, + const MPoly *mpoly, + const uint mpoly_len, + const uint mloop_len, + const uint supposed_poly_kill_tot, + const uint supposed_loop_kill_tot) +{ + uint poly_kills = 0; + uint loop_kills = mloop_len; + const MPoly *mp = &mpoly[0]; + for (uint i = 0; i < mpoly_len; i++, mp++) { + uint poly_ctx = poly_map[i]; + if (poly_ctx != OUT_OF_CONTEXT) { + const WeldPoly *wp = &wpoly[poly_ctx]; + WeldLoopOfPolyIter iter; + if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + poly_kills++; + continue; + } + else { + if (wp->poly_dst != OUT_OF_CONTEXT) { + poly_kills++; + continue; + } + uint remain = wp->len; + uint l = wp->loop_start; + while (remain) { + uint l_next = l + 1; + uint loop_ctx = loop_map[l]; + if (loop_ctx != OUT_OF_CONTEXT) { + const WeldLoop *wl = &wloop[loop_ctx]; + if (wl->loop_skip_to != OUT_OF_CONTEXT) { + l_next = wl->loop_skip_to; + } + if (wl->flag != ELEM_COLLAPSED) { + loop_kills--; + remain--; + } + } + else { + loop_kills--; + remain--; + } + l = l_next; + } + } + } + else { + loop_kills -= mp->totloop; + } + } + + const WeldPoly *wp = &wpoly_new[0]; + for (uint i = wpoly_new_len; i--; wp++) { + if (wp->poly_dst != OUT_OF_CONTEXT) { + poly_kills++; + continue; + } + uint remain = wp->len; + uint l = wp->loop_start; + while (remain) { + uint l_next = l + 1; + uint loop_ctx = loop_map[l]; + if (loop_ctx != OUT_OF_CONTEXT) { + const WeldLoop *wl = &wloop[loop_ctx]; + if (wl->loop_skip_to != OUT_OF_CONTEXT) { + l_next = wl->loop_skip_to; + } + if (wl->flag != ELEM_COLLAPSED) { + loop_kills--; + remain--; + } + } + else { + loop_kills--; + remain--; + } + l = l_next; + } + } + + BLI_assert(poly_kills == supposed_poly_kill_tot); + BLI_assert(loop_kills == supposed_loop_kill_tot); +} + +static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp, + const WeldLoop *wloop, + const MLoop *mloop, + const uint *loop_map) +{ + const uint len = wp->len; + uint *verts = BLI_array_alloca(verts, len); + WeldLoopOfPolyIter iter; + if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + return; + } + else { + uint i = 0; + while (weld_iter_loop_of_poly_next(&iter)) { + verts[i++] = iter.v; + } + } + for (uint i = 0; i < len; i++) { + uint va = verts[i]; + for (uint j = i + 1; j < len; j++) { + uint vb = verts[j]; + BLI_assert(va != vb); + } + } +} + +static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop) +{ + if (wp->flag == ELEM_COLLAPSED) { + return; + } + + uint len = wp->len; + const WeldLoop *wl = &wloop[wp->loops.ofs]; + BLI_assert(wp->loop_start <= wl->loop_orig); + + uint end_wloop = wp->loops.ofs + wp->loops.len; + const WeldLoop *wl_end = &wloop[end_wloop - 1]; + + uint min_len = 0; + for (; wl <= wl_end; wl++) { + BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */ + if (wl->flag != ELEM_COLLAPSED) { + min_len++; + } + } + BLI_assert(len >= min_len); + + uint max_len = wp->loop_end - wp->loop_start + 1; + BLI_assert(len <= max_len); +} +#endif +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Vert API + * \{ */ + +static void weld_vert_ctx_alloc_and_setup(const uint vert_tot, + const BVHTreeOverlap *overlap, + const uint overlap_tot, + uint *r_vert_dest_map, + WeldVert **r_wvert, + uint *r_wvert_tot, + uint *r_vert_kill_tot) +{ + uint *v_dest_iter = &r_vert_dest_map[0]; + for (uint i = vert_tot; i--; v_dest_iter++) { + *v_dest_iter = OUT_OF_CONTEXT; + } + + uint vert_kill_tot = 0; + const BVHTreeOverlap *overlap_iter = &overlap[0]; + for (uint i = 0; i < overlap_tot; i++, overlap_iter++) { + uint indexA = overlap_iter->indexA; + uint indexB = overlap_iter->indexB; + + BLI_assert(indexA < indexB); + + uint va_dst = r_vert_dest_map[indexA]; + uint vb_dst = r_vert_dest_map[indexB]; + if (va_dst == OUT_OF_CONTEXT) { + if (vb_dst == OUT_OF_CONTEXT) { + vb_dst = indexA; + r_vert_dest_map[indexB] = vb_dst; + } + r_vert_dest_map[indexA] = vb_dst; + vert_kill_tot++; + } + else if (vb_dst == OUT_OF_CONTEXT) { + r_vert_dest_map[indexB] = va_dst; + vert_kill_tot++; + } + else if (va_dst != vb_dst) { + uint v_new, v_old; + if (va_dst < vb_dst) { + v_new = va_dst; + v_old = vb_dst; + } + else { + v_new = vb_dst; + v_old = va_dst; + } + BLI_assert(r_vert_dest_map[v_old] == v_old); + BLI_assert(r_vert_dest_map[v_new] == v_new); + vert_kill_tot++; + + const BVHTreeOverlap *overlap_iter_b = &overlap[0]; + for (uint j = i + 1; j--; overlap_iter_b++) { + indexA = overlap_iter_b->indexA; + indexB = overlap_iter_b->indexB; + va_dst = r_vert_dest_map[indexA]; + vb_dst = r_vert_dest_map[indexB]; + if (ELEM(v_old, vb_dst, va_dst)) { + r_vert_dest_map[indexA] = v_new; + r_vert_dest_map[indexB] = v_new; + } + } + BLI_assert(r_vert_dest_map[v_old] == v_new); + } + } + + /* Vert Context. */ + uint wvert_tot = 0; + + WeldVert *wvert, *wv; + wvert = MEM_mallocN(sizeof(*wvert) * vert_tot, __func__); + wv = &wvert[0]; + + v_dest_iter = &r_vert_dest_map[0]; + for (uint i = 0; i < vert_tot; i++, v_dest_iter++) { + if (*v_dest_iter != OUT_OF_CONTEXT) { + wv->vert_dest = *v_dest_iter; + wv->vert_orig = i; + wv++; + wvert_tot++; + } + } + +#ifdef USE_WELD_DEBUG + weld_assert_vert_dest_map_setup(overlap, overlap_tot, r_vert_dest_map); +#endif + + *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_tot); + *r_wvert_tot = wvert_tot; + *r_vert_kill_tot = vert_kill_tot; +} + +static void weld_vert_groups_setup(const uint vert_tot, + const uint wvert_tot, + const WeldVert *wvert, + const uint *vert_dest_map, + uint *r_vert_groups_map, + uint **r_vert_groups_buffer, + struct WeldGroup **r_vert_groups) +{ + /* Get weld vert groups. */ + + uint wgroups_len = 0; + const uint *vert_dest_iter = &vert_dest_map[0]; + uint *group_map_iter = &r_vert_groups_map[0]; + for (uint i = 0; i < vert_tot; i++, group_map_iter++, vert_dest_iter++) { + uint vert_dest = *vert_dest_iter; + if (vert_dest != OUT_OF_CONTEXT) { + if (vert_dest != i) { + *group_map_iter = ELEM_MERGED; + } + else { + *group_map_iter = wgroups_len; + wgroups_len++; + } + } + else { + *group_map_iter = OUT_OF_CONTEXT; + } + } + + struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__); + + const WeldVert *wv = &wvert[0]; + for (uint i = wvert_tot; i--; wv++) { + uint group_index = r_vert_groups_map[wv->vert_dest]; + wgroups[group_index].len++; + } + + uint ofs = 0; + struct WeldGroup *wg_iter = &wgroups[0]; + for (uint i = wgroups_len; i--; wg_iter++) { + wg_iter->ofs = ofs; + ofs += wg_iter->len; + } + + BLI_assert(ofs == wvert_tot); + + uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__); + wv = &wvert[0]; + for (uint i = wvert_tot; i--; wv++) { + uint group_index = r_vert_groups_map[wv->vert_dest]; + groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig; + } + + wg_iter = &wgroups[0]; + for (uint i = wgroups_len; i--; wg_iter++) { + wg_iter->ofs -= wg_iter->len; + } + + *r_vert_groups = wgroups; + *r_vert_groups_buffer = groups_buffer; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Edge API + * \{ */ + +static void weld_edge_ctx_setup(const uint vert_tot, + const uint wedge_len, + struct WeldGroup *r_vlinks, + uint *r_edge_dest_map, + WeldEdge *r_wedge, + uint *r_edge_kiil_tot) +{ + WeldEdge *we; + + /* Setup Edge Overlap. */ + uint edge_kill_tot = 0; + + struct WeldGroup *vl_iter, *v_links; + v_links = r_vlinks; + vl_iter = &v_links[0]; + + we = &r_wedge[0]; + for (uint i = wedge_len; i--; we++) { + uint dst_vert_a = we->vert_a; + uint dst_vert_b = we->vert_b; + + if (dst_vert_a == dst_vert_b) { + BLI_assert(we->edge_dest == OUT_OF_CONTEXT); + r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED; + we->flag = ELEM_COLLAPSED; + edge_kill_tot++; + continue; + } + + v_links[dst_vert_a].len++; + v_links[dst_vert_b].len++; + } + + uint link_tot = 0; + vl_iter = &v_links[0]; + for (uint i = vert_tot; i--; vl_iter++) { + vl_iter->ofs = link_tot; + link_tot += vl_iter->len; + } + + if (link_tot) { + uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_tot, __func__); + + we = &r_wedge[0]; + for (uint i = 0; i < wedge_len; i++, we++) { + if (we->flag == ELEM_COLLAPSED) { + continue; + } + + uint dst_vert_a = we->vert_a; + uint dst_vert_b = we->vert_b; + + link_edge_buffer[v_links[dst_vert_a].ofs++] = i; + link_edge_buffer[v_links[dst_vert_b].ofs++] = i; + } + + vl_iter = &v_links[0]; + for (uint i = vert_tot; i--; vl_iter++) { + /* Fix offset */ + vl_iter->ofs -= vl_iter->len; + } + + we = &r_wedge[0]; + for (uint i = 0; i < wedge_len; i++, we++) { + if (we->edge_dest != OUT_OF_CONTEXT) { + /* No need to retest edges. + * (Already includes collapsed edges). */ + continue; + } + + uint dst_vert_a = we->vert_a; + uint dst_vert_b = we->vert_b; + + struct WeldGroup *link_a = &v_links[dst_vert_a]; + struct WeldGroup *link_b = &v_links[dst_vert_b]; + + uint edges_len_a = link_a->len; + uint edges_len_b = link_b->len; + + if (edges_len_a <= 1 || edges_len_b <= 1) { + continue; + } + + uint *edges_ctx_a = &link_edge_buffer[link_a->ofs]; + uint *edges_ctx_b = &link_edge_buffer[link_b->ofs]; + uint edge_orig = we->edge_orig; + + for (; edges_len_a--; edges_ctx_a++) { + uint e_ctx_a = *edges_ctx_a; + if (e_ctx_a == i) { + continue; + } + while (edges_len_b && *edges_ctx_b < e_ctx_a) { + edges_ctx_b++; + edges_len_b--; + } + if (edges_len_b == 0) { + break; + } + uint e_ctx_b = *edges_ctx_b; + if (e_ctx_a == e_ctx_b) { + WeldEdge *we_b = &r_wedge[e_ctx_b]; + BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b)); + BLI_assert(ELEM(we_b->vert_b, dst_vert_a, dst_vert_b)); + BLI_assert(we_b->edge_dest == OUT_OF_CONTEXT); + BLI_assert(we_b->edge_orig != edge_orig); + r_edge_dest_map[we_b->edge_orig] = edge_orig; + we_b->edge_dest = edge_orig; + edge_kill_tot++; + } + } + } + +#ifdef USE_WELD_DEBUG + weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_tot); +#endif + + MEM_freeN(link_edge_buffer); + } + + *r_edge_kiil_tot = edge_kill_tot; +} + +static void weld_edge_ctx_alloc(const MEdge *medge, + const uint edge_tot, + const uint *vert_dest_map, + uint *r_edge_dest_map, + uint **r_edge_ctx_map, + WeldEdge **r_wedge, + uint *r_wedge_len) +{ + /* Edge Context. */ + uint *edge_map = MEM_mallocN(sizeof(*edge_map) * edge_tot, __func__); + uint wedge_tot = 0; + + WeldEdge *wedge, *we; + wedge = MEM_mallocN(sizeof(*wedge) * edge_tot, __func__); + we = &wedge[0]; + + const MEdge *me = &medge[0]; + uint *e_dest_iter = &r_edge_dest_map[0]; + uint *iter = &edge_map[0]; + for (uint i = 0; i < edge_tot; i++, me++, iter++, e_dest_iter++) { + uint v1 = me->v1; + uint v2 = me->v2; + uint v_dest_1 = vert_dest_map[v1]; + uint v_dest_2 = vert_dest_map[v2]; + if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) { + we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1; + we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2; + we->edge_dest = OUT_OF_CONTEXT; + we->edge_orig = i; + we++; + *e_dest_iter = i; + *iter = wedge_tot++; + } + else { + *e_dest_iter = OUT_OF_CONTEXT; + *iter = OUT_OF_CONTEXT; + } + } + + *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_tot); + *r_wedge_len = wedge_tot; + *r_edge_ctx_map = edge_map; +} + +static void weld_edge_groups_setup(const uint edge_tot, + const uint edge_kill_tot, + const uint wedge_len, + WeldEdge *wedge, + const uint *wedge_map, + uint *r_edge_groups_map, + uint **r_edge_groups_buffer, + struct WeldGroupEdge **r_edge_groups) +{ + + /* Get weld edge groups. */ + + struct WeldGroupEdge *wegroups, *wegrp_iter; + + uint wgroups_len = wedge_len - edge_kill_tot; + wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__); + wegrp_iter = &wegroups[0]; + + wgroups_len = 0; + const uint *edge_ctx_iter = &wedge_map[0]; + uint *group_map_iter = &r_edge_groups_map[0]; + for (uint i = edge_tot; i--; edge_ctx_iter++, group_map_iter++) { + uint edge_ctx = *edge_ctx_iter; + if (edge_ctx != OUT_OF_CONTEXT) { + WeldEdge *we = &wedge[edge_ctx]; + uint edge_dest = we->edge_dest; + if (edge_dest != OUT_OF_CONTEXT) { + BLI_assert(edge_dest != we->edge_orig); + *group_map_iter = ELEM_MERGED; + } + else { + we->edge_dest = we->edge_orig; + wegrp_iter->v1 = we->vert_a; + wegrp_iter->v2 = we->vert_b; + *group_map_iter = wgroups_len; + wgroups_len++; + wegrp_iter++; + } + } + else { + *group_map_iter = OUT_OF_CONTEXT; + } + } + + BLI_assert(wgroups_len == wedge_len - edge_kill_tot); + + WeldEdge *we = &wedge[0]; + for (uint i = wedge_len; i--; we++) { + if (we->flag == ELEM_COLLAPSED) { + continue; + } + uint group_index = r_edge_groups_map[we->edge_dest]; + wegroups[group_index].group.len++; + } + + uint ofs = 0; + wegrp_iter = &wegroups[0]; + for (uint i = wgroups_len; i--; wegrp_iter++) { + wegrp_iter->group.ofs = ofs; + ofs += wegrp_iter->group.len; + } + + uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__); + we = &wedge[0]; + for (uint i = wedge_len; i--; we++) { + if (we->flag == ELEM_COLLAPSED) { + continue; + } + uint group_index = r_edge_groups_map[we->edge_dest]; + groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig; + } + + wegrp_iter = &wegroups[0]; + for (uint i = wgroups_len; i--; wegrp_iter++) { + wegrp_iter->group.ofs -= wegrp_iter->group.len; + } + + *r_edge_groups_buffer = groups_buffer; + *r_edge_groups = wegroups; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Poly and Loop API + * \{ */ + +static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, + const WeldPoly *wp, + const WeldLoop *wloop, + const MLoop *mloop, + const uint *loop_map, + uint *group_buffer) +{ + if (wp->flag == ELEM_COLLAPSED) { + return false; + } + + iter->loop_start = wp->loop_start; + iter->loop_end = wp->loop_end; + iter->wloop = wloop; + iter->mloop = mloop; + iter->loop_map = loop_map; + iter->group = group_buffer; + + iter->l_next = iter->loop_start; +#ifdef USE_WELD_DEBUG + iter->v = OUT_OF_CONTEXT; +#endif + return true; +} + +static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) +{ + uint loop_end = iter->loop_end; + const WeldLoop *wloop = iter->wloop; + const uint *loop_map = iter->loop_map; + iter->group_len = 0; + uint l = iter->l_curr = iter->l_next; + while (l <= loop_end) { + uint l_next = l + 1; + const uint loop_ctx = loop_map[l]; + if (loop_ctx != OUT_OF_CONTEXT) { + const WeldLoop *wl = &wloop[loop_ctx]; + if (wl->loop_skip_to != OUT_OF_CONTEXT) { + l_next = wl->loop_skip_to; + } + if (wl->flag == ELEM_COLLAPSED) { + if (iter->group) { + if (l == iter->loop_start) { + uint l_prev = loop_end; + const uint loop_ctx_end = loop_map[l_prev]; + if (loop_ctx_end != OUT_OF_CONTEXT) { + const WeldLoop *wl_prev = &wloop[loop_ctx_end]; + while (wl_prev->flag == ELEM_COLLAPSED) { + iter->group[iter->group_len++] = l_prev--; + wl_prev--; + if (wl_prev->loop_orig != l_prev) { + break; + } + } + } + } + iter->group[iter->group_len++] = l; + } + l = l_next; + continue; + } +#ifdef USE_WELD_DEBUG + BLI_assert(iter->v != wl->vert); +#endif + iter->v = wl->vert; + iter->e = wl->edge; + iter->type = 1; + } + else { + const MLoop *ml = &iter->mloop[l]; +#ifdef USE_WELD_DEBUG + BLI_assert(iter->v != ml->v); +#endif + iter->v = ml->v; + iter->e = ml->e; + iter->type = 0; + } + if (iter->group) { + iter->group[iter->group_len++] = l; + } + iter->l_next = l_next; + return true; + } + + return false; +} + +static void weld_poly_loop_ctx_alloc(const MPoly *mpoly, + const uint mpoly_len, + const MLoop *mloop, + const uint mloop_len, + const uint *vert_dest_map, + const uint *edge_dest_map, + WeldMesh *r_weld_mesh) +{ + /* Loop/Poly Context. */ + uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__); + uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__); + uint wloop_len = 0; + uint wpoly_len = 0; + uint max_ctx_poly_len = 4; + + WeldLoop *wloop, *wl; + wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__); + wl = &wloop[0]; + + WeldPoly *wpoly, *wp; + wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__); + wp = &wpoly[0]; + + uint maybe_new_poly = 0; + + const MPoly *mp = &mpoly[0]; + uint *iter = &poly_map[0]; + uint *loop_map_iter = &loop_map[0]; + for (uint i = 0; i < mpoly_len; i++, mp++, iter++) { + const uint loopstart = mp->loopstart; + const uint totloop = mp->totloop; + + uint vert_ctx_len = 0; + + uint l = loopstart; + uint prev_wloop_len = wloop_len; + const MLoop *ml = &mloop[l]; + for (uint j = totloop; j--; l++, ml++, loop_map_iter++) { + uint v = ml->v; + uint e = ml->e; + uint v_dest = vert_dest_map[v]; + uint e_dest = edge_dest_map[e]; + bool is_vert_ctx = v_dest != OUT_OF_CONTEXT; + bool is_edge_ctx = e_dest != OUT_OF_CONTEXT; + if (is_vert_ctx) { + vert_ctx_len++; + } + if (is_vert_ctx || is_edge_ctx) { + wl->vert = is_vert_ctx ? v_dest : v; + wl->edge = is_edge_ctx ? e_dest : e; + wl->loop_orig = l; + wl->loop_skip_to = OUT_OF_CONTEXT; + wl++; + + *loop_map_iter = wloop_len++; + } + else { + *loop_map_iter = OUT_OF_CONTEXT; + } + } + if (wloop_len != prev_wloop_len) { + uint loops_len = wloop_len - prev_wloop_len; + + wp->poly_dst = OUT_OF_CONTEXT; + wp->poly_orig = i; + wp->loops.len = loops_len; + wp->loops.ofs = prev_wloop_len; + wp->loop_start = loopstart; + wp->loop_end = loopstart + totloop - 1; + wp->len = totloop; + wp++; + + *iter = wpoly_len++; + if (totloop > 5 && vert_ctx_len > 1) { + uint max_new = (totloop / 3) - 1; + vert_ctx_len /= 2; + maybe_new_poly += MIN2(max_new, vert_ctx_len); + CLAMP_MIN(max_ctx_poly_len, totloop); + } + } + else { + *iter = OUT_OF_CONTEXT; + } + } + + if (mpoly_len < (wpoly_len + maybe_new_poly)) { + WeldPoly *wpoly_tmp = wpoly; + wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__); + memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len); + MEM_freeN(wpoly_tmp); + } + + WeldPoly *poly_new = &wpoly[wpoly_len]; + + r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len); + r_weld_mesh->wpoly = wpoly; + r_weld_mesh->wpoly_new = poly_new; + r_weld_mesh->wloop_len = wloop_len; + r_weld_mesh->wpoly_len = wpoly_len; + r_weld_mesh->wpoly_new_len = 0; + r_weld_mesh->loop_map = loop_map; + r_weld_mesh->poly_map = poly_map; + r_weld_mesh->max_poly_len = max_ctx_poly_len; +} + +static void weld_poly_split_recursive(const uint *vert_dest_map, +#ifdef USE_WELD_DEBUG + const MLoop *mloop, +#endif + uint ctx_verts_len, + WeldPoly *r_wp, + WeldMesh *r_weld_mesh, + uint *r_poly_kill, + uint *r_loop_kill) +{ + uint poly_len = r_wp->len; + if (poly_len > 3 && ctx_verts_len > 1) { + const uint ctx_loops_len = r_wp->loops.len; + const uint ctx_loops_ofs = r_wp->loops.ofs; + WeldLoop *wloop = r_weld_mesh->wloop; + WeldPoly *wpoly_new = r_weld_mesh->wpoly_new; + + uint loop_kill = 0; + + WeldLoop *poly_loops = &wloop[ctx_loops_ofs]; + WeldLoop *wla = &poly_loops[0]; + WeldLoop *wla_prev = &poly_loops[ctx_loops_len - 1]; + while (wla_prev->flag == ELEM_COLLAPSED) { + wla_prev--; + } + const uint la_len = ctx_loops_len - 1; + for (uint la = 0; la < la_len; la++, wla++) { + wa_continue: + if (wla->flag == ELEM_COLLAPSED) { + continue; + } + uint vert_a = wla->vert; + /* Only test vertices that will be merged. */ + if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) { + uint lb = la + 1; + WeldLoop *wlb = wla + 1; + WeldLoop *wlb_prev = wla; + uint killed_ab = 0; + ctx_verts_len = 1; + for (; lb < ctx_loops_len; lb++, wlb++) { + BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT); + if (wlb->flag == ELEM_COLLAPSED) { + killed_ab++; + continue; + } + uint vert_b = wlb->vert; + if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) { + ctx_verts_len++; + } + if (vert_a == vert_b) { + const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab; + const uint dist_b = poly_len - dist_a; + + BLI_assert(dist_a != 0 && dist_b != 0); + if (dist_a == 1 || dist_b == 1) { + BLI_assert(dist_a != dist_b); + BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED)); + } + else { + WeldLoop *wl_tmp = NULL; + if (dist_a == 2) { + wl_tmp = wlb_prev; + BLI_assert(wla->flag != ELEM_COLLAPSED); + BLI_assert(wl_tmp->flag != ELEM_COLLAPSED); + wla->flag = ELEM_COLLAPSED; + wl_tmp->flag = ELEM_COLLAPSED; + loop_kill += 2; + poly_len -= 2; + } + if (dist_b == 2) { + if (wl_tmp != NULL) { + r_wp->flag = ELEM_COLLAPSED; + *r_poly_kill += 1; + } + else { + wl_tmp = wla_prev; + BLI_assert(wlb->flag != ELEM_COLLAPSED); + BLI_assert(wl_tmp->flag != ELEM_COLLAPSED); + wlb->flag = ELEM_COLLAPSED; + wl_tmp->flag = ELEM_COLLAPSED; + } + loop_kill += 2; + poly_len -= 2; + } + if (wl_tmp == NULL) { + const uint new_loops_len = lb - la; + const uint new_loops_ofs = ctx_loops_ofs + la; + + WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++]; + new_wp->poly_dst = OUT_OF_CONTEXT; + new_wp->poly_orig = r_wp->poly_orig; + new_wp->loops.len = new_loops_len; + new_wp->loops.ofs = new_loops_ofs; + new_wp->loop_start = wla->loop_orig; + new_wp->loop_end = wlb_prev->loop_orig; + new_wp->len = dist_a; + weld_poly_split_recursive(vert_dest_map, +#ifdef USE_WELD_DEBUG + mloop, +#endif + ctx_verts_len, + new_wp, + r_weld_mesh, + r_poly_kill, + r_loop_kill); + BLI_assert(dist_b == poly_len - dist_a); + poly_len = dist_b; + if (wla_prev->loop_orig > wla->loop_orig) { + /* New start. */ + r_wp->loop_start = wlb->loop_orig; + } + else { + /* The `loop_start` doesn't change but some loops must be skipped. */ + wla_prev->loop_skip_to = wlb->loop_orig; + } + wla = wlb; + la = lb; + goto wa_continue; + } + break; + } + } + if (wlb->flag != ELEM_COLLAPSED) { + wlb_prev = wlb; + } + } + } + if (wla->flag != ELEM_COLLAPSED) { + wla_prev = wla; + } + } + r_wp->len = poly_len; + *r_loop_kill += loop_kill; + +#ifdef USE_WELD_DEBUG + weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map); +#endif + } +} + +static void weld_poly_loop_ctx_setup(const MLoop *mloop, +#ifdef USE_WELD_DEBUG + const MPoly *mpoly, + const uint mpoly_len, + const uint mloop_len, +#endif + const uint vert_tot, + const uint *vert_dest_map, + const uint remain_edge_ctx_len, + struct WeldGroup *r_vlinks, + WeldMesh *r_weld_mesh) +{ + uint poly_kill_tot, loop_kill_tot, wpoly_len, wpoly_new_tot; + + WeldPoly *wpoly_new, *wpoly, *wp; + WeldLoop *wloop, *wl; + + wpoly = r_weld_mesh->wpoly; + wloop = r_weld_mesh->wloop; + wpoly_new = r_weld_mesh->wpoly_new; + wpoly_len = r_weld_mesh->wpoly_len; + wpoly_new_tot = 0; + poly_kill_tot = 0; + loop_kill_tot = 0; + + const uint *loop_map = r_weld_mesh->loop_map; + + if (remain_edge_ctx_len) { + + /* Setup Poly/Loop. */ + + wp = &wpoly[0]; + for (uint i = wpoly_len; i--; wp++) { + const uint ctx_loops_len = wp->loops.len; + const uint ctx_loops_ofs = wp->loops.ofs; + + uint poly_len = wp->len; + uint ctx_verts_len = 0; + wl = &wloop[ctx_loops_ofs]; + for (uint l = ctx_loops_len; l--; wl++) { + const uint edge_dest = wl->edge; + if (edge_dest == ELEM_COLLAPSED) { + wl->flag = ELEM_COLLAPSED; + if (poly_len == 3) { + wp->flag = ELEM_COLLAPSED; + poly_kill_tot++; + loop_kill_tot += 3; + poly_len = 0; + break; + } + loop_kill_tot++; + poly_len--; + } + else { + const uint vert_dst = wl->vert; + if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) { + ctx_verts_len++; + } + } + } + + if (poly_len) { + wp->len = poly_len; +#ifdef USE_WELD_DEBUG + weld_assert_poly_len(wp, wloop); +#endif + + weld_poly_split_recursive(vert_dest_map, +#ifdef USE_WELD_DEBUG + mloop, +#endif + ctx_verts_len, + wp, + r_weld_mesh, + &poly_kill_tot, + &loop_kill_tot); + + wpoly_new_tot = r_weld_mesh->wpoly_new_len; + } + } + +#ifdef USE_WELD_DEBUG + weld_assert_poly_and_loop_kill_len(wpoly, + wpoly_new, + wpoly_new_tot, + wloop, + mloop, + loop_map, + r_weld_mesh->poly_map, + mpoly, + mpoly_len, + mloop_len, + poly_kill_tot, + loop_kill_tot); +#endif + + /* Setup Polygon Overlap. */ + + uint wpoly_and_new_tot = wpoly_len + wpoly_new_tot; + + struct WeldGroup *vl_iter, *v_links = r_vlinks; + memset(v_links, 0, sizeof(*v_links) * vert_tot); + + wp = &wpoly[0]; + for (uint i = wpoly_and_new_tot; i--; wp++) { + WeldLoopOfPolyIter iter; + if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + while (weld_iter_loop_of_poly_next(&iter)) { + v_links[iter.v].len++; + } + } + } + + uint link_tot = 0; + vl_iter = &v_links[0]; + for (uint i = vert_tot; i--; vl_iter++) { + vl_iter->ofs = link_tot; + link_tot += vl_iter->len; + } + + if (link_tot) { + uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_tot, __func__); + + wp = &wpoly[0]; + for (uint i = 0; i < wpoly_and_new_tot; i++, wp++) { + WeldLoopOfPolyIter iter; + if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + while (weld_iter_loop_of_poly_next(&iter)) { + link_poly_buffer[v_links[iter.v].ofs++] = i; + } + } + } + + vl_iter = &v_links[0]; + for (uint i = vert_tot; i--; vl_iter++) { + /* Fix offset */ + vl_iter->ofs -= vl_iter->len; + } + + uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b; + polys_len_b = p_ctx_b = 0; /* silence warnings */ + + wp = &wpoly[0]; + for (uint i = 0; i < wpoly_and_new_tot; i++, wp++) { + if (wp->poly_dst != OUT_OF_CONTEXT) { + /* No need to retest poly. + * (Already includes collapsed polygons). */ + continue; + } + + WeldLoopOfPolyIter iter; + weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL); + weld_iter_loop_of_poly_next(&iter); + struct WeldGroup *link_a = &v_links[iter.v]; + polys_len_a = link_a->len; + if (polys_len_a == 1) { + BLI_assert(link_poly_buffer[link_a->ofs] == i); + continue; + } + uint wp_len = wp->len; + polys_ctx_a = &link_poly_buffer[link_a->ofs]; + for (; polys_len_a--; polys_ctx_a++) { + p_ctx_a = *polys_ctx_a; + if (p_ctx_a == i) { + continue; + } + + WeldPoly *wp_tmp = &wpoly[p_ctx_a]; + if (wp_tmp->len != wp_len) { + continue; + } + + WeldLoopOfPolyIter iter_b = iter; + while (weld_iter_loop_of_poly_next(&iter_b)) { + struct WeldGroup *link_b = &v_links[iter_b.v]; + polys_len_b = link_b->len; + if (polys_len_b == 1) { + BLI_assert(link_poly_buffer[link_b->ofs] == i); + polys_len_b = 0; + break; + } + + polys_ctx_b = &link_poly_buffer[link_b->ofs]; + for (; polys_len_b; polys_len_b--, polys_ctx_b++) { + p_ctx_b = *polys_ctx_b; + if (p_ctx_b < p_ctx_a) { + continue; + } + if (p_ctx_b >= p_ctx_a) { + if (p_ctx_b > p_ctx_a) { + polys_len_b = 0; + } + break; + } + } + if (polys_len_b == 0) { + break; + } + } + if (polys_len_b == 0) { + continue; + } + BLI_assert(p_ctx_a > i); + BLI_assert(p_ctx_a == p_ctx_b); + BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT); + BLI_assert(wp_tmp != wp); + wp_tmp->poly_dst = wp->poly_orig; + loop_kill_tot += wp_tmp->len; + poly_kill_tot++; + } + } + MEM_freeN(link_poly_buffer); + } + } + else { + poly_kill_tot = r_weld_mesh->wpoly_len; + loop_kill_tot = r_weld_mesh->wloop_len; + + wp = &wpoly[0]; + for (uint i = wpoly_len; i--; wp++) { + wp->flag = ELEM_COLLAPSED; + } + } + +#ifdef USE_WELD_DEBUG + weld_assert_poly_and_loop_kill_len(wpoly, + wpoly_new, + wpoly_new_tot, + wloop, + mloop, + loop_map, + r_weld_mesh->poly_map, + mpoly, + mpoly_len, + mloop_len, + poly_kill_tot, + loop_kill_tot); +#endif + + r_weld_mesh->wpoly_new = wpoly_new; + r_weld_mesh->poly_kill_tot = poly_kill_tot; + r_weld_mesh->loop_kill_tot = loop_kill_tot; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Mesh API + * \{ */ + +static void weld_mesh_context_create(const Mesh *mesh, + BVHTreeOverlap *overlap, + const uint overlap_tot, + WeldMesh *r_weld_mesh) +{ + const MEdge *medge = mesh->medge; + const MLoop *mloop = mesh->mloop; + const MPoly *mpoly = mesh->mpoly; + const uint vert_tot = mesh->totvert; + const uint edge_tot = mesh->totedge; + const uint mloop_len = mesh->totloop; + const uint mpoly_len = mesh->totpoly; + + uint *vert_dest_map = MEM_mallocN(sizeof(*vert_dest_map) * vert_tot, __func__); + uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * edge_tot, __func__); + struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * vert_tot, __func__); + + WeldVert *wvert; + uint wvert_len; + weld_vert_ctx_alloc_and_setup(vert_tot, + overlap, + overlap_tot, + vert_dest_map, + &wvert, + &wvert_len, + &r_weld_mesh->vert_kill_tot); + + uint *edge_ctx_map; + WeldEdge *wedge; + uint wedge_len; + weld_edge_ctx_alloc( + medge, edge_tot, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len); + + weld_edge_ctx_setup( + vert_tot, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_tot); + + weld_poly_loop_ctx_alloc( + mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh); + + weld_poly_loop_ctx_setup(mloop, +#ifdef USE_WELD_DEBUG + mpoly, + mpoly_len, + mloop_len, +#endif + vert_tot, + vert_dest_map, + wedge_len - r_weld_mesh->edge_kill_tot, + v_links, + r_weld_mesh); + + weld_vert_groups_setup(vert_tot, + wvert_len, + wvert, + vert_dest_map, + vert_dest_map, + &r_weld_mesh->vert_groups_buffer, + &r_weld_mesh->vert_groups); + + weld_edge_groups_setup(edge_tot, + r_weld_mesh->edge_kill_tot, + wedge_len, + wedge, + edge_ctx_map, + edge_dest_map, + &r_weld_mesh->edge_groups_buffer, + &r_weld_mesh->edge_groups); + + r_weld_mesh->vert_groups_map = vert_dest_map; + r_weld_mesh->edge_groups_map = edge_dest_map; + MEM_freeN(v_links); + MEM_freeN(wvert); + MEM_freeN(edge_ctx_map); + MEM_freeN(wedge); +} + +static void weld_mesh_context_free(WeldMesh *weld_mesh) +{ + MEM_freeN(weld_mesh->vert_groups); + MEM_freeN(weld_mesh->vert_groups_buffer); + MEM_freeN(weld_mesh->vert_groups_map); + + MEM_freeN(weld_mesh->edge_groups); + MEM_freeN(weld_mesh->edge_groups_buffer); + MEM_freeN(weld_mesh->edge_groups_map); + + MEM_freeN(weld_mesh->wloop); + MEM_freeN(weld_mesh->wpoly); + MEM_freeN(weld_mesh->loop_map); + MEM_freeN(weld_mesh->poly_map); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld CustomData + * \{ */ + +static void customdata_weld( + const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index) +{ + if (count == 1) { + CustomData_copy_data(source, dest, src_indices[0], dest_index, 1); + return; + } + + int src_i, dest_i; + int j; + + float co[3] = {0.0f, 0.0f, 0.0f}; +#ifdef USE_WELD_NORMALS + float no[3] = {0.0f, 0.0f, 0.0f}; +#endif + uint crease = 0; + uint bweight = 0; + char flag = 0; + + /* interpolates a layer at a time */ + dest_i = 0; + for (src_i = 0; src_i < source->totlayer; src_i++) { + const int type = source->layers[src_i].type; + + /* find the first dest layer with type >= the source type + * (this should work because layers are ordered by type) + */ + while (dest_i < dest->totlayer && dest->layers[dest_i].type < type) { + dest_i++; + } + + /* if there are no more dest layers, we're done */ + if (dest_i == dest->totlayer) { + break; + } + + /* if we found a matching layer, add the data */ + if (dest->layers[dest_i].type == type) { + void *src_data = source->layers[src_i].data; + + if (CustomData_layer_has_math(dest, dest_i)) { + const int size = CustomData_sizeof(type); + void *dst_data = dest->layers[dest_i].data; + void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size); + for (j = 0; j < count; j++) { + CustomData_data_add( + type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size)); + } + } + else if (type == CD_MVERT) { + for (j = 0; j < count; j++) { + MVert *mv_src = &((MVert *)src_data)[src_indices[j]]; + add_v3_v3(co, mv_src->co); +#ifdef USE_WELD_NORMALS + short *mv_src_no = mv_src->no; + no[0] += mv_src_no[0]; + no[1] += mv_src_no[1]; + no[2] += mv_src_no[2]; +#endif + bweight += mv_src->bweight; + flag |= mv_src->flag; + } + } + else if (type == CD_MEDGE) { + for (j = 0; j < count; j++) { + MEdge *me_src = &((MEdge *)src_data)[src_indices[j]]; + crease += me_src->crease; + bweight += me_src->bweight; + flag |= me_src->flag; + } + } + else { + CustomData_copy_layer_type_data(source, dest, type, src_indices[0], dest_index, 1); + } + + /* if there are multiple source & dest layers of the same type, + * we don't want to copy all source layers to the same dest, so + * increment dest_i + */ + dest_i++; + } + } + + float fac = 1.0f / count; + + for (dest_i = 0; dest_i < dest->totlayer; dest_i++) { + CustomDataLayer *layer_dst = &dest->layers[dest_i]; + const int type = layer_dst->type; + if (CustomData_layer_has_math(dest, dest_i)) { + const int size = CustomData_sizeof(type); + void *dst_data = layer_dst->data; + void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size); + CustomData_data_multiply(type, v_dst, fac); + } + else if (type == CD_MVERT) { + MVert *mv = &((MVert *)layer_dst->data)[dest_index]; + mul_v3_fl(co, fac); + bweight *= fac; + CLAMP_MAX(bweight, 255); + + copy_v3_v3(mv->co, co); +#ifdef USE_WELD_NORMALS + mul_v3_fl(no, fac); + short *mv_no = mv->no; + mv_no[0] = (short)no[0]; + mv_no[1] = (short)no[1]; + mv_no[2] = (short)no[2]; +#endif + + mv->flag = flag; + mv->bweight = (char)bweight; + } + else if (type == CD_MEDGE) { + MEdge *me = &((MEdge *)layer_dst->data)[dest_index]; + crease *= fac; + bweight *= fac; + CLAMP_MAX(crease, 255); + CLAMP_MAX(bweight, 255); + + me->crease = (char)crease; + me->bweight = (char)bweight; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Weld Modifier Main + * \{ */ + +struct WeldOverlapData { + const MVert *mvert; + float merge_dist_sq; +}; +static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread)) +{ + if (index_a < index_b) { + struct WeldOverlapData *data = userdata; + const MVert *mvert = data->mvert; + const float dist_sq = len_squared_v3v3(mvert[index_a].co, mvert[index_b].co); + return dist_sq <= data->merge_dist_sq; + } + return false; +} + +static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *ctx, Mesh *mesh) +{ + Mesh *result = mesh; + + Object *ob = ctx->object; + BLI_bitmap *v_mask = NULL; + int v_mask_act = 0; + + const MVert *mvert; + const MLoop *mloop; + const MPoly *mpoly, *mp; + uint totvert, totedge, totloop, totpoly; + uint i; + + mvert = mesh->mvert; + totvert = mesh->totvert; + + /* Vertex Group. */ + const int defgrp_index = defgroup_name_index(ob, wmd->defgrp_name); + if (defgrp_index != -1) { + MDeformVert *dvert, *dv; + dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + dv = &dvert[0]; + v_mask = BLI_BITMAP_NEW(totvert, __func__); + for (i = 0; i < totvert; i++, dv++) { + const bool found = defvert_find_weight(dv, defgrp_index) > 0.0f; + if (found) { + BLI_BITMAP_ENABLE(v_mask, i); + v_mask_act++; + } + } + } + + /* Get overlap map. */ + /* TODO: For a better performanse use KD-Tree. */ + struct BVHTreeFromMesh treedata; + BVHTree *bvhtree = bvhtree_from_mesh_verts_ex( + &treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist, 2, 6, 0, NULL); + + struct WeldOverlapData data; + data.mvert = mvert; + data.merge_dist_sq = SQUARE(wmd->merge_dist); + + uint overlap_tot; + BVHTreeOverlap *overlap = BLI_bvhtree_overlap_ex(bvhtree, + bvhtree, + &overlap_tot, + bvhtree_weld_overlap_cb, + &data, + wmd->max_interactions, + BVH_OVERLAP_RETURN_PAIRS); + + free_bvhtree_from_mesh(&treedata); + + if (overlap_tot) { + WeldMesh weld_mesh; + weld_mesh_context_create(mesh, overlap, overlap_tot, &weld_mesh); + + mloop = mesh->mloop; + mpoly = mesh->mpoly; + + totedge = mesh->totedge; + totloop = mesh->totloop; + totpoly = mesh->totpoly; + + const int result_nverts = totvert - weld_mesh.vert_kill_tot; + const int result_nedges = totedge - weld_mesh.edge_kill_tot; + const int result_nloops = totloop - weld_mesh.loop_kill_tot; + const int result_npolys = totpoly - weld_mesh.poly_kill_tot + weld_mesh.wpoly_new_len; + + result = BKE_mesh_new_nomain_from_template( + mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); + + /* Vertices */ + + uint *vert_final = weld_mesh.vert_groups_map; + uint *index_iter = &vert_final[0]; + int dest_index = 0; + for (i = 0; i < totvert; i++, index_iter++) { + int source_index = i; + int count = 0; + while (i < totvert && *index_iter == OUT_OF_CONTEXT) { + *index_iter = dest_index + count; + index_iter++; + count++; + i++; + } + if (count) { + CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count); + dest_index += count; + } + if (i == totvert) { + break; + } + if (*index_iter != ELEM_MERGED) { + struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter]; + customdata_weld(&mesh->vdata, + &result->vdata, + &weld_mesh.vert_groups_buffer[wgroup->ofs], + wgroup->len, + dest_index); + *index_iter = dest_index; + dest_index++; + } + } + + BLI_assert(dest_index == result_nverts); + + /* Edges */ + + uint *edge_final = weld_mesh.edge_groups_map; + index_iter = &edge_final[0]; + dest_index = 0; + for (i = 0; i < totedge; i++, index_iter++) { + int source_index = i; + int count = 0; + while (i < totedge && *index_iter == OUT_OF_CONTEXT) { + *index_iter = dest_index + count; + index_iter++; + count++; + i++; + } + if (count) { + CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count); + MEdge *me = &result->medge[dest_index]; + dest_index += count; + for (; count--; me++) { + me->v1 = vert_final[me->v1]; + me->v2 = vert_final[me->v2]; + } + } + if (i == totedge) { + break; + } + if (*index_iter != ELEM_MERGED) { + struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter]; + customdata_weld(&mesh->edata, + &result->edata, + &weld_mesh.edge_groups_buffer[wegrp->group.ofs], + wegrp->group.len, + dest_index); + MEdge *me = &result->medge[dest_index]; + me->v1 = vert_final[wegrp->v1]; + me->v2 = vert_final[wegrp->v2]; + me->flag |= ME_LOOSEEDGE; + + *index_iter = dest_index; + dest_index++; + } + } + + BLI_assert(dest_index == result_nedges); + + /* Polys/Loops */ + + mp = &mpoly[0]; + MPoly *r_mp = &result->mpoly[0]; + MLoop *r_ml = &result->mloop[0]; + uint r_i = 0; + int loop_cur = 0; + uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len); + for (i = 0; i < totpoly; i++, mp++) { + int loop_start = loop_cur; + uint poly_ctx = weld_mesh.poly_map[i]; + if (poly_ctx == OUT_OF_CONTEXT) { + uint mp_totloop = mp->totloop; + CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_totloop); + loop_cur += mp_totloop; + for (; mp_totloop--; r_ml++) { + r_ml->v = vert_final[r_ml->v]; + r_ml->e = edge_final[r_ml->e]; + } + } + else { + WeldPoly *wp = &weld_mesh.wpoly[poly_ctx]; + WeldLoopOfPolyIter iter; + if (!weld_iter_loop_of_poly_begin( + &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) { + continue; + } + else { + if (wp->poly_dst != OUT_OF_CONTEXT) { + continue; + } + while (weld_iter_loop_of_poly_next(&iter)) { + customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur); + uint v = vert_final[iter.v]; + uint e = edge_final[iter.e]; + r_ml->v = v; + r_ml->e = e; + r_ml++; + loop_cur++; + if (iter.type) { + result->medge[e].flag &= ~ME_LOOSEEDGE; + } + BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0); + } + } + } + + CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1); + r_mp->loopstart = loop_start; + r_mp->totloop = loop_cur - loop_start; + r_mp++; + r_i++; + } + + WeldPoly *wp = &weld_mesh.wpoly_new[0]; + for (i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) { + int loop_start = loop_cur; + WeldLoopOfPolyIter iter; + if (!weld_iter_loop_of_poly_begin( + &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) { + continue; + } + else { + if (wp->poly_dst != OUT_OF_CONTEXT) { + continue; + } + while (weld_iter_loop_of_poly_next(&iter)) { + customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur); + uint v = vert_final[iter.v]; + uint e = edge_final[iter.e]; + r_ml->v = v; + r_ml->e = e; + r_ml++; + loop_cur++; + if (iter.type) { + result->medge[e].flag &= ~ME_LOOSEEDGE; + } + BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0); + } + } + r_mp->loopstart = loop_start; + r_mp->totloop = loop_cur - loop_start; + r_mp++; + r_i++; + } + + BLI_assert((int)r_i == result_npolys); + BLI_assert(loop_cur == result_nloops); + + /* is this needed? */ + /* recalculate normals */ + result->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + + weld_mesh_context_free(&weld_mesh); + } + + if (v_mask) { + MEM_freeN(v_mask); + } + MEM_freeN(overlap); + return result; +} + +static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) +{ + WeldModifierData *wmd = (WeldModifierData *)md; + return weldModifier_doWeld(wmd, ctx, mesh); +} + +static void initData(ModifierData *md) +{ + WeldModifierData *wmd = (WeldModifierData *)md; + + wmd->merge_dist = 0.001f; + wmd->max_interactions = 1; + wmd->defgrp_name[0] = '\0'; +} + +ModifierTypeInfo modifierType_Weld = { + /* name */ "Weld", + /* structName */ "WeldModifierData", + /* structSize */ sizeof(WeldModifierData), + /* type */ eModifierTypeType_Constructive, + /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs, + + /* copyData */ modifier_copyData_generic, + + /* deformVerts */ NULL, + /* deformMatrices */ NULL, + /* deformVertsEM */ NULL, + /* deformMatricesEM */ NULL, + /* applyModifier */ applyModifier, + + /* initData */ initData, + /* requiredDataMask */ NULL, + /* freeData */ NULL, + /* isDisabled */ NULL, + /* updateDepsgraph */ NULL, + /* dependsOnTime */ NULL, + /* dependsOnNormals */ NULL, + /* foreachObjectLink */ NULL, + /* foreachIDLink */ NULL, + /* foreachTexLink */ NULL, + /* freeRuntimeData */ NULL, +}; + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index f24b7826b01..1f2eb4e28fc 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -3727,12 +3727,12 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle ScrArea *sa = handler->dynamic.user_data; handler->keymap_tool = NULL; bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL; - if (tref_rt && tref_rt->keymap[0]) { + if (tref_rt && (tref_rt->keymap[0] || tref_rt->keymap_fallback[0])) { const char *keymap_id = tref_rt->keymap; /* Support for the gizmo owning the tool keymap. */ if (USER_EXPEREMENTAL_TEST(&U, use_tool_fallback)) { - if (tref_rt->gizmo_group[0] != '\0') { + if (tref_rt->gizmo_group[0] != '\0' && tref_rt->keymap_fallback[0] != '\n') { wmGizmoMap *gzmap = NULL; wmGizmoGroup *gzgroup = NULL; for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { @@ -3750,9 +3750,7 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle if (gzgroup->use_fallback_keymap) { wmGizmo *highlight = wm_gizmomap_highlight_get(gzmap); if (highlight == NULL) { - if (tref_rt->keymap_fallback[0]) { - keymap_id = tref_rt->keymap_fallback; - } + keymap_id = tref_rt->keymap_fallback; } } } @@ -3760,15 +3758,18 @@ wmKeyMap *WM_event_get_keymap_from_toolsystem(wmWindowManager *wm, wmEventHandle } } - wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( - &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW); - /* We shouldn't use keymaps from unrelated spaces. */ - if (km != NULL) { - handler->keymap_tool = sa->runtime.tool; - return km; - } - else { - printf("Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); + if (keymap_id[0]) { + wmKeyMap *km = WM_keymap_list_find_spaceid_or_empty( + &wm->userconf->keymaps, keymap_id, sa->spacetype, RGN_TYPE_WINDOW); + /* We shouldn't use keymaps from unrelated spaces. */ + if (km != NULL) { + handler->keymap_tool = sa->runtime.tool; + return km; + } + else { + printf( + "Keymap: '%s' not found for tool '%s'\n", tref_rt->keymap, sa->runtime.tool->idname); + } } } return NULL; |