/* (currently used for action constraints and in rebuild_pose) */ bPoseChannel *verify_pose_channel(bPose *pose, const char *name) { bPoseChannel *chan; if (pose == NULL) return NULL; /* See if this channel exists */ chan= BLI_findstring(&pose->chanbase, name, offsetof(bPoseChannel, name)); if(chan) { return chan; } /* If not, create it and add it */ chan = MEM_callocN(sizeof(bPoseChannel), "verifyPoseChannel"); BLI_strncpy(chan->name, name, sizeof(chan->name)); /* init vars to prevent math errors */ unit_qt(chan->quat); unit_axis_angle(chan->rotAxis, &chan->rotAngle); chan->size[0] = chan->size[1] = chan->size[2] = 1.0f; chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; chan->limitmax[0]= chan->limitmax[1]= chan->limitmax[2]= 180.0f; chan->stiffness[0]= chan->stiffness[1]= chan->stiffness[2]= 0.0f; chan->ikrotweight = chan->iklinweight = 0.0f; unit_m4(chan->constinv); chan->protectflag = OB_LOCK_ROT4D; /* lock by components by default */ BLI_addtail(&pose->chanbase, chan); free_pose_channels_hash(pose); return chan; }
static void get_duplivert_transform(const float co[3], const float nor_f[3], const short nor_s[3], bool use_rotation, short axis, short upflag, float mat[4][4]) { float quat[4]; const float size[3] = {1.0f, 1.0f, 1.0f}; if (use_rotation) { float nor[3]; /* construct rotation matrix from normals */ if (nor_f) { nor[0] = -nor_f[0]; nor[1] = -nor_f[1]; nor[2] = -nor_f[2]; } else if (nor_s) { nor[0] = (float)-nor_s[0]; nor[1] = (float)-nor_s[1]; nor[2] = (float)-nor_s[2]; } vec_to_quat(quat, nor, axis, upflag); } else unit_qt(quat); loc_quat_size_to_mat4(mat, co, quat, size); }
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ void BKE_pose_rest(bPose *pose) { bPoseChannel *pchan; if (!pose) return; memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; pchan->roll1 = pchan->roll2 = 0.0f; pchan->curveInX = pchan->curveInY = 0.0f; pchan->curveOutX = pchan->curveOutY = 0.0f; pchan->scaleIn = pchan->scaleOut = 1.0f; pchan->flag &= ~(POSE_LOC | POSE_ROT | POSE_SIZE | POSE_BBONE_SHAPE); } }
/*pass Py_WRAP - if vector is a WRAPPER for data allocated by BLENDER * (i.e. it was allocated elsewhere by MEM_mallocN()) * pass Py_NEW - if vector is not a WRAPPER and managed by PYTHON * (i.e. it must be created here with PyMEM_malloc())*/ PyObject *Quaternion_CreatePyObject(float *quat, int type, PyTypeObject *base_type) { QuaternionObject *self; self = base_type ? (QuaternionObject *)base_type->tp_alloc(base_type, 0) : (QuaternionObject *)PyObject_GC_New(QuaternionObject, &quaternion_Type); if (self) { /* init callbacks as NULL */ self->cb_user = NULL; self->cb_type = self->cb_subtype = 0; if (type == Py_WRAP) { self->quat = quat; self->wrapped = Py_WRAP; } else if (type == Py_NEW) { self->quat = PyMem_Malloc(QUAT_SIZE * sizeof(float)); if (!quat) { //new empty unit_qt(self->quat); } else { copy_qt_qt(self->quat, quat); } self->wrapped = Py_NEW; } else { Py_FatalError("Quaternion(): invalid type!"); } } return (PyObject *) self; }
static PyObject *Quaternion_identity(QuaternionObject *self) { if (BaseMath_ReadCallback(self) == -1) return NULL; unit_qt(self->quat); (void)BaseMath_WriteCallback(self); Py_RETURN_NONE; }
/* most simple meta-element adding function * don't do context manipulation here (rna uses) */ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type) { MetaElem *ml = MEM_callocN(sizeof(MetaElem), "metaelem"); unit_qt(ml->quat); ml->rad = 2.0; ml->s = 2.0; ml->flag = MB_SCALE_RAD; switch (type) { case MB_BALL: ml->type = MB_BALL; ml->expx = ml->expy = ml->expz = 1.0; break; case MB_TUBE: ml->type = MB_TUBE; ml->expx = ml->expy = ml->expz = 1.0; break; case MB_PLANE: ml->type = MB_PLANE; ml->expx = ml->expy = ml->expz = 1.0; break; case MB_ELIPSOID: ml->type = MB_ELIPSOID; ml->expx = 1.2f; ml->expy = 0.8f; ml->expz = 1.0; break; case MB_CUBE: ml->type = MB_CUBE; ml->expx = ml->expy = ml->expz = 1.0; break; default: break; } BLI_addtail(&mb->elems, ml); return ml; }
/* for do_all_pose_actions, clears the pose. Now also exported for proxy and tools */ void rest_pose(bPose *pose) { bPoseChannel *pchan; if (!pose) return; memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) { zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f; pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); } }
static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent, int index) { BLI_assert(index >= 0 && index < totkeys); iter->key = keys + index; iter->index = index; iter->time = (float)index / (float)(totkeys - 1); if (parent) { iter->parent_key = parent + index; if (index > 0) mul_qt_qtqt(iter->parent_rotation, iter->parent_key->rot, parent->rot); else copy_qt_qt(iter->parent_rotation, parent->rot); } else { iter->parent_key = NULL; unit_qt(iter->parent_rotation); } }
/* clear rotation of object */ static void object_clear_rot(Object *ob) { /* clear rotations that aren't locked */ if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) { if (ob->protectflag & OB_LOCK_ROT4D) { /* perform clamping on a component by component basis */ if (ob->rotmode == ROT_MODE_AXISANGLE) { if ((ob->protectflag & OB_LOCK_ROTW) == 0) ob->rotAngle= ob->drotAngle= 0.0f; if ((ob->protectflag & OB_LOCK_ROTX) == 0) ob->rotAxis[0]= ob->drotAxis[0]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTY) == 0) ob->rotAxis[1]= ob->drotAxis[1]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTZ) == 0) ob->rotAxis[2]= ob->drotAxis[2]= 0.0f; /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2])) ob->rotAxis[1] = 1.0f; if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2])) ob->drotAxis[1]= 1.0f; } else if (ob->rotmode == ROT_MODE_QUAT) { if ((ob->protectflag & OB_LOCK_ROTW) == 0) ob->quat[0]= ob->dquat[0]= 1.0f; if ((ob->protectflag & OB_LOCK_ROTX) == 0) ob->quat[1]= ob->dquat[1]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTY) == 0) ob->quat[2]= ob->dquat[2]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTZ) == 0) ob->quat[3]= ob->dquat[3]= 0.0f; // TODO: does this quat need normalising now? } else { /* the flag may have been set for the other modes, so just ignore the extra flag... */ if ((ob->protectflag & OB_LOCK_ROTX) == 0) ob->rot[0]= ob->drot[0]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTY) == 0) ob->rot[1]= ob->drot[1]= 0.0f; if ((ob->protectflag & OB_LOCK_ROTZ) == 0) ob->rot[2]= ob->drot[2]= 0.0f; } } else { /* perform clamping using euler form (3-components) */ // FIXME: deltas are not handled for these cases yet... float eul[3], oldeul[3], quat1[4] = {0}; if (ob->rotmode == ROT_MODE_QUAT) { copy_qt_qt(quat1, ob->quat); quat_to_eul(oldeul, ob->quat); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle); } else { copy_v3_v3(oldeul, ob->rot); } eul[0]= eul[1]= eul[2]= 0.0f; if (ob->protectflag & OB_LOCK_ROTX) eul[0]= oldeul[0]; if (ob->protectflag & OB_LOCK_ROTY) eul[1]= oldeul[1]; if (ob->protectflag & OB_LOCK_ROTZ) eul[2]= oldeul[2]; if (ob->rotmode == ROT_MODE_QUAT) { eul_to_quat(ob->quat, eul); /* quaternions flip w sign to accumulate rotations correctly */ if ((quat1[0]<0.0f && ob->quat[0]>0.0f) || (quat1[0]>0.0f && ob->quat[0]<0.0f)) { mul_qt_fl(ob->quat, -1.0f); } } else if (ob->rotmode == ROT_MODE_AXISANGLE) { eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle,eul, EULER_ORDER_DEFAULT); } else { copy_v3_v3(ob->rot, eul); } } } // Duplicated in source/blender/editors/armature/editarmature.c else { if (ob->rotmode == ROT_MODE_QUAT) { unit_qt(ob->quat); unit_qt(ob->dquat); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { unit_axis_angle(ob->rotAxis, &ob->rotAngle); unit_axis_angle(ob->drotAxis, &ob->drotAngle); } else { zero_v3(ob->rot); zero_v3(ob->drot); } } }
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; int a, change = 1; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ob->type == OB_MESH) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing"); change = 0; } } else if (ob->type == OB_ARMATURE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing"); change = 0; } } else if (ob->type == OB_LATTICE) { if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user lattice, doing nothing"); change = 0; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu; if (ID_REAL_USERS(ob->data) > 1) { BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing"); change = 0; } cu = ob->data; if (!(cu->flag & CU_3D) && (apply_rot || apply_loc)) { BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing"); change = 0; } if (cu->key) { BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing"); change = 0; } } } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; change = 0; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else continue; if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); change = 1; } CTX_DATA_END; if (!change) return OPERATOR_CANCELLED; WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
int BL_ArmatureChannel::py_attr_set_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value) { BL_ArmatureChannel* self= static_cast<BL_ArmatureChannel*>(self_v); bPoseChannel* pchan = self->m_posechannel; PyObject *item; float joints[3]; float quat[4]; if (!PySequence_Check(value) || PySequence_Size(value) != 3) { PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); return PY_SET_ATTR_FAIL; } for (int i=0; i<3; i++) { item = PySequence_GetItem(value, i); /* new ref */ joints[i] = PyFloat_AsDouble(item); Py_DECREF(item); if (joints[i] == -1.0f && PyErr_Occurred()) { PyErr_SetString(PyExc_AttributeError, "expected a sequence of [3] floats"); return PY_SET_ATTR_FAIL; } } int flag = 0; if (!(pchan->ikflag & BONE_IK_NO_XDOF)) flag |= 1; if (!(pchan->ikflag & BONE_IK_NO_YDOF)) flag |= 2; if (!(pchan->ikflag & BONE_IK_NO_ZDOF)) flag |= 4; unit_qt(quat); switch (flag) { case 0: // fixed joint break; case 1: // X only joints[1] = joints[2] = 0.f; eulO_to_quat( quat,joints, EULER_ORDER_XYZ); break; case 2: // Y only joints[0] = joints[2] = 0.f; eulO_to_quat( quat,joints, EULER_ORDER_XYZ); break; case 3: // X+Y joints[2] = 0.f; eulO_to_quat( quat,joints, EULER_ORDER_ZYX); break; case 4: // Z only joints[0] = joints[1] = 0.f; eulO_to_quat( quat,joints, EULER_ORDER_XYZ); break; case 5: // X+Z // X and Z are components of an equivalent rotation axis joints[1] = 0; axis_angle_to_quat( quat,joints, len_v3(joints)); break; case 6: // Y+Z joints[0] = 0.f; eulO_to_quat( quat,joints, EULER_ORDER_XYZ); break; case 7: // X+Y+Z // equivalent axis axis_angle_to_quat( quat,joints, len_v3(joints)); break; } if (pchan->rotmode > 0) { quat_to_eulO( joints, pchan->rotmode,quat); copy_v3_v3(pchan->eul, joints); } else copy_qt_qt(pchan->quat, quat); return PY_SET_ATTR_SUCCESS; }
static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, bool apply_rot, bool apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF, OB_FONT)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (obdata->lib) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ELEM(ob->type, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { BKE_reportf(reports, RPT_ERROR, "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (cu->key) { BKE_reportf(reports, RPT_ERROR, "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ob->type == OB_FONT) { if (apply_rot || apply_loc) { BKE_reportf(reports, RPT_ERROR, "Font's can only have scale applied: \"%s\"", ob->id.name + 2); changed = false; } } } CTX_DATA_END; if (!changed) return OPERATOR_CANCELLED; changed = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat, true); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { float tmat[3][3]; /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ BKE_mesh_transform(me, mat, true); /* update normals */ BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BKE_lattice_transform(lt, mat, true); } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; BKE_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; scale = mat3_to_scale(rsmat); BKE_curve_transform_ex(cu, mat, true, scale); } else if (ob->type == OB_FONT) { Curve *cu = ob->data; int i; scale = mat3_to_scale(rsmat); for (i = 0; i < cu->totbox; i++) { TextBox *tb = &cu->tb[i]; tb->x *= scale; tb->y *= scale; tb->w *= scale; tb->h *= scale; } cu->fsize *= scale; } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. */ if (!clip) continue; if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } else if (ob->type == OB_EMPTY) { /* It's possible for empties too, even though they don't * really have obdata, since we can simply apply the maximum * scaling to the empty's drawsize. * * Core Assumptions: * 1) Most scaled empties have uniform scaling * (i.e. for visibility reasons), AND/OR * 2) Preserving non-uniform scaling is not that important, * and is something that many users would be willing to * sacrifice for having an easy way to do this. */ if ((apply_loc == false) && (apply_rot == false) && (apply_scale == true)) { float max_scale = max_fff(fabsf(ob->size[0]), fabsf(ob->size[1]), fabsf(ob->size[2])); ob->empty_drawsize *= max_scale; } } else { continue; } if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } CTX_DATA_END; if (!changed) { BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData, ModifierApplyFlag UNUSED(flag)) { DerivedMesh *dm = derivedData, *result; ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md; ParticleSimulationData sim; ParticleSystem *psys = NULL; ParticleData *pa = NULL; MPoly *mpoly, *orig_mpoly; MLoop *mloop, *orig_mloop; MVert *mvert, *orig_mvert; int totvert, totpoly, totloop /* , totedge */; int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0; int k, p, p_skip; short track = ob->trackflag % 3, trackneg, axis = pimd->axis; float max_co = 0.0, min_co = 0.0, temp_co[3]; float *size = NULL; trackneg = ((ob->trackflag > 2) ? 1 : 0); if (pimd->ob == ob) { pimd->ob = NULL; return derivedData; } if (pimd->ob) { psys = BLI_findlink(&pimd->ob->particlesystem, pimd->psys - 1); if (psys == NULL || psys->totpart == 0) return derivedData; } else { return derivedData; } if (pimd->flag & eParticleInstanceFlag_Parents) totpart += psys->totpart; if (pimd->flag & eParticleInstanceFlag_Children) { if (totpart == 0) first_particle = psys->totpart; totpart += psys->totchild; } if (totpart == 0) return derivedData; sim.scene = md->scene; sim.ob = pimd->ob; sim.psys = psys; sim.psmd = psys_get_modifier(pimd->ob, psys); if (pimd->flag & eParticleInstanceFlag_UseSize) { float *si; si = size = MEM_callocN(totpart * sizeof(float), "particle size array"); if (pimd->flag & eParticleInstanceFlag_Parents) { for (p = 0, pa = psys->particles; p < psys->totpart; p++, pa++, si++) *si = pa->size; } if (pimd->flag & eParticleInstanceFlag_Children) { ChildParticle *cpa = psys->child; for (p = 0; p < psys->totchild; p++, cpa++, si++) { *si = psys_get_child_size(psys, cpa, 0.0f, NULL); } } } totvert = dm->getNumVerts(dm); totpoly = dm->getNumPolys(dm); totloop = dm->getNumLoops(dm); /* totedge = dm->getNumEdges(dm); */ /* UNUSED */ /* count particles */ maxvert = 0; maxpoly = 0; maxloop = 0; for (p = 0; p < totpart; p++) { if (particle_skip(pimd, psys, p)) continue; maxvert += totvert; maxpoly += totpoly; maxloop += totloop; } psys->lattice_deform_data = psys_create_lattice_deform_data(&sim); if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) { float min[3], max[3]; INIT_MINMAX(min, max); dm->getMinMax(dm, min, max); min_co = min[track]; max_co = max[track]; } result = CDDM_from_template(dm, maxvert, 0, 0, maxloop, maxpoly); mvert = result->getVertArray(result); orig_mvert = dm->getVertArray(dm); mpoly = result->getPolyArray(result); orig_mpoly = dm->getPolyArray(dm); mloop = result->getLoopArray(result); orig_mloop = dm->getLoopArray(dm); for (p = 0, p_skip = 0; p < totpart; p++) { float prev_dir[3]; float frame[4]; /* frame orientation quaternion */ /* skip particle? */ if (particle_skip(pimd, psys, p)) continue; /* set vertices coordinates */ for (k = 0; k < totvert; k++) { ParticleKey state; MVert *inMV; MVert *mv = mvert + p_skip * totvert + k; inMV = orig_mvert + k; DM_copy_vert_data(dm, result, k, p_skip * totvert + k, 1); *mv = *inMV; /*change orientation based on object trackflag*/ copy_v3_v3(temp_co, mv->co); mv->co[axis] = temp_co[track]; mv->co[(axis + 1) % 3] = temp_co[(track + 1) % 3]; mv->co[(axis + 2) % 3] = temp_co[(track + 2) % 3]; /* get particle state */ if ((psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) && (pimd->flag & eParticleInstanceFlag_Path)) { float ran = 0.0f; if (pimd->random_position != 0.0f) { ran = pimd->random_position * BLI_hash_frand(psys->seed + p); } if (pimd->flag & eParticleInstanceFlag_KeepShape) { state.time = pimd->position * (1.0f - ran); } else { state.time = (mv->co[axis] - min_co) / (max_co - min_co) * pimd->position * (1.0f - ran); if (trackneg) state.time = 1.0f - state.time; mv->co[axis] = 0.0; } psys_get_particle_on_path(&sim, first_particle + p, &state, 1); normalize_v3(state.vel); /* Incrementally Rotating Frame (Bishop Frame) */ if (k == 0) { float hairmat[4][4]; float mat[3][3]; if (first_particle + p < psys->totpart) pa = psys->particles + first_particle + p; else { ChildParticle *cpa = psys->child + (p - psys->totpart); pa = psys->particles + cpa->parent; } psys_mat_hair_to_global(sim.ob, sim.psmd->dm, sim.psys->part->from, pa, hairmat); copy_m3_m4(mat, hairmat); /* to quaternion */ mat3_to_quat(frame, mat); /* note: direction is same as normal vector currently, * but best to keep this separate so the frame can be * rotated later if necessary */ copy_v3_v3(prev_dir, state.vel); } else { float rot[4]; /* incrementally rotate along bend direction */ rotation_between_vecs_to_quat(rot, prev_dir, state.vel); mul_qt_qtqt(frame, rot, frame); copy_v3_v3(prev_dir, state.vel); } copy_qt_qt(state.rot, frame); #if 0 /* Absolute Frame (Frenet Frame) */ if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) { unit_qt(state.rot); } else { float cross[3]; float temp[3] = {0.0f, 0.0f, 0.0f}; temp[axis] = 1.0f; cross_v3_v3v3(cross, temp, state.vel); /* state.vel[axis] is the only component surviving from a dot product with the axis */ axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis])); } #endif } else { state.time = -1.0; psys_get_particle_state(&sim, first_particle + p, &state, 1); } mul_qt_v3(state.rot, mv->co); if (pimd->flag & eParticleInstanceFlag_UseSize) mul_v3_fl(mv->co, size[p]); add_v3_v3(mv->co, state.co); } /* create polys and loops */ for (k = 0; k < totpoly; k++) { MPoly *inMP = orig_mpoly + k; MPoly *mp = mpoly + p_skip * totpoly + k; DM_copy_poly_data(dm, result, k, p_skip * totpoly + k, 1); *mp = *inMP; mp->loopstart += p_skip * totloop; { MLoop *inML = orig_mloop + inMP->loopstart; MLoop *ml = mloop + mp->loopstart; int j = mp->totloop; DM_copy_loop_data(dm, result, inMP->loopstart, mp->loopstart, j); for (; j; j--, ml++, inML++) { ml->v = inML->v + (p_skip * totvert); } } } p_skip++; } CDDM_calc_edges(result); if (psys->lattice_deform_data) { end_latt_deform(psys->lattice_deform_data); psys->lattice_deform_data = NULL; } if (size) MEM_freeN(size); result->dirty |= DM_DIRTY_NORMALS; return result; }
/* set the current pose as the restpose */ static int apply_armature_pose2bones_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); // must be active object, not edit-object bArmature *arm = BKE_armature_from_object(ob); bPose *pose; bPoseChannel *pchan; EditBone *curbone; /* don't check if editmode (should be done by caller) */ if (ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (BKE_object_obdata_is_libdata(ob)) { BKE_report(op->reports, RPT_ERROR, "Cannot apply pose to lib-linked armature"); /* error_libdata(); */ return OPERATOR_CANCELLED; } /* helpful warnings... */ /* TODO: add warnings to be careful about actions, applying deforms first, etc. */ if (ob->adt && ob->adt->action) BKE_report(op->reports, RPT_WARNING, "Actions on this armature will be destroyed by this new rest pose as the " "transforms stored are relative to the old rest pose"); /* Get editbones of active armature to alter */ ED_armature_to_edit(arm); /* get pose of active object and move it out of posemode */ pose = ob->pose; for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { curbone = ED_armature_bone_find_name(arm->edbo, pchan->name); /* simply copy the head/tail values from pchan over to curbone */ copy_v3_v3(curbone->head, pchan->pose_head); copy_v3_v3(curbone->tail, pchan->pose_tail); /* fix roll: * 1. find auto-calculated roll value for this bone now * 2. remove this from the 'visual' y-rotation */ { float premat[3][3], imat[3][3], pmat[3][3], tmat[3][3]; float delta[3], eul[3]; /* obtain new auto y-rotation */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, 0.0f, premat); invert_m3_m3(imat, premat); /* get pchan 'visual' matrix */ copy_m3_m4(pmat, pchan->pose_mat); /* remove auto from visual and get euler rotation */ mul_m3_m3m3(tmat, imat, pmat); mat3_to_eul(eul, tmat); /* just use this euler-y as new roll value */ curbone->roll = eul[1]; } /* clear transform values for pchan */ zero_v3(pchan->loc); zero_v3(pchan->eul); unit_qt(pchan->quat); unit_axis_angle(pchan->rotAxis, &pchan->rotAngle); pchan->size[0] = pchan->size[1] = pchan->size[2] = 1.0f; /* set anim lock */ curbone->flag |= BONE_UNKEYED; } /* convert editbones back to bones, and then free the edit-data */ ED_armature_from_edit(arm); ED_armature_edit_free(arm); /* flush positions of posebones */ BKE_pose_where_is(scene, ob); /* fix parenting of objects which are bone-parented */ applyarmature_fix_boneparents(scene, ob); /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); return OPERATOR_FINISHED; }
static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); float rsmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale; bool changed = true; /* first check if we can execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; if (ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to a multi user: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (obdata->lib) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } if (ELEM(ob->type, OB_CURVE, OB_SURF)) { ID *obdata = ob->data; Curve *cu; cu = ob->data; if (((ob->type == OB_CURVE) && !(cu->flag & CU_3D)) && (apply_rot || apply_loc)) { BKE_reportf(reports, RPT_ERROR, "Rotation/Location can't apply to a 2D curve: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } if (cu->key) { BKE_reportf(reports, RPT_ERROR, "Can't apply to a curve with shape-keys: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); changed = false; } } } CTX_DATA_END; if (!changed) return OPERATOR_CANCELLED; changed = false; /* now execute */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { /* calculate rotation/scale matrix */ if (apply_scale && apply_rot) BKE_object_to_mat3(ob, rsmat); else if (apply_scale) BKE_object_scale_to_mat3(ob, rsmat); else if (apply_rot) { float tmat[3][3], timat[3][3]; /* simple rotation matrix */ BKE_object_rot_to_mat3(ob, rsmat, TRUE); /* correct for scale, note mul_m3_m3m3 has swapped args! */ BKE_object_scale_to_mat3(ob, tmat); invert_m3_m3(timat, tmat); mul_m3_m3m3(rsmat, timat, rsmat); mul_m3_m3m3(rsmat, rsmat, tmat); } else unit_m3(rsmat); copy_m4_m3(mat, rsmat); /* calculate translation */ if (apply_loc) { copy_v3_v3(mat[3], ob->loc); if (!(apply_scale && apply_rot)) { float tmat[3][3]; /* correct for scale and rotation that is still applied */ BKE_object_to_mat3(ob, obmat); invert_m3_m3(iobmat, obmat); mul_m3_m3m3(tmat, rsmat, iobmat); mul_m3_v3(tmat, mat[3]); } } /* apply to object data */ if (ob->type == OB_MESH) { Mesh *me = ob->data; MVert *mvert; int a; if (apply_scale) multiresModifier_scale_disp(scene, ob); /* adjust data */ mvert = me->mvert; for (a = 0; a < me->totvert; a++, mvert++) mul_m4_v3(mat, mvert->co); if (me->key) { KeyBlock *kb; for (kb = me->key->block.first; kb; kb = kb->next) { float *fp = kb->data; for (a = 0; a < kb->totelem; a++, fp += 3) mul_m4_v3(mat, fp); } } /* update normals */ BKE_mesh_calc_normals(me); } else if (ob->type == OB_ARMATURE) { ED_armature_apply_transform(ob, mat); } else if (ob->type == OB_LATTICE) { Lattice *lt = ob->data; BPoint *bp = lt->def; int a = lt->pntsu * lt->pntsv * lt->pntsw; while (a--) { mul_m4_v3(mat, bp->vec); bp++; } } else if (ob->type == OB_MBALL) { MetaBall *mb = ob->data; ED_mball_transform(mb, mat); } else if (ELEM(ob->type, OB_CURVE, OB_SURF)) { Curve *cu = ob->data; Nurb *nu; BPoint *bp; BezTriple *bezt; int a; scale = mat3_to_scale(rsmat); for (nu = cu->nurb.first; nu; nu = nu->next) { if (nu->type == CU_BEZIER) { a = nu->pntsu; for (bezt = nu->bezt; a--; bezt++) { mul_m4_v3(mat, bezt->vec[0]); mul_m4_v3(mat, bezt->vec[1]); mul_m4_v3(mat, bezt->vec[2]); bezt->radius *= scale; } BKE_nurb_handles_calc(nu); } else { a = nu->pntsu * nu->pntsv; for (bp = nu->bp; a--; bp++) mul_m4_v3(mat, bp->vec); } } } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); /* applying scale on camera actually scales clip's reconstruction. * of there's clip assigned to camera nothing to do actually. */ if (!clip) continue; if (apply_scale) BKE_tracking_reconstruction_scale(&clip->tracking, ob->size); } else if (ob->type == OB_EMPTY) { /* It's possible for empties too, even though they don't * really have obdata, since we can simply apply the maximum * scaling to the empty's drawsize. * * Core Assumptions: * 1) Most scaled empties have uniform scaling * (i.e. for visibility reasons), AND/OR * 2) Preserving non-uniform scaling is not that important, * and is something that many users would be willing to * sacrifice for having an easy way to do this. */ float max_scale = MAX3(ob->size[0], ob->size[1], ob->size[2]); ob->empty_drawsize *= max_scale; } else { continue; } if (apply_loc) zero_v3(ob->loc); if (apply_scale) ob->size[0] = ob->size[1] = ob->size[2] = 1.0f; if (apply_rot) { zero_v3(ob->rot); unit_qt(ob->quat); unit_axis_angle(ob->rotAxis, &ob->rotAngle); } BKE_object_where_is_calc(scene, ob); if (ob->type == OB_ARMATURE) { BKE_pose_where_is(scene, ob); /* needed for bone parents */ } ignore_parent_tx(bmain, scene, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); changed = true; } CTX_DATA_END; if (!changed) { BKE_report(reports, RPT_WARNING, "Objects have no data to transform"); return OPERATOR_CANCELLED; } WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); return OPERATOR_FINISHED; }