/* returns standard diameter */ static float new_primitive_matrix(bContext *C, float *loc, float *rot, float primmat[][4]) { Object *obedit = CTX_data_edit_object(C); View3D *v3d = CTX_wm_view3d(C); float mat[3][3], rmat[3][3], cmat[3][3], imat[3][3]; unit_m4(primmat); eul_to_mat3(rmat, rot); invert_m3(rmat); /* inverse transform for initial rotation and object */ copy_m3_m4(mat, obedit->obmat); mul_m3_m3m3(cmat, rmat, mat); invert_m3_m3(imat, cmat); copy_m4_m3(primmat, imat); /* center */ copy_v3_v3(primmat[3], loc); sub_v3_v3(primmat[3], obedit->obmat[3]); invert_m3_m3(imat, mat); mul_m3_v3(imat, primmat[3]); return v3d ? v3d->grid : 1.0f; }
static void rigid_orthogonalize_R(float R[][3]) { HMatrix M, Q, S; copy_m4_m3(M, R); polar_decomp(M, Q, S); copy_m3_m4(R, Q); }
void ED_armature_ebone_to_mat4(EditBone *ebone, float mat[4][4]) { float m3[3][3]; ED_armature_ebone_to_mat3(ebone, m3); copy_m4_m3(mat, m3); copy_v3_v3(mat[3], ebone->head); }
static void rna_EditBone_matrix_get(PointerRNA *ptr, float *values) { EditBone *ebone = (EditBone *)(ptr->data); float delta[3], tmat[3][3], mat[4][4]; /* Find the current bone matrix */ sub_v3_v3v3(delta, ebone->tail, ebone->head); vec_roll_to_mat3(delta, ebone->roll, tmat); copy_m4_m3(mat, tmat); copy_v3_v3(mat[3], ebone->head); memcpy(values, mat, 16 * sizeof(float)); }
static void camera_frame_fit_data_init( const Scene *scene, const Object *ob, CameraParams *params, CameraViewFrameData *data) { float camera_rotmat_transposed_inversed[4][4]; unsigned int i; /* setup parameters */ BKE_camera_params_init(params); BKE_camera_params_from_object(params, ob); /* compute matrix, viewplane, .. */ if (scene) { BKE_camera_params_compute_viewplane(params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); } else { BKE_camera_params_compute_viewplane(params, 1, 1, 1.0f, 1.0f); } BKE_camera_params_compute_matrix(params); /* initialize callback data */ copy_m3_m4(data->camera_rotmat, (float (*)[4])ob->obmat); normalize_m3(data->camera_rotmat); /* To transform a plane which is in its homogeneous representation (4d vector), * we need the inverse of the transpose of the transform matrix... */ copy_m4_m3(camera_rotmat_transposed_inversed, data->camera_rotmat); transpose_m4(camera_rotmat_transposed_inversed); invert_m4(camera_rotmat_transposed_inversed); /* Extract frustum planes from projection matrix. */ planes_from_projmat(params->winmat, /* left right top bottom near far */ data->plane_tx[2], data->plane_tx[0], data->plane_tx[3], data->plane_tx[1], NULL, NULL); /* Rotate planes and get normals from them */ for (i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) { mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]); normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]); } copy_v4_fl(data->dist_vals_sq, FLT_MAX); data->tot = 0; data->is_ortho = params->is_ortho; if (params->is_ortho) { /* we want (0, 0, -1) transformed by camera_rotmat, this is a quicker shortcut. */ negate_v3_v3(data->camera_no, data->camera_rotmat[2]); data->dist_to_cam = FLT_MAX; } }
void init_mapping(TexMapping *texmap) { float eul[3], smat[3][3], rmat[3][3], mat[3][3]; size_to_mat3( smat,texmap->size); eul[0]= DEG2RADF(texmap->rot[0]); eul[1]= DEG2RADF(texmap->rot[1]); eul[2]= DEG2RADF(texmap->rot[2]); eul_to_mat3( rmat,eul); mul_m3_m3m3(mat, rmat, smat); copy_m4_m3(texmap->mat, mat); VECCOPY(texmap->mat[3], texmap->loc); }
/* to make this work, the diffmats have to be precalculated! Stored in chan_mat */ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr = to detect if this is first bone { float vec[3], ikmat[4][4]; copy_m4_m3(ikmat, ik_mat); if (pchan->parent) mul_serie_m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL); else mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat); /* calculate head */ copy_v3_v3(pchan->pose_head, pchan->pose_mat[3]); /* calculate tail */ copy_v3_v3(vec, pchan->pose_mat[1]); mul_v3_fl(vec, pchan->bone->length); add_v3_v3v3(pchan->pose_tail, pchan->pose_head, vec); pchan->flag |= POSE_DONE; }
void init_tex_mapping(TexMapping *texmap) { float smat[3][3], rmat[3][3], mat[3][3], proj[3][3]; if (texmap->projx == PROJ_X && texmap->projy == PROJ_Y && texmap->projz == PROJ_Z && is_zero_v3(texmap->loc) && is_zero_v3(texmap->rot) && is_one_v3(texmap->size)) { unit_m4(texmap->mat); texmap->flag |= TEXMAP_UNIT_MATRIX; } else { /* axis projection */ zero_m3(proj); if (texmap->projx != PROJ_N) proj[texmap->projx - 1][0] = 1.0f; if (texmap->projy != PROJ_N) proj[texmap->projy - 1][1] = 1.0f; if (texmap->projz != PROJ_N) proj[texmap->projz - 1][2] = 1.0f; /* scale */ size_to_mat3(smat, texmap->size); /* rotation */ /* TexMapping rotation are now in radians. */ eul_to_mat3(rmat, texmap->rot); /* compose it all */ mul_m3_m3m3(mat, rmat, smat); mul_m3_m3m3(mat, proj, mat); /* translation */ copy_m4_m3(texmap->mat, mat); copy_v3_v3(texmap->mat[3], texmap->loc); texmap->flag &= ~TEXMAP_UNIT_MATRIX; } }
/* Evaluate spline IK for a given bone */ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *ob, bPoseChannel *pchan, int index, float ctime) { bSplineIKConstraint *ikData = tree->ikData; float poseHead[3], poseTail[3], poseMat[4][4]; float splineVec[3], scaleFac, radius = 1.0f; /* firstly, calculate the bone matrix the standard way, since this is needed for roll control */ BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1); copy_v3_v3(poseHead, pchan->pose_head); copy_v3_v3(poseTail, pchan->pose_tail); /* step 1: determine the positions for the endpoints of the bone */ { float vec[4], dir[3], rad; float tailBlendFac = 1.0f; /* determine if the bone should still be affected by SplineIK */ if (tree->points[index + 1] >= 1.0f) { /* spline doesn't affect the bone anymore, so done... */ pchan->flag |= POSE_DONE; return; } else if ((tree->points[index] >= 1.0f) && (tree->points[index + 1] < 1.0f)) { /* blending factor depends on the amount of the bone still left on the chain */ tailBlendFac = (1.0f - tree->points[index + 1]) / (tree->points[index] - tree->points[index + 1]); } /* tail endpoint */ if (where_on_path(ikData->tar, tree->points[index], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* convert the position to pose-space, then store it */ mul_m4_v3(ob->imat, vec); interp_v3_v3v3(poseTail, pchan->pose_tail, vec, tailBlendFac); /* set the new radius */ radius = rad; } /* head endpoint */ if (where_on_path(ikData->tar, tree->points[index + 1], vec, dir, NULL, &rad, NULL)) { /* apply curve's object-mode transforms to the position * unless the option to allow curve to be positioned elsewhere is activated (i.e. no root) */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) == 0) mul_m4_v3(ikData->tar->obmat, vec); /* store the position, and convert it to pose space */ mul_m4_v3(ob->imat, vec); copy_v3_v3(poseHead, vec); /* set the new radius (it should be the average value) */ radius = (radius + rad) / 2; } } /* step 2: determine the implied transform from these endpoints * - splineVec: the vector direction that the spline applies on the bone * - scaleFac: the factor that the bone length is scaled by to get the desired amount */ sub_v3_v3v3(splineVec, poseTail, poseHead); scaleFac = len_v3(splineVec) / pchan->bone->length; /* step 3: compute the shortest rotation needed to map from the bone rotation to the current axis * - this uses the same method as is used for the Damped Track Constraint (see the code there for details) */ { float dmat[3][3], rmat[3][3], tmat[3][3]; float raxis[3], rangle; /* compute the raw rotation matrix from the bone's current matrix by extracting only the * orientation-relevant axes, and normalizing them */ copy_v3_v3(rmat[0], pchan->pose_mat[0]); copy_v3_v3(rmat[1], pchan->pose_mat[1]); copy_v3_v3(rmat[2], pchan->pose_mat[2]); normalize_m3(rmat); /* also, normalize the orientation imposed by the bone, now that we've extracted the scale factor */ normalize_v3(splineVec); /* calculate smallest axis-angle rotation necessary for getting from the * current orientation of the bone, to the spline-imposed direction */ cross_v3_v3v3(raxis, rmat[1], splineVec); rangle = dot_v3v3(rmat[1], splineVec); CLAMP(rangle, -1.0f, 1.0f); rangle = acosf(rangle); /* multiply the magnitude of the angle by the influence of the constraint to * control the influence of the SplineIK effect */ rangle *= tree->con->enforce; /* construct rotation matrix from the axis-angle rotation found above * - this call takes care to make sure that the axis provided is a unit vector first */ axis_angle_to_mat3(dmat, raxis, rangle); /* combine these rotations so that the y-axis of the bone is now aligned as the spline dictates, * while still maintaining roll control from the existing bone animation */ mul_m3_m3m3(tmat, dmat, rmat); /* m1, m3, m2 */ normalize_m3(tmat); /* attempt to reduce shearing, though I doubt this'll really help too much now... */ copy_m4_m3(poseMat, tmat); } /* step 4: set the scaling factors for the axes */ { /* only multiply the y-axis by the scaling factor to get nice volume-preservation */ mul_v3_fl(poseMat[1], scaleFac); /* set the scaling factors of the x and z axes from... */ switch (ikData->xzScaleMode) { case CONSTRAINT_SPLINEIK_XZS_ORIGINAL: { /* original scales get used */ float scale; /* x-axis scale */ scale = len_v3(pchan->pose_mat[0]); mul_v3_fl(poseMat[0], scale); /* z-axis scale */ scale = len_v3(pchan->pose_mat[2]); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_INVERSE: { /* old 'volume preservation' method using the inverse scale */ float scale; /* calculate volume preservation factor which is * basically the inverse of the y-scaling factor */ if (fabsf(scaleFac) != 0.0f) { scale = 1.0f / fabsf(scaleFac); /* we need to clamp this within sensible values */ /* NOTE: these should be fine for now, but should get sanitised in future */ CLAMP(scale, 0.0001f, 100000.0f); } else scale = 1.0f; /* apply the scaling */ mul_v3_fl(poseMat[0], scale); mul_v3_fl(poseMat[2], scale); break; } case CONSTRAINT_SPLINEIK_XZS_VOLUMETRIC: { /* improved volume preservation based on the Stretch To constraint */ float final_scale; /* as the basis for volume preservation, we use the inverse scale factor... */ if (fabsf(scaleFac) != 0.0f) { /* NOTE: The method here is taken wholesale from the Stretch To constraint */ float bulge = powf(1.0f / fabsf(scaleFac), ikData->bulge); if (bulge > 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MAX) { float bulge_max = max_ff(ikData->bulge_max, 1.0f); float hard = min_ff(bulge, bulge_max); float range = bulge_max - 1.0f; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } if (bulge < 1.0f) { if (ikData->flag & CONSTRAINT_SPLINEIK_USE_BULGE_MIN) { float bulge_min = CLAMPIS(ikData->bulge_min, 0.0f, 1.0f); float hard = max_ff(bulge, bulge_min); float range = 1.0f - bulge_min; float scale = (range > 0.0f) ? 1.0f / range : 0.0f; float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2; bulge = interpf(soft, hard, ikData->bulge_smooth); } } /* compute scale factor for xz axes from this value */ final_scale = sqrtf(bulge); } else { /* no scaling, so scale factor is simple */ final_scale = 1.0f; } /* apply the scaling (assuming normalised scale) */ mul_v3_fl(poseMat[0], final_scale); mul_v3_fl(poseMat[2], final_scale); break; } } /* finally, multiply the x and z scaling by the radius of the curve too, * to allow automatic scales to get tweaked still */ if ((ikData->flag & CONSTRAINT_SPLINEIK_NO_CURVERAD) == 0) { mul_v3_fl(poseMat[0], radius); mul_v3_fl(poseMat[2], radius); } } /* step 5: set the location of the bone in the matrix */ if (ikData->flag & CONSTRAINT_SPLINEIK_NO_ROOT) { /* when the 'no-root' option is affected, the chain can retain * the shape but be moved elsewhere */ copy_v3_v3(poseHead, pchan->pose_head); } else if (tree->con->enforce < 1.0f) { /* when the influence is too low * - blend the positions for the 'root' bone * - stick to the parent for any other */ if (pchan->parent) { copy_v3_v3(poseHead, pchan->pose_head); } else { /* FIXME: this introduces popping artifacts when we reach 0.0 */ interp_v3_v3v3(poseHead, pchan->pose_head, poseHead, tree->con->enforce); } } copy_v3_v3(poseMat[3], poseHead); /* finally, store the new transform */ copy_m4_m4(pchan->pose_mat, poseMat); copy_v3_v3(pchan->pose_head, poseHead); /* recalculate tail, as it's now outdated after the head gets adjusted above! */ BKE_pose_where_is_bone_tail(pchan); /* done! */ pchan->flag |= POSE_DONE; }
/* join armature exec is exported for use in object->join objects operator... */ int join_armature_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); bArmature *arm = (ob) ? ob->data : NULL; bPose *pose, *opose; bPoseChannel *pchan, *pchann; EditBone *curbone; float mat[4][4], oimat[4][4]; /* Ensure we're not in editmode and that the active object is an armature*/ if (!ob || ob->type != OB_ARMATURE) return OPERATOR_CANCELLED; if (!arm || arm->edbo) return OPERATOR_CANCELLED; /* Get editbones of active armature to add editbones to */ ED_armature_to_edit(ob); /* get pose of active object and move it out of posemode */ pose = ob->pose; ob->mode &= ~OB_MODE_POSE; CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases) { if ((base->object->type == OB_ARMATURE) && (base->object != ob)) { bArmature *curarm = base->object->data; /* Make a list of editbones in current armature */ ED_armature_to_edit(base->object); /* Get Pose of current armature */ opose = base->object->pose; base->object->mode &= ~OB_MODE_POSE; //BASACT->flag &= ~OB_MODE_POSE; /* Find the difference matrix */ invert_m4_m4(oimat, ob->obmat); mult_m4_m4m4(mat, oimat, base->object->obmat); /* Copy bones and posechannels from the object to the edit armature */ for (pchan = opose->chanbase.first; pchan; pchan = pchann) { pchann = pchan->next; curbone = editbone_name_exists(curarm->edbo, pchan->name); /* Get new name */ unique_editbone_name(arm->edbo, curbone->name, NULL); /* Transform the bone */ { float premat[4][4]; float postmat[4][4]; float difmat[4][4]; float imat[4][4]; float temp[3][3]; float delta[3]; /* Get the premat */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); unit_m4(premat); /* Mat4MulMat34 only sets 3x3 part */ mul_m4_m3m4(premat, temp, mat); mul_m4_v3(mat, curbone->head); mul_m4_v3(mat, curbone->tail); /* Get the postmat */ sub_v3_v3v3(delta, curbone->tail, curbone->head); vec_roll_to_mat3(delta, curbone->roll, temp); copy_m4_m3(postmat, temp); /* Find the roll */ invert_m4_m4(imat, premat); mult_m4_m4m4(difmat, imat, postmat); curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]); } /* Fix Constraints and Other Links to this Bone and Armature */ joined_armature_fix_links(ob, base->object, pchan, curbone); /* Rename pchan */ BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name)); /* Jump Ship! */ BLI_remlink(curarm->edbo, curbone); BLI_addtail(arm->edbo, curbone); BLI_remlink(&opose->chanbase, pchan); BLI_addtail(&pose->chanbase, pchan); BKE_pose_channels_hash_free(opose); BKE_pose_channels_hash_free(pose); } ED_base_object_free_and_unlink(bmain, scene, base); } } CTX_DATA_END; DAG_relations_tag_update(bmain); /* because we removed object(s) */ ED_armature_from_edit(ob); ED_armature_edit_free(ob); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); 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], 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; }
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 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; }