/* get a vector, vec, that points from v1->co to wherever makes sense to
 * the bevel operation as a whole based on the relationship between v1 and v2
 * (won't necessarily be a vec from v1->co to v2->co, though it probably will be);
 * the return value is -1 for failure, 0 if we used vert co's, and 1 if we used transform origins */
static int BME_bevel_get_vec(float *vec, BME_Vert *v1, BME_Vert *v2, BME_TransData_Head *td) {
	BME_TransData *vtd1, *vtd2;

	vtd1 = BME_get_transdata(td,v1);
	vtd2 = BME_get_transdata(td,v2);
	if (!vtd1 || !vtd2) {
		//printf("BME_bevel_get_vec() got called without proper BME_TransData\n");
		return -1;
	}

	/* compare the transform origins to see if we can use the vert co's;
	 * if they belong to different origins, then we will use the origins to determine
	 * the vector */
	if (compare_v3v3(vtd1->org,vtd2->org,0.000001f)) {
		VECSUB(vec,v2->co,v1->co);
		if (len_v3(vec) < 0.000001f) {
			mul_v3_fl(vec,0);
		}
		return 0;
	}
	else {
		VECSUB(vec,vtd2->org,vtd1->org);
		if (len_v3(vec) < 0.000001f) {
			mul_v3_fl(vec,0);
		}
		return 1;
	}
}
static float BME_bevel_set_max(BME_Vert *v1, BME_Vert *v2, float value, BME_TransData_Head *td) {
	BME_TransData *vtd1, *vtd2;
	float max, fac1, fac2, vec1[3], vec2[3], vec3[3];

	BME_bevel_get_vec(vec1,v1,v2,td);
	vtd1 = BME_get_transdata(td,v1);
	vtd2 = BME_get_transdata(td,v2);

	if (vtd1->loc == NULL) {
		fac1 = 0;
	}
	else {
		VECCOPY(vec2,vtd1->vec);
		mul_v3_fl(vec2,vtd1->factor);
		if (dot_v3v3(vec1, vec1)) {
			project_v3_v3v3(vec2,vec2,vec1);
			fac1 = len_v3(vec2)/value;
		}
		else {
			fac1 = 0;
		}
	}

	if (vtd2->loc == NULL) {
		fac2 = 0;
	}
	else {
		VECCOPY(vec3,vtd2->vec);
		mul_v3_fl(vec3,vtd2->factor);
		if (dot_v3v3(vec1, vec1)) {
			project_v3_v3v3(vec2,vec3,vec1);
			fac2 = len_v3(vec2)/value;
		}
		else {
			fac2 = 0;
		}
	}

	if (fac1 || fac2) {
		max = len_v3(vec1)/(fac1 + fac2);
		if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
			*vtd1->max = max;
		}
		if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
			*vtd2->max = max;
		}
	}
	else {
		max = -1;
	}

	return max;
}
static void BME_bevel_add_vweight(BME_TransData_Head *td, BME_Mesh *bm, BME_Vert *v, float weight, float factor, int options) {
	BME_TransData *vtd;

	if (v->tflag1 & BME_BEVEL_NONMAN) return;
	v->tflag1 |= BME_BEVEL_BEVEL;
	if ( (vtd = BME_get_transdata(td, v)) ) {
		if (options & BME_BEVEL_EMIN) {
			vtd->factor = 1.0;
			if (vtd->weight < 0 || weight < vtd->weight) {
				vtd->weight = weight;
			}
		}
		else if (options & BME_BEVEL_EMAX) {
			vtd->factor = 1.0;
			if (weight > vtd->weight) {
				vtd->weight = weight;
			}
		}
		else if (vtd->weight < 0) {
			vtd->factor = factor;
			vtd->weight = weight;
		}
		else {
			vtd->factor += factor; /* increment number of edges with weights (will be averaged) */
			vtd->weight += weight; /* accumulate all the weights */
		}
	}
	else {
		/* we'll use vtd->loc == NULL to mark that this vert is not moving */
		vtd = BME_assign_transdata(td, bm, v, v->co, NULL, NULL, NULL, factor, weight, -1, NULL);
	}
}
/* options that can be passed:
 * BME_BEVEL_VWEIGHT	<---- v, Look at vertex weights; use defgrp_index if option is present
 * BME_BEVEL_SELECT		<---- v,e, check selection for verts and edges
 * BME_BEVEL_ANGLE		<---- v,e, don't bevel-tag verts - tag verts per edge
 * BME_BEVEL_VERT		<---- e, don't tag edges
 * BME_BEVEL_EWEIGHT	<---- e, use crease flag for now
 * BME_BEVEL_PERCENT	<---- Will need to think about this one; will probably need to incorporate into actual bevel routine
 * BME_BEVEL_RADIUS		<---- Will need to think about this one; will probably need to incorporate into actual bevel routine
 * All weights/limits are stored per-vertex
 */
BME_Mesh *BME_bevel(BME_Mesh *bm, float value, int res, int options, int defgrp_index, float angle, BME_TransData_Head **rtd) {
	BME_Vert *v;
	BME_TransData_Head *td;
	BME_TransData *vtd;
	int i;
	float fac=1, d;

	td = BME_init_transdata(BLI_MEMARENA_STD_BUFSIZE);

	BME_bevel_initialize(bm, options, defgrp_index, angle, td);

	/* recursion math courtesy of Martin Poirier (theeth) */
	for (i=0; i<res-1; i++) {
		if (i==0) fac += 1.0f/3.0f; else fac += 1.0f/(3 * i * 2.0f);
	}
	d = 1.0f/fac;
	/* crazy idea. if res == 0, don't remove original geometry */
	for (i=0; i<res || (res==0 && i==0); i++) {
		if (i != 0) BME_bevel_reinitialize(bm);
		BME_model_begin(bm);
		BME_bevel_mesh(bm,d,res,options,defgrp_index,td);
		BME_model_end(bm);
		if (i==0) d /= 3; else d /= 2;
	}

	BME_tesselate(bm);

	if (rtd) {
		*rtd = td;
		return bm;
	}

	/* transform pass */
	for (v = bm->verts.first; v; v=v->next) {
		if ( (vtd = BME_get_transdata(td, v)) ) {
			if (vtd->max && (*vtd->max > 0 && value > *vtd->max)) {
				d = *vtd->max;
			}
			else {
				d = value;
			}
			VECADDFAC(v->co,vtd->org,vtd->vec,vtd->factor*d);
		}
		v->tflag1 = 0;
	}

	BME_free_transdata(td);
	return bm;
}
Esempio n. 5
0
/* adds the geometry in the bmesh to editMesh (does not free editMesh)
 * if td != NULL, the transdata will be mapped to the EditVert's co */
void BME_bmesh_to_editmesh(BME_Mesh *bm, BME_TransData_Head *td, EditMesh *em) {
	BME_Vert *v1;
	BME_Edge *e;
	BME_Poly *f;
	
	BME_TransData *vtd;

	EditVert *eve1, *eve2, *eve3, *eve4, **evlist;
	EditEdge *eed;
	EditFace *efa;

	int totvert, len, i, numTex, numCol;

	if (em == NULL) return;

	CustomData_copy(&bm->vdata, &em->vdata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_copy(&bm->edata, &em->edata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_copy(&bm->pdata, &em->fdata, CD_MASK_BMESH, CD_CALLOC, 0);
	CustomData_from_bmeshpoly(&em->fdata, &bm->pdata, &bm->ldata,0);
	numTex = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
	numCol = CustomData_number_of_layers(&bm->ldata, CD_MLOOPCOL);


	/* convert to EditMesh */
	/* make editverts */
	totvert = BLI_countlist(&(bm->verts));
	evlist= (EditVert **)MEM_mallocN(totvert*sizeof(void *),"evlist");
	for (i=0,v1=bm->verts.first;v1;v1=v1->next,i++) {
		v1->tflag1 = i;
		eve1 = NULL; //XXX addvertlist(v1->co,NULL);
		if (td && (vtd = BME_get_transdata(td,v1))) {
			vtd->loc = eve1->co;
		}
		eve1->keyindex = i;
		evlist[i]= eve1;
		eve1->f = (unsigned char)v1->flag;
		eve1->h = (unsigned char)v1->h;
		eve1->bweight = v1->bweight;
		CustomData_em_copy_data(&bm->vdata, &em->vdata, v1->data, &eve1->data);
	}
	
	/* make edges */
	for (e=bm->edges.first;e;e=e->next) {
		if(0) { //XXX if(!(findedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1]))){
			eed= NULL; //XXX addedgelist(evlist[e->v1->tflag1], evlist[e->v2->tflag1], NULL);
			eed->crease = e->crease;
			eed->bweight = e->bweight;
			if(e->flag & ME_SEAM) eed->seam = 1;
			if(e->flag & ME_SHARP) eed->sharp = 1;
			if(e->flag & SELECT) eed->f |= SELECT;
			//XXX if(e->flag & ME_FGON) eed->h= EM_FGON; // 2 different defines!
			if(e->flag & ME_HIDE) eed->h |= 1;
			if(em->selectmode==SCE_SELECT_EDGE) { 
				; //XXX EM_select_edge(eed, eed->f & SELECT);
			}
			CustomData_em_copy_data(&bm->edata, &em->edata, e->data, &eed->data);
		}
	}

	/* make faces */
	for (f=bm->polys.first;f;f=f->next) {
		len = BME_cycle_length(f->loopbase);
		if (len==3 || len==4) {
			eve1= evlist[f->loopbase->v->tflag1];
			eve2= evlist[f->loopbase->next->v->tflag1];
			eve3= evlist[f->loopbase->next->next->v->tflag1];
			if (len == 4) {
				eve4= evlist[f->loopbase->prev->v->tflag1];
			}
			else {
				eve4= NULL;
			}

			efa = NULL; //XXX addfacelist(eve1, eve2, eve3, eve4, NULL, NULL);
			efa->mat_nr = (unsigned char)f->mat_nr;
			efa->flag= f->flag & ~ME_HIDE;
			if(f->flag & ME_FACE_SEL) {
				efa->f |= SELECT;
			}
			if(f->flag & ME_HIDE) efa->h= 1;
			// XXX flag depricated
			// if((G.f & G_FACESELECT) && (efa->f & SELECT))
				//XXX EM_select_face(efa, 1); /* flush down */
			CustomData_em_copy_data(&bm->pdata, &em->fdata, f->data, &efa->data);
			BME_loops_to_corners(bm, &em->fdata, efa->data, f,numCol,numTex);
		}
	}

	MEM_freeN(evlist);

}
/**
 *			BME_bevel_poly
 *
 *	Polygon inset tool:
 *
 *	Insets a polygon/face based on the tflag1's of its vertices
 *	and edges. Used by the bevel tool only, for now.
 *  The parameter "value" is the distance to inset (should be negative).
 *  The parameter "options" is not currently used.
 *
 *	Returns -
 *  A BME_Poly pointer to the resulting inner face.
*/
static BME_Poly *BME_bevel_poly(BME_Mesh *bm, BME_Poly *f, float value, int options, BME_TransData_Head *td) {
	BME_Loop *l, *ol;
	BME_TransData *vtd1, *vtd2;
	float up_vec[3], vec1[3], vec2[3], vec3[3], fac1, fac2, max = -1;
	int len, i;

	up_vec[0] = 0.0f;
	up_vec[1] = 0.0f;
	up_vec[2] = 0.0f;
	/* find a good normal for this face (there's better ways, I'm sure) */
	ol = f->loopbase;
	l = ol->next;
	for (i=0,ol=f->loopbase,l=ol->next; l->next!=ol; l=l->next) {
		BME_bevel_get_vec(vec1,l->next->v,ol->v,td);
		BME_bevel_get_vec(vec2,l->v,ol->v,td);
		cross_v3_v3v3(vec3,vec2,vec1);
		VECADD(up_vec,up_vec,vec3);
		i++;
	}
	mul_v3_fl(up_vec,1.0f/i);
	normalize_v3(up_vec);

	for (i=0,len=f->len; i<len; i++,l=l->next) {
		if ((l->e->tflag1 & BME_BEVEL_BEVEL) && (l->e->tflag1 & BME_BEVEL_ORIG)) {
			max = 1.0f;
			l = BME_bevel_edge(bm, l, value, options, up_vec, td);
		}
		else if ((l->v->tflag1 & BME_BEVEL_BEVEL) && (l->v->tflag1 & BME_BEVEL_ORIG) && (l->prev->e->tflag1 & BME_BEVEL_BEVEL) == 0) {
			max = 1.0f;
			l = BME_bevel_vert(bm, l, value, options, up_vec, td);
		}
	}

	/* max pass */
	if (value > 0.5 && max > 0) {
		max = -1;
		for (i=0,len=f->len; i<len; i++,l=l->next) {
			if ((l->e->tflag1 & BME_BEVEL_BEVEL) || (l->e->tflag1 & BME_BEVEL_ORIG)) {
				BME_bevel_get_vec(vec1,l->v,l->next->v,td);
				vtd1 = BME_get_transdata(td,l->v);
				vtd2 = BME_get_transdata(td,l->next->v);
				if (vtd1->loc == NULL) {
					fac1 = 0;
				}
				else {
					VECCOPY(vec2,vtd1->vec);
					mul_v3_fl(vec2,vtd1->factor);
					if (dot_v3v3(vec1, vec1)) {
						project_v3_v3v3(vec2,vec2,vec1);
						fac1 = len_v3(vec2)/value;
					}
					else {
						fac1 = 0;
					}
				}
				if (vtd2->loc == NULL) {
					fac2 = 0;
				}
				else {
					VECCOPY(vec3,vtd2->vec);
					mul_v3_fl(vec3,vtd2->factor);
					if (dot_v3v3(vec1, vec1)) {
						project_v3_v3v3(vec2,vec3,vec1);
						fac2 = len_v3(vec2)/value;
					}
					else {
						fac2 = 0;
					}
				}
				if (fac1 || fac2) {
					max = len_v3(vec1)/(fac1 + fac2);
					if (vtd1->max && (*vtd1->max < 0 || max < *vtd1->max)) {
						*vtd1->max = max;
					}
					if (vtd2->max && (*vtd2->max < 0 || max < *vtd2->max)) {
						*vtd2->max = max;
					}
				}
			}
		}
	}

	return l->f;
}
/* BME_bevel_split_edge() is the main math work-house; its responsibilities are:
 * using the vert and the loop passed, get or make the split vert, set its coordinates
 * and transform properties, and set the max limits.
 * Finally, return the split vert. */
static BME_Vert *BME_bevel_split_edge(BME_Mesh *bm, BME_Vert *v, BME_Vert *v1, BME_Loop *l, float *up_vec, float value, BME_TransData_Head *td) {
	BME_TransData *vtd, *vtd1, *vtd2;
	BME_Vert *sv, *v2, *v3, *ov;
	BME_Loop *lv1, *lv2;
	BME_Edge *ne, *e1, *e2;
	float maxfactor, scale, len, dis, vec1[3], vec2[3], t_up_vec[3];
	int is_edge, forward, is_split_vert;

	if (l == NULL) {
		/* what you call operator overloading in C :)
		 * I wanted to use the same function for both wire edges and poly loops
		 * so... here we walk around edges to find the needed verts */
		forward = 1;
		is_split_vert = 0;
		if (v->edge == NULL) {
			//printf("We can't split a loose vert's edge!\n");
			return NULL;
		}
		e1 = v->edge; /* we just use the first two edges */
		e2 = BME_disk_nextedge(v->edge, v);
		if (e1 == e2) {
			//printf("You need at least two edges to use BME_bevel_split_edge()\n");
			return NULL;
		}
		v2 = BME_edge_getothervert(e1, v);
		v3 = BME_edge_getothervert(e2, v);
		if (v1 != v2 && v1 != v3) {
			//printf("Error: more than 2 edges in v's disk cycle, or v1 does not share an edge with v\n");
			return NULL;
		}
		if (v1 == v2) {
			v2 = v3;
		}
		else {
			e1 = e2;
		}
		ov = BME_edge_getothervert(e1,v);
		sv = BME_split_edge(bm,v,e1,&ne,0);
		//BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
		//BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
		//BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
		BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
		sv->tflag1 |= BME_BEVEL_BEVEL;
		ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
		BME_bevel_get_vec(vec1,v1,v,td);
		BME_bevel_get_vec(vec2,v2,v,td);
		cross_v3_v3v3(t_up_vec,vec1,vec2);
		normalize_v3(t_up_vec);
		up_vec = t_up_vec;
	}
	else {
		/* establish loop direction */
		if (l->v == v) {
			forward = 1;
			lv1 = l->next;
			lv2 = l->prev;
			v1 = l->next->v;
			v2 = l->prev->v;
		}
		else if (l->next->v == v) {
			forward = 0;
			lv1 = l;
			lv2 = l->next->next;
			v1 = l->v;
			v2 = l->next->next->v;
		}
		else {
			//printf("ERROR: BME_bevel_split_edge() - v must be adjacent to l\n");
			return NULL;
		}

		if (BME_bevel_is_split_vert(lv1)) {
			is_split_vert = 1;
			sv = v1;
			if (forward) v1 = l->next->next->v;
			else v1 = l->prev->v;
		}
		else {
			is_split_vert = 0;
			ov = BME_edge_getothervert(l->e,v);
			sv = BME_split_edge(bm,v,l->e,&ne,0);
			//BME_data_interp_from_verts(bm, v, ov, sv, 0.25); /*this is technically wrong...*/
			//BME_data_interp_from_faceverts(bm, v, ov, sv, 0.25);
			//BME_data_interp_from_faceverts(bm, ov, v, sv, 0.25);
			BME_assign_transdata(td, bm, sv, sv->co, sv->co, NULL, sv->co, 0, -1, -1, NULL); /* quick default */
			sv->tflag1 |= BME_BEVEL_BEVEL;
			ne->tflag1 = BME_BEVEL_ORIG; /* mark edge as original, even though it isn't */
		}

		if (BME_bevel_is_split_vert(lv2)) {
			if (forward) v2 = lv2->prev->v;
			else v2 = lv2->next->v;
		}
	}

	is_edge = BME_bevel_get_vec(vec1,v,v1,td); /* get the vector we will be projecting onto */
	BME_bevel_get_vec(vec2,v,v2,td); /* get the vector we will be projecting parallel to */
	len = len_v3(vec1);
	normalize_v3(vec1);

	vtd = BME_get_transdata(td, sv);
	vtd1 = BME_get_transdata(td, v);
	vtd2 = BME_get_transdata(td,v1);

	if (vtd1->loc == NULL) {
		/* this is a vert with data only for calculating initial weights */
		if (vtd1->weight < 0) {
			vtd1->weight = 0;
		}
		scale = vtd1->weight/vtd1->factor;
		if (!vtd1->max) {
			vtd1->max = BME_new_transdata_float(td);
			*vtd1->max = -1;
		}
	}
	else {
		scale = vtd1->weight;
	}
	vtd->max = vtd1->max;

	if (is_edge && vtd1->loc != NULL) {
		maxfactor = vtd1->maxfactor;
	}
	else {
		maxfactor = scale*BME_bevel_project_vec(vec1,vec2,up_vec,forward,td);
		if (vtd->maxfactor > 0 && vtd->maxfactor < maxfactor) {
			maxfactor = vtd->maxfactor;
		}
	}

	dis = (v1->tflag1 & BME_BEVEL_ORIG)? len/3 : len/2;
	if (is_edge || dis > maxfactor*value) {
		dis = maxfactor*value;
	}
	VECADDFAC(sv->co,v->co,vec1,dis);
	VECSUB(vec1,sv->co,vtd1->org);
	dis = len_v3(vec1);
	normalize_v3(vec1);
	BME_assign_transdata(td, bm, sv, vtd1->org, vtd1->org, vec1, sv->co, dis, scale, maxfactor, vtd->max);

	return sv;
}