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;
}
예제 #2
0
static int dupli_extrude_cursor(bContext *C, wmOperator *op, wmEvent *event)
{
	ViewContext vc;
	EditVert *eve;
	float min[3], max[3];
	int done= 0;
	short use_proj;

	em_setup_viewcontext(C, &vc);

	use_proj= (vc.scene->toolsettings->snap_flag & SCE_SNAP) &&	(vc.scene->toolsettings->snap_mode==SCE_SNAP_MODE_FACE);
	
	invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); 
	
	INIT_MINMAX(min, max);
	
	for(eve= vc.em->verts.first; eve; eve= eve->next) {
		if(eve->f & SELECT) {
			DO_MINMAX(eve->co, min, max);
			done= 1;
		}
	}

	/* call extrude? */
	if(done) {
		const short rot_src= RNA_boolean_get(op->ptr, "rotate_source");
		EditEdge *eed;
		float vec[3], cent[3], mat[3][3];
		float nor[3]= {0.0, 0.0, 0.0};
		
		/* 2D normal calc */
		float mval_f[2];

		mval_f[0]= (float)event->mval[0];
		mval_f[1]= (float)event->mval[1];

		done= 0;

		/* calculate the normal for selected edges */
		for(eed= vc.em->edges.first; eed; eed= eed->next) {
			if(eed->f & SELECT) {
				float co1[3], co2[3];
				mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co);
				mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co);
				project_float_noclip(vc.ar, co1, co1);
				project_float_noclip(vc.ar, co2, co2);
				
				/* 2D rotate by 90d while adding.
				 *  (x, y) = (y, -x)
				 *
				 * accumulate the screenspace normal in 2D,
				 * with screenspace edge length weighting the result. */
				if(line_point_side_v2(co1, co2, mval_f) >= 0.0f) {
					nor[0] +=  (co1[1] - co2[1]);
					nor[1] += -(co1[0] - co2[0]);
				}
				else {
					nor[0] +=  (co2[1] - co1[1]);
					nor[1] += -(co2[0] - co1[0]);
				}
				done= 1;
			}
		}

		if(done) {
			float view_vec[3], cross[3];

			/* convert the 2D nomal into 3D */
			mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */
			mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */
			
			/* correct the normal to be aligned on the view plane */
			copy_v3_v3(view_vec, vc.rv3d->viewinv[2]);
			mul_mat3_m4_v3(vc.obedit->imat, view_vec);
			cross_v3_v3v3(cross, nor, view_vec);
			cross_v3_v3v3(nor, view_vec, cross);
			normalize_v3(nor);
		}
		
		/* center */
		mid_v3_v3v3(cent, min, max);
		copy_v3_v3(min, cent);
		
		mul_m4_v3(vc.obedit->obmat, min);	// view space
		view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);
		mul_m4_v3(vc.obedit->imat, min); // back in object space
		
		sub_v3_v3(min, cent);
		
		/* calculate rotation */
		unit_m3(mat);
		if(done) {
			float dot;
			
			copy_v3_v3(vec, min);
			normalize_v3(vec);
			dot= dot_v3v3(vec, nor);

			if( fabs(dot)<0.999) {
				float cross[3], si, q1[4];
				
				cross_v3_v3v3(cross, nor, vec);
				normalize_v3(cross);
				dot= 0.5f*saacos(dot);
				
				/* halve the rotation if its applied twice */
				if(rot_src) dot *= 0.5f;
				
				si= (float)sin(dot);
				q1[0]= (float)cos(dot);
				q1[1]= cross[0]*si;
				q1[2]= cross[1]*si;
				q1[3]= cross[2]*si;				
				quat_to_mat3( mat,q1);
			}
		}
		
		if(rot_src) {
			rotateflag(vc.em, SELECT, cent, mat);
			/* also project the source, for retopo workflow */
			if(use_proj)
				EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);
		}
		
		extrudeflag(vc.obedit, vc.em, SELECT, nor, 0);
		rotateflag(vc.em, SELECT, cent, mat);
		translateflag(vc.em, SELECT, min);
		
		recalc_editnormals(vc.em);
	}
	else if(vc.em->selectmode & SCE_SELECT_VERTEX) {

		float imat[4][4];
		const float *curs= give_cursor(vc.scene, vc.v3d);
		
		copy_v3_v3(min, curs);
		view3d_get_view_aligned_coordinate(&vc, min, event->mval, TRUE);

		eve= addvertlist(vc.em, 0, NULL);

		invert_m4_m4(imat, vc.obedit->obmat);
		mul_v3_m4v3(eve->co, imat, min);
		
		eve->f= SELECT;
	}

	if(use_proj)
		EM_project_snap_verts(C, vc.ar, vc.obedit, vc.em);

	WM_event_add_notifier(C, NC_GEOM|ND_DATA, vc.obedit->data); 
	DAG_id_tag_update(vc.obedit->data, 0);
	
	return OPERATOR_FINISHED;
}
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;
}