BMBVHTree *BKE_bmbvh_new_ex(
        BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag,
        const float (*cos_cage)[3], const bool cos_cage_free,
        bool (*test_fn)(BMFace *, void *user_data), void *user_data)
{
	/* could become argument */
	const float epsilon = FLT_EPSILON * 2.0f;

	BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree");
	float cos[3][3];
	int i;
	int tottri;

	/* avoid testing every tri */
	BMFace *f_test, *f_test_prev;
	bool test_fn_ret;

	/* BKE_editmesh_tessface_calc() must be called already */
	BLI_assert(looptris_tot != 0 || bm->totface == 0);

	if (cos_cage) {
		BM_mesh_elem_index_ensure(bm, BM_VERT);
	}

	bmtree->looptris = looptris;
	bmtree->looptris_tot = looptris_tot;
	bmtree->bm = bm;
	bmtree->cos_cage = cos_cage;
	bmtree->cos_cage_free = cos_cage_free;
	bmtree->flag = flag;

	if (test_fn) {
		/* callback must do... */
		BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN)));

		f_test_prev = NULL;
		test_fn_ret = false;

		tottri = 0;
		for (i = 0; i < looptris_tot; i++) {
			f_test = looptris[i][0]->f;
			if (f_test != f_test_prev) {
				test_fn_ret = test_fn(f_test, user_data);
				f_test_prev = f_test;
			}

			if (test_fn_ret) {
				tottri++;
			}
		}
	}
	else {
		tottri = looptris_tot;
	}

	bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);

	f_test_prev = NULL;
	test_fn_ret = false;

	for (i = 0; i < looptris_tot; i++) {
		if (test_fn) {
			/* note, the arrays wont align now! take care */
			f_test = looptris[i][0]->f;
			if (f_test != f_test_prev) {
				test_fn_ret = test_fn(f_test, user_data);
				f_test_prev = f_test;
			}

			if (!test_fn_ret) {
				continue;
			}
		}

		if (cos_cage) {
			copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
			copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
			copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
		}
		else {
			copy_v3_v3(cos[0], looptris[i][0]->v->co);
			copy_v3_v3(cos[1], looptris[i][1]->v->co);
			copy_v3_v3(cos[2], looptris[i][2]->v->co);
		}

		BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
	}
	
	BLI_bvhtree_balance(bmtree->tree);
	
	return bmtree;
}
static int gizmo_preselect_edgering_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
  MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
  struct {
    Object *ob;
    BMEdge *eed;
    float dist;
    int base_index;
  } best = {
      .dist = ED_view3d_select_dist_px(),
  };

  struct {
    int base_index;
    int edge_index;
  } prev = {
      .base_index = gz_ring->base_index,
      .edge_index = gz_ring->edge_index,
  };

  {
    ViewLayer *view_layer = CTX_data_view_layer(C);
    View3D *v3d = CTX_wm_view3d(C);
    if (((gz_ring->bases)) == NULL || (gz_ring->bases[0] != view_layer->basact)) {
      MEM_SAFE_FREE(gz_ring->bases);
      gz_ring->bases = BKE_view_layer_array_from_bases_in_edit_mode(
          view_layer, v3d, &gz_ring->bases_len);
    }
  }

  ViewContext vc;
  em_setup_viewcontext(C, &vc);
  copy_v2_v2_int(vc.mval, mval);

  uint base_index;
  BMEdge *eed_test = EDBM_edge_find_nearest_ex(
      &vc, &best.dist, NULL, false, false, NULL, gz_ring->bases, gz_ring->bases_len, &base_index);

  if (eed_test) {
    best.ob = gz_ring->bases[base_index]->object;
    best.eed = eed_test;
    best.base_index = base_index;
  }

  BMesh *bm = NULL;
  if (best.eed) {
    gz_ring->base_index = best.base_index;
    bm = BKE_editmesh_from_object(gz_ring->bases[gz_ring->base_index]->object)->bm;
    BM_mesh_elem_index_ensure(bm, BM_EDGE);
    gz_ring->edge_index = BM_elem_index_get(best.eed);
  }
  else {
    gz_ring->base_index = -1;
    gz_ring->edge_index = -1;
  }

  if ((prev.base_index == gz_ring->base_index) && (prev.edge_index == gz_ring->edge_index)) {
    /* pass (only recalculate on change) */
  }
  else {
    if (best.eed) {
      const float(*coords)[3] = NULL;
      {
        Object *ob = gz_ring->bases[gz_ring->base_index]->object;
        Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
        if (me_eval->runtime.edit_data) {
          coords = me_eval->runtime.edit_data->vertexCos;
        }
      }
      EDBM_preselect_edgering_update_from_edge(gz_ring->psel, bm, best.eed, 1, coords);
    }
    else {
      EDBM_preselect_edgering_clear(gz_ring->psel);
    }

    RNA_int_set(gz->ptr, "object_index", gz_ring->base_index);
    RNA_int_set(gz->ptr, "edge_index", gz_ring->edge_index);

    ARegion *ar = CTX_wm_region(C);
    ED_region_tag_redraw(ar);
  }

  // return best.eed ? 0 : -1;
  return -1;
}

static void gizmo_preselect_edgering_setup(wmGizmo *gz)
{
  MeshEdgeRingGizmo3D *gz_ring = (MeshEdgeRingGizmo3D *)gz;
  if (gz_ring->psel == NULL) {
    gz_ring->psel = EDBM_preselect_edgering_create();
  }
  gz_ring->base_index = -1;
}
static int gizmo_preselect_elem_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
  MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
  struct {
    Object *ob;
    BMElem *ele;
    float dist;
    int base_index;
  } best = {
      .dist = ED_view3d_select_dist_px(),
  };

  struct {
    int base_index;
    int vert_index;
    int edge_index;
    int face_index;
  } prev = {
      .base_index = gz_ele->base_index,
      .vert_index = gz_ele->vert_index,
      .edge_index = gz_ele->edge_index,
      .face_index = gz_ele->face_index,
  };

  {
    ViewLayer *view_layer = CTX_data_view_layer(C);
    View3D *v3d = CTX_wm_view3d(C);
    if (((gz_ele->bases)) == NULL || (gz_ele->bases[0] != view_layer->basact)) {
      MEM_SAFE_FREE(gz_ele->bases);
      gz_ele->bases = BKE_view_layer_array_from_bases_in_edit_mode(
          view_layer, v3d, &gz_ele->bases_len);
    }
  }

  ViewContext vc;
  em_setup_viewcontext(C, &vc);
  copy_v2_v2_int(vc.mval, mval);

  {
    /* TODO: support faces. */
    int base_index = -1;
    BMVert *eve_test;
    BMEdge *eed_test;

    if (EDBM_unified_findnearest_from_raycast(&vc,
                                              gz_ele->bases,
                                              gz_ele->bases_len,
                                              true,
                                              &base_index,
                                              &eve_test,
                                              &eed_test,
                                              NULL)) {
      Base *base = gz_ele->bases[base_index];
      best.ob = base->object;
      if (eve_test) {
        best.ele = (BMElem *)eve_test;
      }
      else if (eed_test) {
        best.ele = (BMElem *)eed_test;
      }
      else {
        BLI_assert(0);
      }
      best.base_index = base_index;
      /* Check above should never fail, if it does it's an internal error. */
      BLI_assert(best.base_index != -1);
    }
  }

  BMesh *bm = NULL;

  gz_ele->base_index = -1;
  gz_ele->vert_index = -1;
  gz_ele->edge_index = -1;
  gz_ele->face_index = -1;

  if (best.ele) {
    gz_ele->base_index = best.base_index;
    bm = BKE_editmesh_from_object(gz_ele->bases[gz_ele->base_index]->object)->bm;
    BM_mesh_elem_index_ensure(bm, best.ele->head.htype);

    if (best.ele->head.htype == BM_VERT) {
      gz_ele->vert_index = BM_elem_index_get(best.ele);
    }
    else if (best.ele->head.htype == BM_EDGE) {
      gz_ele->edge_index = BM_elem_index_get(best.ele);
    }
    else if (best.ele->head.htype == BM_FACE) {
      gz_ele->face_index = BM_elem_index_get(best.ele);
    }
  }

  if ((prev.base_index == gz_ele->base_index) && (prev.vert_index == gz_ele->vert_index) &&
      (prev.edge_index == gz_ele->edge_index) && (prev.face_index == gz_ele->face_index)) {
    /* pass (only recalculate on change) */
  }
  else {
    if (best.ele) {
      const float(*coords)[3] = NULL;
      {
        Object *ob = gz_ele->bases[gz_ele->base_index]->object;
        Depsgraph *depsgraph = CTX_data_depsgraph(C);
        Mesh *me_eval = (Mesh *)DEG_get_evaluated_id(depsgraph, ob->data);
        if (me_eval->runtime.edit_data) {
          coords = me_eval->runtime.edit_data->vertexCos;
        }
      }
      EDBM_preselect_elem_update_from_single(gz_ele->psel, bm, best.ele, coords);
    }
    else {
      EDBM_preselect_elem_clear(gz_ele->psel);
    }

    RNA_int_set(gz->ptr, "object_index", gz_ele->base_index);
    RNA_int_set(gz->ptr, "vert_index", gz_ele->vert_index);
    RNA_int_set(gz->ptr, "edge_index", gz_ele->edge_index);
    RNA_int_set(gz->ptr, "face_index", gz_ele->face_index);

    ARegion *ar = CTX_wm_region(C);
    ED_region_tag_redraw(ar);
  }

  // return best.eed ? 0 : -1;
  return -1;
}

static void gizmo_preselect_elem_setup(wmGizmo *gz)
{
  MeshElemGizmo3D *gz_ele = (MeshElemGizmo3D *)gz;
  if (gz_ele->psel == NULL) {
    gz_ele->psel = EDBM_preselect_elem_create();
  }
  gz_ele->base_index = -1;
}
Beispiel #4
0
BMBVHTree *BKE_bmbvh_new(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free)
{
	/* could become argument */
	const float epsilon = FLT_EPSILON * 2.0f;

	struct BMLoop *(*looptris)[3] = em->looptris;
	BMBVHTree *bmtree = MEM_callocN(sizeof(*bmtree), "BMBVHTree");
	float cos[3][3];
	int i;
	int tottri;

	/* BKE_editmesh_tessface_calc() must be called already */
	BLI_assert(em->tottri != 0 || em->bm->totface == 0);

	if (cos_cage) {
		BM_mesh_elem_index_ensure(em->bm, BM_VERT);
	}

	bmtree->em = em;
	bmtree->bm = em->bm;
	bmtree->cos_cage = cos_cage;
	bmtree->cos_cage_free = cos_cage_free;
	bmtree->flag = flag;

	if (flag & (BMBVH_RESPECT_SELECT)) {
		tottri = 0;
		for (i = 0; i < em->tottri; i++) {
			if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) {
				tottri++;
			}
		}
	}
	else if (flag & (BMBVH_RESPECT_HIDDEN)) {
		tottri = 0;
		for (i = 0; i < em->tottri; i++) {
			if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) {
				tottri++;
			}
		}
	}
	else {
		tottri = em->tottri;
	}

	bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);

	for (i = 0; i < em->tottri; i++) {

		if (flag & BMBVH_RESPECT_SELECT) {
			/* note, the arrays wont align now! take care */
			if (!BM_elem_flag_test(em->looptris[i][0]->f, BM_ELEM_SELECT)) {
				continue;
			}
		}
		else if (flag & BMBVH_RESPECT_HIDDEN) {
			/* note, the arrays wont align now! take care */
			if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) {
				continue;
			}
		}

		if (cos_cage) {
			copy_v3_v3(cos[0], cos_cage[BM_elem_index_get(looptris[i][0]->v)]);
			copy_v3_v3(cos[1], cos_cage[BM_elem_index_get(looptris[i][1]->v)]);
			copy_v3_v3(cos[2], cos_cage[BM_elem_index_get(looptris[i][2]->v)]);
		}
		else {
			copy_v3_v3(cos[0], looptris[i][0]->v->co);
			copy_v3_v3(cos[1], looptris[i][1]->v->co);
			copy_v3_v3(cos[2], looptris[i][2]->v->co);
		}

		BLI_bvhtree_insert(bmtree->tree, i, (float *)cos, 3);
	}
	
	BLI_bvhtree_balance(bmtree->tree);
	
	return bmtree;
}