Ejemplo n.º 1
0
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
                                   Object *ob,
                                   DerivedMesh *dm,
                                   int axis)
{
	const float tolerance_sq = mmd->tolerance * mmd->tolerance;
	const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE);
	int tot_vtargetmap = 0;  /* total merge vertices */

	DerivedMesh *result;
	const int maxVerts = dm->getNumVerts(dm);
	const int maxEdges = dm->getNumEdges(dm);
	const int maxLoops = dm->getNumLoops(dm);
	const int maxPolys = dm->getNumPolys(dm);
	MVert *mv, *mv_prev;
	MEdge *me;
	MLoop *ml;
	MPoly *mp;
	float mtx[4][4];
	int i;
	int a, totshape;
	int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;

	/* mtx is the mirror transformation */
	unit_m4(mtx);
	mtx[axis][axis] = -1.0f;

	if (mmd->mirror_ob) {
		float tmp[4][4];
		float itmp[4][4];

		/* tmp is a transform from coords relative to the object's own origin,
		 * to coords relative to the mirror object origin */
		invert_m4_m4(tmp, mmd->mirror_ob->obmat);
		mul_m4_m4m4(tmp, tmp, ob->obmat);

		/* itmp is the reverse transform back to origin-relative coordinates */
		invert_m4_m4(itmp, tmp);

		/* combine matrices to get a single matrix that translates coordinates into
		 * mirror-object-relative space, does the mirror, and translates back to
		 * origin-relative space */
		mul_m4_m4m4(mtx, mtx, tmp);
		mul_m4_m4m4(mtx, itmp, mtx);
	}

	result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);

	/*copy customdata to original geometry*/
	DM_copy_vert_data(dm, result, 0, 0, maxVerts);
	DM_copy_edge_data(dm, result, 0, 0, maxEdges);
	DM_copy_loop_data(dm, result, 0, 0, maxLoops);
	DM_copy_poly_data(dm, result, 0, 0, maxPolys);


	/* subsurf for eg wont have mesh data in the */
	/* now add mvert/medge/mface layers */

	if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
		dm->copyVertArray(dm, CDDM_get_verts(result));
	}
	if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
		dm->copyEdgeArray(dm, CDDM_get_edges(result));
	}
	if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
		dm->copyLoopArray(dm, CDDM_get_loops(result));
		dm->copyPolyArray(dm, CDDM_get_polys(result));
	}

	/* copy customdata to new geometry,
	 * copy from its self because this data may have been created in the checks above */
	DM_copy_vert_data(result, result, 0, maxVerts, maxVerts);
	DM_copy_edge_data(result, result, 0, maxEdges, maxEdges);
	/* loops are copied later */
	DM_copy_poly_data(result, result, 0, maxPolys, maxPolys);

	if (do_vtargetmap) {
		/* second half is filled with -1 */
		vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap");

		vtmap_a = vtargetmap;
		vtmap_b = vtargetmap + maxVerts;
	}

	/* mirror vertex coordinates */
	mv_prev = CDDM_get_verts(result);
	mv = mv_prev + maxVerts;
	for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
		mul_m4_v3(mtx, mv->co);

		if (do_vtargetmap) {
			/* compare location of the original and mirrored vertex, to see if they
			 * should be mapped for merging */
			if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
				*vtmap_a = maxVerts + i;
				tot_vtargetmap++;

				/* average location */
				mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
				copy_v3_v3(mv_prev->co, mv->co);
			}
			else {
				*vtmap_a = -1;
			}

			*vtmap_b = -1; /* fill here to avoid 2x loops */

			vtmap_a++;
			vtmap_b++;
		}
	}
	
	/* handle shape keys */
	totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY);
	for (a = 0; a < totshape; a++) {
		float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a);
		for (i = maxVerts; i < result->numVertData; i++) {
			mul_m4_v3(mtx, cos[i]);
		}
	}
	
	/* adjust mirrored edge vertex indices */
	me = CDDM_get_edges(result) + maxEdges;
	for (i = 0; i < maxEdges; i++, me++) {
		me->v1 += maxVerts;
		me->v2 += maxVerts;
	}
	
	/* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
	mp = CDDM_get_polys(result) + maxPolys;
	ml = CDDM_get_loops(result);
	for (i = 0; i < maxPolys; i++, mp++) {
		MLoop *ml2;
		int j, e;

		/* reverse the loop, but we keep the first vertex in the face the same,
		 * to ensure that quads are split the same way as on the other side */
		DM_copy_loop_data(result, result, mp->loopstart, mp->loopstart + maxLoops, 1);
		for (j = 1; j < mp->totloop; j++)
			DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j, 1);

		ml2 = ml + mp->loopstart + maxLoops;
		e = ml2[0].e;
		for (j = 0; j < mp->totloop - 1; j++) {
			ml2[j].e = ml2[j + 1].e;
		}
		ml2[mp->totloop - 1].e = e;
		
		mp->loopstart += maxLoops;
	}

	/* adjust mirrored loop vertex and edge indices */
	ml = CDDM_get_loops(result) + maxLoops;
	for (i = 0; i < maxLoops; i++, ml++) {
		ml->v += maxVerts;
		ml->e += maxEdges;
	}

	/* handle uvs,
	 * let tessface recalc handle updating the MTFace data */
	if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
		const bool do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
		const bool do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;

		const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);

		for (a = 0; a < totuv; a++) {
			MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a);
			int j = maxLoops;
			dmloopuv += j; /* second set of loops only */
			for (; j-- > 0; dmloopuv++) {
				if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
				if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
			}
		}
	}

	/* handle vgroup stuff */
	if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) {
		MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vertData, CD_MDEFORMVERT) + maxVerts;
		int *flip_map = NULL, flip_map_len = 0;

		flip_map = defgroup_flip_map(ob, &flip_map_len, false);
		
		if (flip_map) {
			for (i = 0; i < maxVerts; dvert++, i++) {
				/* merged vertices get both groups, others get flipped */
				if (do_vtargetmap && (vtargetmap[i] != -1))
					defvert_flip_merged(dvert, flip_map, flip_map_len);
				else
					defvert_flip(dvert, flip_map, flip_map_len);
			}

			MEM_freeN(flip_map);
		}
	}

	if (do_vtargetmap) {
		/* slow - so only call if one or more merge verts are found,
		 * users may leave this on and not realize there is nothing to merge - campbell */
		if (tot_vtargetmap) {
			result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap);
		}
		MEM_freeN(vtargetmap);
	}

	return result;
}
Ejemplo n.º 2
0
static bool view3d_localview_init(
        wmWindowManager *wm, wmWindow *win,
        Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx,
        ReportList *reports)
{
	View3D *v3d = sa->spacedata.first;
	Base *base;
	float min[3], max[3], box[3], mid[3];
	float size = 0.0f;
	unsigned int locallay;
	bool ok = false;

	if (v3d->localvd) {
		return ok;
	}

	INIT_MINMAX(min, max);

	locallay = free_localbit(bmain);

	if (locallay == 0) {
		BKE_report(reports, RPT_ERROR, "No more than 8 local views");
		ok = false;
	}
	else {
		if (scene->obedit) {
			BKE_object_minmax(scene->obedit, min, max, false);
			
			ok = true;
		
			BASACT->lay |= locallay;
			scene->obedit->lay = BASACT->lay;
		}
		else {
			for (base = FIRSTBASE; base; base = base->next) {
				if (TESTBASE(v3d, base)) {
					BKE_object_minmax(base->object, min, max, false);
					base->lay |= locallay;
					base->object->lay = base->lay;
					ok = true;
				}
			}
		}

		sub_v3_v3v3(box, max, min);
		size = max_fff(box[0], box[1], box[2]);
	}
	
	if (ok == true) {
		ARegion *ar;
		
		v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
		
		memcpy(v3d->localvd, v3d, sizeof(View3D));

		mid_v3_v3v3(mid, min, max);

		copy_v3_v3(v3d->cursor, mid);

		for (ar = sa->regionbase.first; ar; ar = ar->next) {
			if (ar->regiontype == RGN_TYPE_WINDOW) {
				RegionView3D *rv3d = ar->regiondata;
				bool ok_dist = true;

				/* new view values */
				Object *camera_old = NULL;
				float dist_new, ofs_new[3];

				rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
				memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));

				negate_v3_v3(ofs_new, mid);

				if (rv3d->persp == RV3D_CAMOB) {
					rv3d->persp = RV3D_PERSP;
					camera_old = v3d->camera;
				}

				if (rv3d->persp == RV3D_ORTHO) {
					if (size < 0.0001f) {
						ok_dist = false;
					}
				}

				if (ok_dist) {
					dist_new = ED_view3d_radius_to_dist(v3d, ar, rv3d->persp, true, (size / 2) * VIEW3D_MARGIN);
					if (rv3d->persp == RV3D_PERSP) {
						/* don't zoom closer than the near clipping plane */
						dist_new = max_ff(dist_new, v3d->near * 1.5f);
					}
				}

				ED_view3d_smooth_view_ex(
				        wm, win, sa,
				        v3d, ar, camera_old, NULL,
				        ofs_new, NULL, ok_dist ? &dist_new : NULL, NULL,
				        smooth_viewtx);
			}
		}
		
		v3d->lay = locallay;
	}
	else {
		/* clear flags */ 
		for (base = FIRSTBASE; base; base = base->next) {
			if (base->lay & locallay) {
				base->lay -= locallay;
				if (base->lay == 0) base->lay = v3d->layact;
				if (base->object != scene->obedit) base->flag |= SELECT;
				base->object->lay = base->lay;
			}
		}
	}

	return ok;
}
Ejemplo n.º 3
0
/* 0 == do center, 1 == center new, 2 == center cursor */
void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
{
	Object *obedit = scene->obedit; // XXX get from context
	EditBone *ebone;
	bArmature *arm = ob->data;
	float cent[3];

	/* Put the armature into editmode */
	if (ob != obedit) {
		ED_armature_to_edit(ob);
		obedit = NULL; /* we cant use this so behave as if there is no obedit */
	}

	/* Find the centerpoint */
	if (centermode == 2) {
		copy_v3_v3(cent, cursor);
		invert_m4_m4(ob->imat, ob->obmat);
		mul_m4_v3(ob->imat, cent);
	}
	else {
		if (around == V3D_CENTROID) {
			int total = 0;
			zero_v3(cent);
			for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
				total += 2;
				add_v3_v3(cent, ebone->head);
				add_v3_v3(cent, ebone->tail);
			}
			if (total) {
				mul_v3_fl(cent, 1.0f / (float)total);
			}
		}
		else {
			float min[3], max[3];
			INIT_MINMAX(min, max);
			for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
				minmax_v3v3_v3(min, max, ebone->head);
				minmax_v3v3_v3(min, max, ebone->tail);
			}
			mid_v3_v3v3(cent, min, max);
		}
	}
	
	/* Do the adjustments */
	for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
		sub_v3_v3(ebone->head, cent);
		sub_v3_v3(ebone->tail, cent);
	}
	
	/* Turn the list into an armature */
	if (obedit == NULL) {
		ED_armature_from_edit(ob);
		ED_armature_edit_free(ob);
	}

	/* Adjust object location for new centerpoint */
	if (centermode && obedit == NULL) {
		mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
		add_v3_v3(ob->loc, cent);
	}
}
Ejemplo n.º 4
0
static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
{
	Object *obedit = CTX_data_edit_object(C);
	Scene *scene = CTX_data_scene(C);
	View3D *v3d = CTX_wm_view3d(C);
	TransVertStore tvs = {NULL};
	TransVert *tv;
	float bmat[3][3], vec[3], min[3], max[3], centroid[3];
	int count, a;

	count = 0;
	INIT_MINMAX(min, max);
	zero_v3(centroid);

	if (obedit) {

		if (ED_transverts_check_obedit(obedit))
			ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);

		if (tvs.transverts_tot == 0) {
			return false;
		}

		copy_m3_m4(bmat, obedit->obmat);

		tv = tvs.transverts;
		for (a = 0; a < tvs.transverts_tot; a++, tv++) {
			copy_v3_v3(vec, tv->loc);
			mul_m3_v3(bmat, vec);
			add_v3_v3(vec, obedit->obmat[3]);
			add_v3_v3(centroid, vec);
			minmax_v3v3_v3(min, max, vec);
		}

		if (v3d->around == V3D_AROUND_CENTER_MEAN) {
			mul_v3_fl(centroid, 1.0f / (float)tvs.transverts_tot);
			copy_v3_v3(cursor, centroid);
		}
		else {
			mid_v3_v3v3(cursor, min, max);
		}

		ED_transverts_free(&tvs);
	}
	else {
		Object *obact = CTX_data_active_object(C);

		if (obact && (obact->mode & OB_MODE_POSE)) {
			bArmature *arm = obact->data;
			bPoseChannel *pchan;
			for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) {
				if (arm->layer & pchan->bone->layer) {
					if (pchan->bone->flag & BONE_SELECTED) {
						copy_v3_v3(vec, pchan->pose_head);
						mul_m4_v3(obact->obmat, vec);
						add_v3_v3(centroid, vec);
						minmax_v3v3_v3(min, max, vec);
						count++;
					}
				}
			}
		}
		else {
			CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
			{
				copy_v3_v3(vec, ob->obmat[3]);

				/* special case for camera -- snap to bundles */
				if (ob->type == OB_CAMERA) {
					/* snap to bundles should happen only when bundles are visible */
					if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
						bundle_midpoint(scene, ob, vec);
					}
				}

				add_v3_v3(centroid, vec);
				minmax_v3v3_v3(min, max, vec);
				count++;
			}
			CTX_DATA_END;
		}

		if (count == 0) {
			return false;
		}

		if (v3d->around == V3D_AROUND_CENTER_MEAN) {
			mul_v3_fl(centroid, 1.0f / (float)count);
			copy_v3_v3(cursor, centroid);
		}
		else {
			mid_v3_v3v3(cursor, min, max);
		}
	}
Ejemplo n.º 5
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;
}
Ejemplo n.º 6
0
static DerivedMesh *cutEdges(ExplodeModifierData *emd, DerivedMesh *dm)
{
    DerivedMesh *splitdm;
    MFace *mf = NULL, *df1 = NULL;
    MFace *mface = dm->getTessFaceArray(dm);
    MVert *dupve, *mv;
    EdgeHash *edgehash;
    EdgeHashIterator *ehi;
    int totvert = dm->getNumVerts(dm);
    int totface = dm->getNumTessFaces(dm);

    int *facesplit = MEM_callocN(sizeof(int) * totface, "explode_facesplit");
    int *vertpa = MEM_callocN(sizeof(int) * totvert, "explode_vertpa2");
    int *facepa = emd->facepa;
    int *fs, totesplit = 0, totfsplit = 0, curdupface = 0;
    int i, v1, v2, v3, v4, esplit,
        v[4]  = {0, 0, 0, 0}, /* To quite gcc barking... */
                uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
    int numlayer;
    unsigned int ed_v1, ed_v2;

    edgehash = BLI_edgehash_new(__func__);

    /* recreate vertpa from facepa calculation */
    for (i = 0, mf = mface; i < totface; i++, mf++) {
        vertpa[mf->v1] = facepa[i];
        vertpa[mf->v2] = facepa[i];
        vertpa[mf->v3] = facepa[i];
        if (mf->v4)
            vertpa[mf->v4] = facepa[i];
    }

    /* mark edges for splitting and how to split faces */
    for (i = 0, mf = mface, fs = facesplit; i < totface; i++, mf++, fs++) {
        v1 = vertpa[mf->v1];
        v2 = vertpa[mf->v2];
        v3 = vertpa[mf->v3];

        if (v1 != v2) {
            BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, NULL);
            (*fs) |= 1;
        }

        if (v2 != v3) {
            BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, NULL);
            (*fs) |= 2;
        }

        if (mf->v4) {
            v4 = vertpa[mf->v4];

            if (v3 != v4) {
                BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, NULL);
                (*fs) |= 4;
            }

            if (v1 != v4) {
                BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, NULL);
                (*fs) |= 8;
            }

            /* mark center vertex as a fake edge split */
            if (*fs == 15)
                BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
        }
        else {
            (*fs) |= 16; /* mark face as tri */

            if (v1 != v3) {
                BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, NULL);
                (*fs) |= 4;
            }
        }
    }

    /* count splits & create indexes for new verts */
    ehi = BLI_edgehashIterator_new(edgehash);
    totesplit = totvert;
    for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
        BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(totesplit));
        totesplit++;
    }
    BLI_edgehashIterator_free(ehi);

    /* count new faces due to splitting */
    for (i = 0, fs = facesplit; i < totface; i++, fs++)
        totfsplit += add_faces[*fs];

    splitdm = CDDM_from_template_ex(
                  dm, totesplit, 0, totface + totfsplit, 0, 0,
                  CD_MASK_DERIVEDMESH | CD_MASK_FACECORNERS);
    numlayer = CustomData_number_of_layers(&splitdm->faceData, CD_MTFACE);

    /* copy new faces & verts (is it really this painful with custom data??) */
    for (i = 0; i < totvert; i++) {
        MVert source;
        MVert *dest;
        dm->getVert(dm, i, &source);
        dest = CDDM_get_vert(splitdm, i);

        DM_copy_vert_data(dm, splitdm, i, i, 1);
        *dest = source;
    }

    /* override original facepa (original pointer is saved in caller function) */

    /* BMESH_TODO, (totfsplit * 2) over allocation is used since the quads are
     * later interpreted as tri's, for this to work right I think we probably
     * have to stop using tessface - campbell */

    facepa = MEM_callocN(sizeof(int) * (totface + (totfsplit * 2)), "explode_facepa");
    //memcpy(facepa, emd->facepa, totface*sizeof(int));
    emd->facepa = facepa;

    /* create new verts */
    ehi = BLI_edgehashIterator_new(edgehash);
    for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
        BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
        esplit = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
        mv = CDDM_get_vert(splitdm, ed_v2);
        dupve = CDDM_get_vert(splitdm, esplit);

        DM_copy_vert_data(splitdm, splitdm, ed_v2, esplit, 1);

        *dupve = *mv;

        mv = CDDM_get_vert(splitdm, ed_v1);

        mid_v3_v3v3(dupve->co, dupve->co, mv->co);
    }
    BLI_edgehashIterator_free(ehi);

    /* create new faces */
    curdupface = 0; //=totface;
    //curdupin=totesplit;
    for (i = 0, fs = facesplit; i < totface; i++, fs++) {
        mf = dm->getTessFaceData(dm, i, CD_MFACE);

        switch (*fs) {
        case 3:
        case 10:
        case 11:
        case 15:
            SET_VERTS(1, 2, 3, 4);
            break;
        case 5:
        case 6:
        case 7:
            SET_VERTS(2, 3, 4, 1);
            break;
        case 9:
        case 13:
            SET_VERTS(4, 1, 2, 3);
            break;
        case 12:
        case 14:
            SET_VERTS(3, 4, 1, 2);
            break;
        case 21:
        case 23:
            SET_VERTS(1, 2, 3, 4);
            break;
        case 19:
            SET_VERTS(2, 3, 1, 4);
            break;
        case 22:
            SET_VERTS(3, 1, 2, 4);
            break;
        }

        switch (*fs) {
        case 3:
        case 6:
        case 9:
        case 12:
            remap_faces_3_6_9_12(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
            if (numlayer)
                remap_uvs_3_6_9_12(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
            break;
        case 5:
        case 10:
            remap_faces_5_10(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
            if (numlayer)
                remap_uvs_5_10(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
            break;
        case 15:
            remap_faces_15(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
            if (numlayer)
                remap_uvs_15(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
            break;
        case 7:
        case 11:
        case 13:
        case 14:
            remap_faces_7_11_13_14(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2], v[3]);
            if (numlayer)
                remap_uvs_7_11_13_14(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2], uv[3]);
            break;
        case 19:
        case 21:
        case 22:
            remap_faces_19_21_22(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
            if (numlayer)
                remap_uvs_19_21_22(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
            break;
        case 23:
            remap_faces_23(dm, splitdm, mf, facepa, vertpa, i, edgehash, curdupface, v[0], v[1], v[2]);
            if (numlayer)
                remap_uvs_23(dm, splitdm, numlayer, i, curdupface, uv[0], uv[1], uv[2]);
            break;
        case 0:
        case 16:
            df1 = get_dface(dm, splitdm, curdupface, i, mf);
            facepa[curdupface] = vertpa[mf->v1];

            if (df1->v4)
                df1->flag |= ME_FACE_SEL;
            else
                df1->flag &= ~ME_FACE_SEL;
            break;
        }

        curdupface += add_faces[*fs] + 1;
    }

    for (i = 0; i < curdupface; i++) {
        mf = CDDM_get_tessface(splitdm, i);
        test_index_face(mf, &splitdm->faceData, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
    }

    BLI_edgehash_free(edgehash, NULL);
    MEM_freeN(facesplit);
    MEM_freeN(vertpa);

    CDDM_calc_edges_tessface(splitdm);
    CDDM_tessfaces_to_faces(splitdm); /*builds ngon faces from tess (mface) faces*/

    return splitdm;
}
Ejemplo n.º 7
0
/* calculates offset for co, based on fractal, sphere or smooth settings  */
static void alter_co(
        BMVert *v, BMEdge *UNUSED(e_orig),
        const SubDParams *params, const float perc,
        const BMVert *v_a, const BMVert *v_b)
{
	float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
	int i;

	copy_v3_v3(co, v->co);

	if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
		normalize_v3(co);
		mul_v3_fl(co, params->smooth);
	}
	else if (params->use_smooth) {
		/* calculating twice and blending gives smoother results,
		 * removing visible seams. */
#define USE_SPHERE_DUAL_BLEND

		const float eps_unit_vec = 1e-5f;
		float smooth;
		float no_dir[3];

#ifdef USE_SPHERE_DUAL_BLEND
		float no_reflect[3], co_a[3], co_b[3];
#endif

		sub_v3_v3v3(no_dir, v_a->co, v_b->co);
		normalize_v3(no_dir);

#ifndef USE_SPHERE_DUAL_BLEND
		if (len_squared_v3v3(v_a->no, v_b->no) < eps_unit_vec) {
			interp_v3_v3v3(co, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, v_b->no, no_dir, perc, co);
		}
#else
		/* sphere-a */
		reflect_v3_v3v3(no_reflect, v_a->no, no_dir);
		if (len_squared_v3v3(v_a->no, no_reflect) < eps_unit_vec) {
			interp_v3_v3v3(co_a, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, v_a->no, v_b->co, no_reflect, no_dir, perc, co_a);
		}

		/* sphere-b */
		reflect_v3_v3v3(no_reflect, v_b->no, no_dir);
		if (len_squared_v3v3(v_b->no, no_reflect) < eps_unit_vec) {
			interp_v3_v3v3(co_b, v_a->co, v_b->co, perc);
		}
		else {
			interp_slerp_co_no_v3(v_a->co, no_reflect, v_b->co, v_b->no, no_dir, perc, co_b);
		}

		/* blend both spheres */
		interp_v3_v3v3(co, co_a, co_b, perc);
#endif  /* USE_SPHERE_DUAL_BLEND */

		/* apply falloff */
		if (params->smooth_falloff == SUBD_FALLOFF_LIN) {
			smooth = 1.0f;
		}
		else {
			smooth = fabsf(1.0f - 2.0f * fabsf(0.5f - perc));
			smooth = 1.0f + bmesh_subd_falloff_calc(params->smooth_falloff, smooth);
		}

		if (params->use_smooth_even) {
			smooth *= shell_v3v3_mid_normalized_to_dist(v_a->no, v_b->no);
		}

		smooth *= params->smooth;
		if (smooth != 1.0f) {
			float co_flat[3];
			interp_v3_v3v3(co_flat, v_a->co, v_b->co, perc);
			interp_v3_v3v3(co, co_flat, co, smooth);
		}

#undef USE_SPHERE_DUAL_BLEND
	}

	if (params->use_fractal) {
		float normal[3], co2[3], base1[3], base2[3], tvec[3];
		const float len = len_v3v3(v_a->co, v_b->co);
		float fac;

		fac = params->fractal * len;

		mid_v3_v3v3(normal, v_a->no, v_b->no);
		ortho_basis_v3v3_v3(base1, base2, normal);

		add_v3_v3v3(co2, v->co, params->fractal_ofs);
		mul_v3_fl(co2, 10.0f);

		tvec[0] = fac * (BLI_gTurbulence(1.0, co2[0], co2[1], co2[2], 15, 0, 2) - 0.5f);
		tvec[1] = fac * (BLI_gTurbulence(1.0, co2[1], co2[0], co2[2], 15, 0, 2) - 0.5f);
		tvec[2] = fac * (BLI_gTurbulence(1.0, co2[1], co2[2], co2[0], 15, 0, 2) - 0.5f);

		/* add displacement */
		madd_v3_v3fl(co, normal, tvec[0]);
		madd_v3_v3fl(co, base1, tvec[1] * (1.0f - params->along_normal));
		madd_v3_v3fl(co, base2, tvec[2] * (1.0f - params->along_normal));
	}

	/* apply the new difference to the rest of the shape keys,
	 * note that this doesn't take rotations into account, we _could_ support
	 * this by getting the normals and coords for each shape key and
	 * re-calculate the smooth value for each but this is quite involved.
	 * for now its ok to simply apply the difference IMHO - campbell */

	if (params->shape_info.totlayer > 1) {
		float tvec[3];

		sub_v3_v3v3(tvec, v->co, co);

		/* skip the last layer since its the temp */
		i = params->shape_info.totlayer - 1;
		co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset);
		while (i--) {
			BLI_assert(co != BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp));
			sub_v3_v3(co += 3, tvec);
		}
	}
}
Ejemplo n.º 8
0
/**
 * Specialized slerp that uses a sphere defined by each points normal.
 */
static void interp_slerp_co_no_v3(
        const float co_a[3], const float no_a[3],
        const float co_b[3], const float no_b[3],
        const float no_dir[3],  /* caller already knows, avoid normalize */
        float fac,
        float r_co[3])
{
	/* center of the sphere defined by both normals */
	float center[3];

	BLI_assert(len_squared_v3v3(no_a, no_b) != 0);

	/* calculate sphere 'center' */
	{
		/* use point on plane to */
		float plane_a[4], plane_b[4], plane_c[4];
		float no_mid[3], no_ortho[3];
		/* pass this as an arg instead */
#if 0
		float no_dir[3];
#endif

		float v_a_no_ortho[3], v_b_no_ortho[3];

		add_v3_v3v3(no_mid, no_a, no_b);
		normalize_v3(no_mid);

#if 0
		sub_v3_v3v3(no_dir, co_a, co_b);
		normalize_v3(no_dir);
#endif

		/* axis of slerp */
		cross_v3_v3v3(no_ortho, no_mid, no_dir);
		normalize_v3(no_ortho);

		/* create planes */
		cross_v3_v3v3(v_a_no_ortho, no_ortho, no_a);
		cross_v3_v3v3(v_b_no_ortho, no_ortho, no_b);
		project_v3_plane(v_a_no_ortho, no_ortho, v_a_no_ortho);
		project_v3_plane(v_b_no_ortho, no_ortho, v_b_no_ortho);

		plane_from_point_normal_v3(plane_a, co_a, v_a_no_ortho);
		plane_from_point_normal_v3(plane_b, co_b, v_b_no_ortho);
		plane_from_point_normal_v3(plane_c, co_b, no_ortho);

		/* find the sphere center from 3 planes */
		if (isect_plane_plane_plane_v3(plane_a, plane_b, plane_c, center)) {
			/* pass */
		}
		else {
			mid_v3_v3v3(center, co_a, co_b);
		}
	}

	/* calculate the final output 'r_co' */
	{
		float ofs_a[3], ofs_b[3], ofs_slerp[3];
		float dist_a, dist_b;

		sub_v3_v3v3(ofs_a, co_a, center);
		sub_v3_v3v3(ofs_b, co_b, center);

		dist_a = normalize_v3(ofs_a);
		dist_b = normalize_v3(ofs_b);

		if (interp_v3_v3v3_slerp(ofs_slerp, ofs_a, ofs_b, fac)) {
			madd_v3_v3v3fl(r_co, center, ofs_slerp, interpf(dist_b, dist_a, fac));
		}
		else {
			interp_v3_v3v3(r_co, co_a, co_b, fac);
		}
	}
}
Ejemplo n.º 9
0
static bool view3d_localview_init(Main *bmain, Scene *scene, ScrArea *sa, ReportList *reports)
{
	View3D *v3d = sa->spacedata.first;
	Base *base;
	float min[3], max[3], box[3];
	float size = 0.0f, size_persp = 0.0f, size_ortho = 0.0f;
	unsigned int locallay;
	bool ok = false;

	if (v3d->localvd) {
		return ok;
	}

	INIT_MINMAX(min, max);

	locallay = free_localbit(bmain);

	if (locallay == 0) {
		BKE_report(reports, RPT_ERROR, "No more than 8 local views");
		ok = false;
	}
	else {
		if (scene->obedit) {
			BKE_object_minmax(scene->obedit, min, max, false);
			
			ok = true;
		
			BASACT->lay |= locallay;
			scene->obedit->lay = BASACT->lay;
		}
		else {
			for (base = FIRSTBASE; base; base = base->next) {
				if (TESTBASE(v3d, base)) {
					BKE_object_minmax(base->object, min, max, false);
					base->lay |= locallay;
					base->object->lay = base->lay;
					ok = true;
				}
			}
		}

		sub_v3_v3v3(box, max, min);
		size = max_fff(box[0], box[1], box[2]);

		/* do not zoom closer than the near clipping plane */
		size = max_ff(size, v3d->near * 1.5f);

		/* perspective size (we always switch out of camera view so no need to use its lens size) */
		size_persp = ED_view3d_radius_to_persp_dist(focallength_to_fov(v3d->lens, DEFAULT_SENSOR_WIDTH), size / 2.0f) * VIEW3D_MARGIN;
		size_ortho = ED_view3d_radius_to_ortho_dist(v3d->lens, size / 2.0f) * VIEW3D_MARGIN;
	}
	
	if (ok == true) {
		ARegion *ar;
		
		v3d->localvd = MEM_mallocN(sizeof(View3D), "localview");
		
		memcpy(v3d->localvd, v3d, sizeof(View3D));

		for (ar = sa->regionbase.first; ar; ar = ar->next) {
			if (ar->regiontype == RGN_TYPE_WINDOW) {
				RegionView3D *rv3d = ar->regiondata;

				rv3d->localvd = MEM_mallocN(sizeof(RegionView3D), "localview region");
				memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
				
				mid_v3_v3v3(v3d->cursor, min, max);
				negate_v3_v3(rv3d->ofs, v3d->cursor);

				if (rv3d->persp == RV3D_CAMOB) {
					rv3d->persp = RV3D_PERSP;
				}

				/* perspective should be a bit farther away to look nice */
				if (rv3d->persp != RV3D_ORTHO) {
					rv3d->dist = size_persp;
				}
				else {
					rv3d->dist = size_ortho;
				}

				/* correction for window aspect ratio */
				if (ar->winy > 2 && ar->winx > 2) {
					float asp = (float)ar->winx / (float)ar->winy;
					if (asp < 1.0f) asp = 1.0f / asp;
					rv3d->dist *= asp;
				}
			}
		}
		
		v3d->lay = locallay;
	}
	else {
		/* clear flags */ 
		for (base = FIRSTBASE; base; base = base->next) {
			if (base->lay & locallay) {
				base->lay -= locallay;
				if (base->lay == 0) base->lay = v3d->layact;
				if (base->object != scene->obedit) base->flag |= SELECT;
				base->object->lay = base->lay;
			}
		}
	}

	return ok;
}