Exemple #1
0
/* result written in vec and mat */
void curve_deform_vector(Scene *scene, Object *cuOb, Object *target,
                         float orco[3], float vec[3], float mat[][3], int no_rot_axis)
{
	CurveDeform cd;
	float quat[4];
	
	if (cuOb->type != OB_CURVE) {
		unit_m3(mat);
		return;
	}

	init_curve_deform(cuOb, target, &cd);
	cd.no_rot_axis = no_rot_axis;                /* option to only rotate for XY, for example */
	
	copy_v3_v3(cd.dmin, orco);
	copy_v3_v3(cd.dmax, orco);

	mul_m4_v3(cd.curvespace, vec);
	
	if (calc_curve_deform(scene, cuOb, vec, target->trackflag, &cd, quat)) {
		float qmat[3][3];
		
		quat_to_mat3(qmat, quat);
		mul_m3_m3m3(mat, qmat, cd.objectspace3);
	}
	else
		unit_m3(mat);
	
	mul_m4_v3(cd.objectspace, vec);

}
Exemple #2
0
void crazyspace_build_sculpt(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
{
	int totleft= sculpt_get_first_deform_matrices(scene, ob, deformmats, deformcos);

	if(totleft) {
		/* there are deformation modifier which doesn't support deformation matricies
		   calculation. Need additional crazyspace correction */

		float (*deformedVerts)[3]= *deformcos;
		float (*origVerts)[3]= MEM_dupallocN(deformedVerts);
		float *quats= NULL;
		int i, deformed= 0;
		ModifierData *md= modifiers_getVirtualModifierList(ob);
		Mesh *me= (Mesh*)ob->data;

		for(; md; md= md->next) {
			ModifierTypeInfo *mti= modifierType_getInfo(md->type);

			if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;

			if(mti->type==eModifierTypeType_OnlyDeform) {
				/* skip leading modifiers which have been already
				   handled in sculpt_get_first_deform_matrices */
				if(mti->deformMatrices && !deformed)
					continue;

				mti->deformVerts(md, ob, NULL, deformedVerts, me->totvert, 0, 0);
				deformed= 1;
			}
		}

		quats= MEM_mallocN(me->totvert*sizeof(float)*4, "crazy quats");

		crazyspace_set_quats_mesh(me, (float*)origVerts, (float*)deformedVerts, quats);

		for(i=0; i<me->totvert; i++) {
			float qmat[3][3], tmat[3][3];

			quat_to_mat3(qmat, &quats[i*4]);
			mul_m3_m3m3(tmat, qmat, (*deformmats)[i]);
			copy_m3_m3((*deformmats)[i], tmat);
		}

		MEM_freeN(origVerts);
		MEM_freeN(quats);
	}

	if(!*deformmats) {
		int a, numVerts;
		Mesh *me= (Mesh*)ob->data;

		*deformcos= mesh_getVertexCos(me, &numVerts);
		*deformmats= MEM_callocN(sizeof(*(*deformmats))*numVerts, "defmats");

		for(a=0; a<numVerts; a++)
			unit_m3((*deformmats)[a]);
	}
}
Exemple #3
0
static PyObject *Quaternion_to_matrix(QuaternionObject *self)
{
	float mat[9]; /* all values are set */

	if (BaseMath_ReadCallback(self) == -1)
		return NULL;

	quat_to_mat3((float (*)[3])mat, self->quat);
	return Matrix_CreatePyObject(mat, 3, 3, Py_NEW, NULL);
}
Exemple #4
0
static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
                                  const float no_f[3], const short no_s[3])
{
	DupliObject *dob;
	vertexDupliData *vdd= userData;
	float vec[3], q2[4], mat[3][3], tmat[4][4], obmat[4][4];
	int origlay;
	
	mul_v3_m4v3(vec, vdd->pmat, co);
	sub_v3_v3(vec, vdd->pmat[3]);
	add_v3_v3(vec, vdd->obmat[3]);
	
	copy_m4_m4(obmat, vdd->obmat);
	copy_v3_v3(obmat[3], vec);
	
	if (vdd->par->transflag & OB_DUPLIROT) {
		if (no_f) {
			vec[0]= -no_f[0]; vec[1]= -no_f[1]; vec[2]= -no_f[2];
		}
		else if (no_s) {
			vec[0]= -no_s[0]; vec[1]= -no_s[1]; vec[2]= -no_s[2];
		}
		
		vec_to_quat( q2,vec, vdd->ob->trackflag, vdd->ob->upflag);
		
		quat_to_mat3( mat,q2);
		copy_m4_m4(tmat, obmat);
		mul_m4_m4m3(obmat, tmat, mat);
	}

	origlay = vdd->ob->lay;
	
	dob= new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated);

	/* restore the original layer so that each dupli will have proper dob->origlay */
	vdd->ob->lay = origlay;

	if (vdd->orco)
		copy_v3_v3(dob->orco, vdd->orco[index]);
	
	if (vdd->ob->transflag & OB_DUPLI) {
		float tmpmat[4][4];
		copy_m4_m4(tmpmat, vdd->ob->obmat);
		copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */
		object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level+1, vdd->animated);
		copy_m4_m4(vdd->ob->obmat, tmpmat);
	}
}
Exemple #5
0
int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
{
  if (EulerObject_Check(value)) {
    if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
      return -1;
    }
    else {
      eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
      return 0;
    }
  }
  else if (QuaternionObject_Check(value)) {
    if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
      return -1;
    }
    else {
      float tquat[4];
      normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
      quat_to_mat3(rmat, tquat);
      return 0;
    }
  }
  else if (MatrixObject_Check(value)) {
    if (BaseMath_ReadCallback((BaseMathObject *)value) == -1) {
      return -1;
    }
    else if (((MatrixObject *)value)->num_row < 3 || ((MatrixObject *)value)->num_col < 3) {
      PyErr_Format(
          PyExc_ValueError, "%.200s: matrix must have minimum 3x3 dimensions", error_prefix);
      return -1;
    }
    else {
      matrix_as_3x3(rmat, (MatrixObject *)value);
      normalize_m3(rmat);
      return 0;
    }
  }
  else {
    PyErr_Format(PyExc_TypeError,
                 "%.200s: expected a Euler, Quaternion or Matrix type, "
                 "found %.200s",
                 error_prefix,
                 Py_TYPE(value)->tp_name);
    return -1;
  }
}
Exemple #6
0
/* Meta object density, brute force for now 
 * (might be good enough anyway, don't need huge number of metaobs to model volumetric objects */
static float metadensity(Object *ob, const float co[3])
{
	float mat[4][4], imat[4][4], dens = 0.f;
	MetaBall *mb = (MetaBall *)ob->data;
	MetaElem *ml;
	
	/* transform co to meta-element */
	float tco[3] = {co[0], co[1], co[2]};
	mult_m4_m4m4(mat, R.viewmat, ob->obmat);
	invert_m4_m4(imat, mat);
	mul_m4_v3(imat, tco);
	
	for (ml = mb->elems.first; ml; ml = ml->next) {
		float bmat[3][3], dist2;
		
		/* element rotation transform */
		float tp[3] = {ml->x - tco[0], ml->y - tco[1], ml->z - tco[2]};
		quat_to_mat3(bmat, ml->quat);
		transpose_m3(bmat); /* rot.only, so inverse == transpose */
		mul_m3_v3(bmat, tp);

		/* MB_BALL default */
		switch (ml->type) {
			case MB_ELIPSOID:
				tp[0] /= ml->expx, tp[1] /= ml->expy, tp[2] /= ml->expz;
				break;
			case MB_CUBE:
				tp[2] = (tp[2] > ml->expz) ? (tp[2] - ml->expz) : ((tp[2] < -ml->expz) ? (tp[2] + ml->expz) : 0.f);
			/* no break, xy as plane */
			case MB_PLANE:
				tp[1] = (tp[1] > ml->expy) ? (tp[1] - ml->expy) : ((tp[1] < -ml->expy) ? (tp[1] + ml->expy) : 0.f);
			/* no break, x as tube */
			case MB_TUBE:
				tp[0] = (tp[0] > ml->expx) ? (tp[0] - ml->expx) : ((tp[0] < -ml->expx) ? (tp[0] + ml->expx) : 0.f);
		}

		/* ml->rad2 is not set */
		dist2 = 1.0f - (dot_v3v3(tp, tp) / (ml->rad * ml->rad));
		if (dist2 > 0.f)
			dens += (ml->flag & MB_NEGATIVE) ? -ml->s * dist2 * dist2 * dist2 : ml->s * dist2 * dist2 * dist2;
	}
	
	dens -= mb->thresh;
	return (dens < 0.f) ? 0.f : dens;
}
Exemple #7
0
static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
{
	float tquat[4];
	float eul[3];
	const char *order_str = NULL;
	short order = EULER_ORDER_XYZ;
	EulerObject *eul_compat = NULL;

	if (!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
		return NULL;

	if (BaseMath_ReadCallback(self) == -1)
		return NULL;

	if (order_str) {
		order = euler_order_from_string(order_str, "Matrix.to_euler()");

		if (order == -1)
			return NULL;
	}

	normalize_qt_qt(tquat, self->quat);

	if (eul_compat) {
		float mat[3][3];

		if (BaseMath_ReadCallback(eul_compat) == -1)
			return NULL;

		quat_to_mat3(mat, tquat);

		if (order == EULER_ORDER_XYZ)  mat3_to_compatible_eul(eul, eul_compat->eul, mat);
		else                           mat3_to_compatible_eulO(eul, eul_compat->eul, order, mat);
	}
	else {
		if (order == EULER_ORDER_XYZ)  quat_to_eul(eul, tquat);
		else                           quat_to_eulO(eul, order, tquat);
	}

	return Euler_CreatePyObject(eul, order, Py_NEW, NULL);
}
Exemple #8
0
static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
{
	float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
	float tquat[4], length;

	if (BaseMath_ReadCallback(self) == -1)
		return NULL;

	if (mathutils_any_to_rotmat(other_rmat, value, "Quaternion.rotate(value)") == -1)
		return NULL;

	length = normalize_qt_qt(tquat, self->quat);
	quat_to_mat3(self_rmat, tquat);
	mul_m3_m3m3(rmat, other_rmat, self_rmat);

	mat3_to_quat(self->quat, rmat);
	mul_qt_fl(self->quat, length); /* maintain length after rotating */

	(void)BaseMath_WriteCallback(self);
	Py_RETURN_NONE;
}
/* called from within the core BKE_pose_where_is loop, all animsystems and constraints
 * were executed & assigned. Now as last we do an IK pass */
static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
{
	float R_parmat[3][3], identity[3][3];
	float iR_parmat[3][3];
	float R_bonemat[3][3];
	float goalrot[3][3], goalpos[3];
	float rootmat[4][4], imat[4][4];
	float goal[4][4], goalinv[4][4];
	float irest_basis[3][3], full_basis[3][3];
	float end_pose[4][4], world_pose[4][4];
	float length, basis[3][3], rest_basis[3][3], start[3], *ikstretch = NULL;
	float resultinf = 0.0f;
	int a, flag, hasstretch = 0, resultblend = 0;
	bPoseChannel *pchan;
	IK_Segment *seg, *parent, **iktree, *iktarget;
	IK_Solver *solver;
	PoseTarget *target;
	bKinematicConstraint *data, *poleangledata = NULL;
	Bone *bone;

	if (tree->totchannel == 0)
		return;

	iktree = MEM_mallocN(sizeof(void *) * tree->totchannel, "ik tree");

	for (a = 0; a < tree->totchannel; a++) {
		pchan = tree->pchan[a];
		bone = pchan->bone;

		/* set DoF flag */
		flag = 0;
		if (!(pchan->ikflag & BONE_IK_NO_XDOF) && !(pchan->ikflag & BONE_IK_NO_XDOF_TEMP))
			flag |= IK_XDOF;
		if (!(pchan->ikflag & BONE_IK_NO_YDOF) && !(pchan->ikflag & BONE_IK_NO_YDOF_TEMP))
			flag |= IK_YDOF;
		if (!(pchan->ikflag & BONE_IK_NO_ZDOF) && !(pchan->ikflag & BONE_IK_NO_ZDOF_TEMP))
			flag |= IK_ZDOF;

		if (tree->stretch && (pchan->ikstretch > 0.0f)) {
			flag |= IK_TRANS_YDOF;
			hasstretch = 1;
		}

		seg = iktree[a] = IK_CreateSegment(flag);

		/* find parent */
		if (a == 0)
			parent = NULL;
		else
			parent = iktree[tree->parent[a]];

		IK_SetParent(seg, parent);

		/* get the matrix that transforms from prevbone into this bone */
		copy_m3_m4(R_bonemat, pchan->pose_mat);

		/* gather transformations for this IK segment */

		if (pchan->parent)
			copy_m3_m4(R_parmat, pchan->parent->pose_mat);
		else
			unit_m3(R_parmat);

		/* bone offset */
		if (pchan->parent && (a > 0))
			sub_v3_v3v3(start, pchan->pose_head, pchan->parent->pose_tail);
		else
			/* only root bone (a = 0) has no parent */
			start[0] = start[1] = start[2] = 0.0f;

		/* change length based on bone size */
		length = bone->length * len_v3(R_bonemat[1]);

		/* compute rest basis and its inverse */
		copy_m3_m3(rest_basis, bone->bone_mat);
		copy_m3_m3(irest_basis, bone->bone_mat);
		transpose_m3(irest_basis);

		/* compute basis with rest_basis removed */
		invert_m3_m3(iR_parmat, R_parmat);
		mul_m3_m3m3(full_basis, iR_parmat, R_bonemat);
		mul_m3_m3m3(basis, irest_basis, full_basis);

		/* basis must be pure rotation */
		normalize_m3(basis);

		/* transform offset into local bone space */
		normalize_m3(iR_parmat);
		mul_m3_v3(iR_parmat, start);

		IK_SetTransform(seg, start, rest_basis, basis, length);

		if (pchan->ikflag & BONE_IK_XLIMIT)
			IK_SetLimit(seg, IK_X, pchan->limitmin[0], pchan->limitmax[0]);
		if (pchan->ikflag & BONE_IK_YLIMIT)
			IK_SetLimit(seg, IK_Y, pchan->limitmin[1], pchan->limitmax[1]);
		if (pchan->ikflag & BONE_IK_ZLIMIT)
			IK_SetLimit(seg, IK_Z, pchan->limitmin[2], pchan->limitmax[2]);

		IK_SetStiffness(seg, IK_X, pchan->stiffness[0]);
		IK_SetStiffness(seg, IK_Y, pchan->stiffness[1]);
		IK_SetStiffness(seg, IK_Z, pchan->stiffness[2]);

		if (tree->stretch && (pchan->ikstretch > 0.0f)) {
			const float ikstretch = pchan->ikstretch * pchan->ikstretch;
			/* this function does its own clamping */
			IK_SetStiffness(seg, IK_TRANS_Y, 1.0f - ikstretch);
			IK_SetLimit(seg, IK_TRANS_Y, IK_STRETCH_STIFF_MIN, IK_STRETCH_STIFF_MAX);
		}
	}

	solver = IK_CreateSolver(iktree[0]);

	/* set solver goals */

	/* first set the goal inverse transform, assuming the root of tree was done ok! */
	pchan = tree->pchan[0];
	if (pchan->parent) {
		/* transform goal by parent mat, so this rotation is not part of the
		 * segment's basis. otherwise rotation limits do not work on the
		 * local transform of the segment itself. */
		copy_m4_m4(rootmat, pchan->parent->pose_mat);
		/* However, we do not want to get (i.e. reverse) parent's scale, as it generates [#31008]
		 * kind of nasty bugs... */
		normalize_m4(rootmat);
	}
	else
		unit_m4(rootmat);
	copy_v3_v3(rootmat[3], pchan->pose_head);

	mul_m4_m4m4(imat, ob->obmat, rootmat);
	invert_m4_m4(goalinv, imat);

	for (target = tree->targets.first; target; target = target->next) {
		float polepos[3];
		int poleconstrain = 0;

		data = (bKinematicConstraint *)target->con->data;

		/* 1.0=ctime, we pass on object for auto-ik (owner-type here is object, even though
		 * strictly speaking, it is a posechannel)
		 */
		BKE_constraint_target_matrix_get(scene, target->con, 0, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);

		/* and set and transform goal */
		mul_m4_m4m4(goal, goalinv, rootmat);

		copy_v3_v3(goalpos, goal[3]);
		copy_m3_m4(goalrot, goal);
		normalize_m3(goalrot);

		/* same for pole vector target */
		if (data->poletar) {
			BKE_constraint_target_matrix_get(scene, target->con, 1, CONSTRAINT_OBTYPE_OBJECT, ob, rootmat, 1.0);

			if (data->flag & CONSTRAINT_IK_SETANGLE) {
				/* don't solve IK when we are setting the pole angle */
				break;
			}
			else {
				mul_m4_m4m4(goal, goalinv, rootmat);
				copy_v3_v3(polepos, goal[3]);
				poleconstrain = 1;

				/* for pole targets, we blend the result of the ik solver
				 * instead of the target position, otherwise we can't get
				 * a smooth transition */
				resultblend = 1;
				resultinf = target->con->enforce;

				if (data->flag & CONSTRAINT_IK_GETANGLE) {
					poleangledata = data;
					data->flag &= ~CONSTRAINT_IK_GETANGLE;
				}
			}
		}

		/* do we need blending? */
		if (!resultblend && target->con->enforce != 1.0f) {
			float q1[4], q2[4], q[4];
			float fac = target->con->enforce;
			float mfac = 1.0f - fac;

			pchan = tree->pchan[target->tip];

			/* end effector in world space */
			copy_m4_m4(end_pose, pchan->pose_mat);
			copy_v3_v3(end_pose[3], pchan->pose_tail);
			mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL);

			/* blend position */
			goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0];
			goalpos[1] = fac * goalpos[1] + mfac * world_pose[3][1];
			goalpos[2] = fac * goalpos[2] + mfac * world_pose[3][2];

			/* blend rotation */
			mat3_to_quat(q1, goalrot);
			mat4_to_quat(q2, world_pose);
			interp_qt_qtqt(q, q1, q2, mfac);
			quat_to_mat3(goalrot, q);
		}

		iktarget = iktree[target->tip];

		if ((data->flag & CONSTRAINT_IK_POS) && data->weight != 0.0f) {
			if (poleconstrain)
				IK_SolverSetPoleVectorConstraint(solver, iktarget, goalpos,
				                                 polepos, data->poleangle, (poleangledata == data));
			IK_SolverAddGoal(solver, iktarget, goalpos, data->weight);
		}
		if ((data->flag & CONSTRAINT_IK_ROT) && (data->orientweight != 0.0f))
			if ((data->flag & CONSTRAINT_IK_AUTO) == 0)
				IK_SolverAddGoalOrientation(solver, iktarget, goalrot,
				                            data->orientweight);
	}

	/* solve */
	IK_Solve(solver, 0.0f, tree->iterations);

	if (poleangledata)
		poleangledata->poleangle = IK_SolverGetPoleAngle(solver);

	IK_FreeSolver(solver);

	/* gather basis changes */
	tree->basis_change = MEM_mallocN(sizeof(float[3][3]) * tree->totchannel, "ik basis change");
	if (hasstretch)
		ikstretch = MEM_mallocN(sizeof(float) * tree->totchannel, "ik stretch");

	for (a = 0; a < tree->totchannel; a++) {
		IK_GetBasisChange(iktree[a], tree->basis_change[a]);

		if (hasstretch) {
			/* have to compensate for scaling received from parent */
			float parentstretch, stretch;

			pchan = tree->pchan[a];
			parentstretch = (tree->parent[a] >= 0) ? ikstretch[tree->parent[a]] : 1.0f;

			if (tree->stretch && (pchan->ikstretch > 0.0f)) {
				float trans[3], length;

				IK_GetTranslationChange(iktree[a], trans);
				length = pchan->bone->length * len_v3(pchan->pose_mat[1]);

				ikstretch[a] = (length == 0.0f) ? 1.0f : (trans[1] + length) / length;
			}
			else
				ikstretch[a] = 1.0;

			stretch = (parentstretch == 0.0f) ? 1.0f : ikstretch[a] / parentstretch;

			mul_v3_fl(tree->basis_change[a][0], stretch);
			mul_v3_fl(tree->basis_change[a][1], stretch);
			mul_v3_fl(tree->basis_change[a][2], stretch);
		}

		if (resultblend && resultinf != 1.0f) {
			unit_m3(identity);
			blend_m3_m3m3(tree->basis_change[a], identity,
			              tree->basis_change[a], resultinf);
		}

		IK_FreeSegment(iktree[a]);
	}

	MEM_freeN(iktree);
	if (ikstretch) MEM_freeN(ikstretch);
}
Exemple #10
0
static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated)
{
	Object *ob, *ob_iter;
	Base *base = NULL;
	DupliObject *dob;
	DerivedMesh *dm;
	Mesh *me= par->data;
	MLoopUV *mloopuv;
	MPoly *mpoly, *mp;
	MLoop *mloop;
	MVert *mvert;
	float pmat[4][4], imat[3][3], (*orco)[3] = NULL, w;
	int lay, oblay, totface, a;
	Scene *sce = NULL;
	Group *group = NULL;
	GroupObject *go = NULL;
	BMEditMesh *em;
	float ob__obmat[4][4]; /* needed for groups where the object matrix needs to be modified */
	
	/* simple preventing of too deep nested groups */
	if (level>MAX_DUPLI_RECUR) return;
	
	copy_m4_m4(pmat, par->obmat);
	em = me->edit_btmesh;

	if (em) {
		dm= editbmesh_get_derived_cage(scene, par, em, CD_MASK_BAREMESH);
	}
	else {
		dm = mesh_get_derived_deform(scene, par, CD_MASK_BAREMESH);
	}

	totface= dm->getNumPolys(dm);
	mpoly= dm->getPolyArray(dm);
	mloop= dm->getLoopArray(dm);
	mvert= dm->getVertArray(dm);

	if (G.rendering) {

		orco= (float(*)[3])get_mesh_orco_verts(par);
		transform_mesh_orco_verts(me, orco, me->totvert, 0);
		mloopuv= me->mloopuv;
	}
	else {
		orco= NULL;
		mloopuv= NULL;
	}
	
	/* having to loop on scene OR group objects is NOT FUN */
	if (GS(id->name) == ID_SCE) {
		sce = (Scene *)id;
		lay= sce->lay;
		base= sce->base.first;
	}
	else {
		group = (Group *)id;
		lay= group->layer;
		go = group->gobject.first;
	}
	
	/* Start looping on Scene OR Group objects */
	while (base || go) { 
		if (sce) {
			ob_iter= base->object;
			oblay = base->lay;
		}
		else {
			ob_iter= go->ob;
			oblay = ob_iter->lay;
		}
		
		if (lay & oblay && scene->obedit!=ob_iter) {
			ob=ob_iter->parent;
			while (ob) {
				if (ob==par) {
					ob = ob_iter;
	/* End Scene/Group object loop, below is generic */
					
					/* par_space_mat - only used for groups so we can modify the space dupli's are in
					 * when par_space_mat is NULL ob->obmat can be used instead of ob__obmat
					 */
					if (par_space_mat)
						mult_m4_m4m4(ob__obmat, par_space_mat, ob->obmat);
					else
						copy_m4_m4(ob__obmat, ob->obmat);
					
					copy_m3_m4(imat, ob->parentinv);
						
					/* mballs have a different dupli handling */
					if (ob->type!=OB_MBALL) ob->flag |= OB_DONE;	/* doesnt render */

					for (a=0, mp= mpoly; a<totface; a++, mp++) {
						int mv1;
						int mv2;
						int mv3;
						/* int mv4; */ /* UNUSED */
						float *v1;
						float *v2;
						float *v3;
						/* float *v4; */ /* UNUSED */
						float cent[3], quat[4], mat[3][3], mat3[3][3], tmat[4][4], obmat[4][4];
						MLoop *loopstart= mloop + mp->loopstart;

						if (mp->totloop < 3) {
							/* highly unlikely but to be safe */
							continue;
						}
						else {
							v1= mvert[(mv1= loopstart[0].v)].co;
							v2= mvert[(mv2= loopstart[1].v)].co;
							v3= mvert[(mv3= loopstart[2].v)].co;
#if 0
							if (mp->totloop > 3) {
								v4= mvert[(mv4= loopstart[3].v)].co;
							}
#endif
						}

						/* translation */
						mesh_calc_poly_center(mp, loopstart, mvert, cent);

						mul_m4_v3(pmat, cent);
						
						sub_v3_v3v3(cent, cent, pmat[3]);
						add_v3_v3(cent, ob__obmat[3]);
						
						copy_m4_m4(obmat, ob__obmat);
						
						copy_v3_v3(obmat[3], cent);
						
						/* rotation */
						tri_to_quat( quat,v1, v2, v3);
						quat_to_mat3( mat,quat);
						
						/* scale */
						if (par->transflag & OB_DUPLIFACES_SCALE) {
							float size= mesh_calc_poly_area(mp, loopstart, mvert, NULL);
							size= sqrtf(size) * par->dupfacesca;
							mul_m3_fl(mat, size);
						}
						
						copy_m3_m3(mat3, mat);
						mul_m3_m3m3(mat, imat, mat3);
						
						copy_m4_m4(tmat, obmat);
						mul_m4_m4m3(obmat, tmat, mat);
						
						dob= new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated);
						if (G.rendering) {
							w= 1.0f / (float)mp->totloop;

							if (orco) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
								}
							}

							if (mloopuv) {
								int j;
								for (j = 0; j < mpoly->totloop; j++) {
									madd_v2_v2fl(dob->orco, mloopuv[loopstart[j].v].uv, w);
								}
							}
						}
						
						if (ob->transflag & OB_DUPLI) {
							float tmpmat[4][4];
							copy_m4_m4(tmpmat, ob->obmat);
							copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */
							object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level+1, animated);
							copy_m4_m4(ob->obmat, tmpmat);
						}
					}
					
					break;
				}
				ob= ob->parent;
			}
		}
		if (sce)	base= base->next;	/* scene loop */
		else		go= go->next;		/* group loop */
	}

	if (orco)
		MEM_freeN(orco);
	
	dm->release(dm);
}
Exemple #11
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;
}
Exemple #12
0
static void make_prim(Object *obedit, int type, float mat[4][4], int tot, int seg,
		int subdiv, float dia, float depth, int ext, int fill)
{
	/*
	 * type - for the type of shape
	 * dia - the radius for cone,sphere cylinder etc.
	 * depth - 
	 * ext - extrude
	 * fill - end capping, and option to fill in circle
	 * cent[3] - center of the data. 
	 * */
	EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
	EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
	float phi, phid, vec[3];
	float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
	short a, b;
	
	EM_clear_flag_all(em, SELECT);

	phid= 2.0f*(float)M_PI/tot;
	phi= .25f*(float)M_PI;

	switch(type) {
	case PRIM_GRID: /*  grid */
		/* clear flags */
		eve= em->verts.first;
		while(eve) {
			eve->f= 0;
			eve= eve->next;
		}
		
		/* one segment first: the X axis */		
		phi = (2*dia)/(float)(tot-1);
		phid = (2*dia)/(float)(seg-1);
		for(a=tot-1;a>=0;a--) {
			vec[0] = (phi*a) - dia;
			vec[1]= - dia;
			vec[2]= 0.0f;
			eve= addvertlist(em, vec, NULL);
			eve->f= 1+2+4;
			if(a < tot -1) addedgelist(em, eve->prev, eve, NULL);
		}
		/* extrude and translate */
		vec[0]= vec[2]= 0.0;
		vec[1]= phid;
		
		for(a=0;a<seg-1;a++) {
			extrudeflag_vert(obedit, em, 2, nor, 0);	// nor unused
			translateflag(em, 2, vec);
		}
			
		/* and now do imat */
		eve= em->verts.first;
		while(eve) {
			if(eve->f & SELECT) {
				mul_m4_v3(mat,eve->co);
			}
			eve= eve->next;
		}
		recalc_editnormals(em);
		break;
			
	case PRIM_UVSPHERE: /*  UVsphere */
		
		/* clear all flags */
		eve= em->verts.first;
		while(eve) {
			eve->f= 0;
			eve= eve->next;
		}
		
		/* one segment first */
		phi= 0; 
		phid/=2;
		for(a=0; a<=tot; a++) {
			vec[0]= dia*sinf(phi);
			vec[1]= 0.0;
			vec[2]= dia*cosf(phi);
			eve= addvertlist(em, vec, NULL);
			eve->f= 1+2+4;
			if(a==0) v1= eve;
			else addedgelist(em, eve, eve->prev, NULL);
			phi+= phid;
		}
		
		/* extrude and rotate */
		phi= M_PI/seg;
		q[0]= cos(phi);
		q[3]= sin(phi);
		q[1]=q[2]= 0;
		quat_to_mat3( cmat,q);
		
		for(a=0; a<seg; a++) {
			extrudeflag_vert(obedit, em, 2, nor, 0); // nor unused
			rotateflag(em, 2, v1->co, cmat);
		}

		removedoublesflag(em, 4, 0, 0.0001);

		/* and now do imat */
		eve= em->verts.first;
		while(eve) {
			if(eve->f & SELECT) {
				mul_m4_v3(mat,eve->co);
			}
			eve= eve->next;
		}
		recalc_editnormals(em);
		break;
	case PRIM_ICOSPHERE: /* Icosphere */
		{
			EditVert *eva[12];
			EditEdge *eed;
			
			/* clear all flags */
			eve= em->verts.first;
			while(eve) {
				eve->f= 0;
				eve= eve->next;
			}
			dia/=200;
			for(a=0;a<12;a++) {
				vec[0]= dia*icovert[a][0];
				vec[1]= dia*icovert[a][1];
				vec[2]= dia*icovert[a][2];
				eva[a]= addvertlist(em, vec, NULL);
				eva[a]->f= 1+2;
			}
			for(a=0;a<20;a++) {
				EditFace *evtemp;
				v1= eva[ icoface[a][0] ];
				v2= eva[ icoface[a][1] ];
				v3= eva[ icoface[a][2] ];
				evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL);
				evtemp->e1->f = 1+2;
				evtemp->e2->f = 1+2;
				evtemp->e3->f = 1+2;
			}

			dia*=200;
			for(a=1; a<subdiv; a++) esubdivideflag(obedit, em, 2, dia, 0, B_SPHERE,1, SUBDIV_CORNER_PATH, 0);
			/* and now do imat */
			eve= em->verts.first;
			while(eve) {
				if(eve->f & 2) {
					mul_m4_v3(mat,eve->co);
				}
				eve= eve->next;
			}
			
			// Clear the flag 2 from the edges
			for(eed=em->edges.first;eed;eed=eed->next){
				if(eed->f & 2){
					   eed->f &= !2;
				}   
			}
		}
		break;
	case PRIM_MONKEY: /* Monkey */
		{
			//extern int monkeyo, monkeynv, monkeynf;
			//extern signed char monkeyf[][4];
			//extern signed char monkeyv[][3];
			EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
			int i;

			for (i=0; i<monkeynv; i++) {
				float v[3];
				v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
				tv[i]= addvertlist(em, v, NULL);
				tv[i]->f |= SELECT;
				tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL);
				tv[monkeynv+i]->f |= SELECT;
			}
			for (i=0; i<monkeynf; i++) {
				addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
				addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
			}

			MEM_freeN(tv);

			/* and now do imat */
			for(eve= em->verts.first; eve; eve= eve->next) {
				if(eve->f & SELECT) {
					mul_m4_v3(mat,eve->co);
				}
			}
			recalc_editnormals(em);
		}
		break;
	default: /* all types except grid, sphere... */
		if(type==PRIM_CONE);
		else if(ext==0) 
			depth= 0.0f;
	
		/* first vertex at 0° for circular objects */
		if( ELEM3(type, PRIM_CIRCLE,PRIM_CYLINDER,PRIM_CONE) )
			phi = 0.0f;
			
		vtop= vdown= v1= v2= 0;
		for(b=0; b<=ext; b++) {
			for(a=0; a<tot; a++) {
				
				vec[0]= dia*sinf(phi);
				vec[1]= dia*cosf(phi);
				vec[2]= b?depth:-depth;
				
				mul_m4_v3(mat, vec);
				eve= addvertlist(em, vec, NULL);
				eve->f= SELECT;
				if(a==0) {
					if(b==0) v1= eve;
					else v2= eve;
				}
				phi+=phid;
			}
		}
			
		/* center vertices */
		/* type PRIM_CONE can only have 1 one side filled
		 * if the cone has no capping, dont add vtop */
		if(type == PRIM_CONE || (fill && !ELEM(type, PRIM_PLANE, PRIM_CUBE))) {
			vec[0]= vec[1]= 0.0f;
			vec[2]= type==PRIM_CONE ? depth : -depth;
			mul_m4_v3(mat, vec);
			vdown= addvertlist(em, vec, NULL);
			if((ext || type==PRIM_CONE) && fill) {
				vec[0]= vec[1]= 0.0f;
				vec[2]= type==PRIM_CONE ? -depth : depth;
				mul_m4_v3(mat,vec);
				vtop= addvertlist(em, vec, NULL);
			}
		} else {
			vdown= v1;
			vtop= v2;
		}
		if(vtop) vtop->f= SELECT;
		if(vdown) vdown->f= SELECT;
	
		/* top and bottom face */
		if(fill || type==PRIM_CONE) {
			if(tot==4 && ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
				v3= v1->next->next;
				if(ext) v4= v2->next->next;
				
				addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL);
				if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL);
				
			}
			else {
				v3= v1;
				v4= v2;
				for(a=1; a<tot; a++) {
					addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL);
					v3= v3->next;
					if(ext && fill) {
						addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL);
						v4= v4->next;
					}
				}
				if(!ELEM(type, PRIM_PLANE, PRIM_CUBE)) {
					addfacelist(em, vdown, v3, v1, 0, NULL, NULL);
					if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL);
				}
			}
		}
		else if(type==PRIM_CIRCLE) {  /* we need edges for a circle */
			v3= v1;
			for(a=1;a<tot;a++) {
				addedgelist(em, v3, v3->next, NULL);
				v3= v3->next;
			}
			addedgelist(em, v3, v1, NULL);
		}
		/* side faces */
		if(ext) {
			v3= v1;
			v4= v2;
			for(a=1; a<tot; a++) {
				addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL);
				v3= v3->next;
				v4= v4->next;
			}
			addfacelist(em, v3, v1, v2, v4, NULL, NULL);
		}
		else if(fill && type==PRIM_CONE) {
			/* add the bottom flat area of the cone
			 * if capping is disabled dont bother */
			v3= v1;
			for(a=1; a<tot; a++) {
				addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL);
				v3= v3->next;
			}
			addfacelist(em, vtop, v1, v3, 0, NULL, NULL);
		}
	}
	
	EM_stats_update(em);
	/* simple selection flush OK, based on fact it's a single model */
	EM_select_flush(em); /* flushes vertex -> edge -> face selection */

	if(!ELEM5(type, PRIM_GRID, PRIM_PLANE, PRIM_ICOSPHERE, PRIM_UVSPHERE, PRIM_MONKEY))
		EM_recalc_normal_direction(em, FALSE, TRUE);	/* otherwise monkey has eyes in wrong direction */

	BKE_mesh_end_editmesh(obedit->data, em);
}