void getConstraintMatrix(TransInfo *t) { float mat[3][3]; invert_m3_m3(t->con.imtx, t->con.mtx); unit_m3(t->con.pmtx); if (!(t->con.mode & CON_AXIS0)) { t->con.pmtx[0][0] = t->con.pmtx[0][1] = t->con.pmtx[0][2] = 0.0f; } if (!(t->con.mode & CON_AXIS1)) { t->con.pmtx[1][0] = t->con.pmtx[1][1] = t->con.pmtx[1][2] = 0.0f; } if (!(t->con.mode & CON_AXIS2)) { t->con.pmtx[2][0] = t->con.pmtx[2][1] = t->con.pmtx[2][2] = 0.0f; } mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); }
static void applyObjectConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) { if (td && t->con.mode & CON_APPLY) { float tmat[3][3]; float imat[3][3]; invert_m3_m3(imat, td->axismtx); if (!(t->con.mode & CON_AXIS0)) { smat[0][0] = 1.0f; } if (!(t->con.mode & CON_AXIS1)) { smat[1][1] = 1.0f; } if (!(t->con.mode & CON_AXIS2)) { smat[2][2] = 1.0f; } mul_m3_m3m3(tmat, smat, imat); if (t->flag & T_EDIT) { mul_m3_m3m3(smat, t->obedit_mat, smat); } mul_m3_m3m3(smat, td->axismtx, tmat); } }
void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4]) { EditBone *ebone; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ float mat3[3][3]; copy_m3_m4(mat3, mat); normalize_m3(mat3); /* Do the rotations */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { float tmat[3][3]; /* find the current bone's roll matrix */ ED_armature_ebone_to_mat3(ebone, tmat); /* transform the roll matrix */ mul_m3_m3m3(tmat, mat3, tmat); /* transform the bone */ mul_m4_v3(mat, ebone->head); mul_m4_v3(mat, ebone->tail); /* apply the transformed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); ebone->rad_head *= scale; ebone->rad_tail *= scale; ebone->dist *= scale; /* we could be smarter and scale by the matrix along the x & z axis */ ebone->xwidth *= scale; ebone->zwidth *= scale; } }
/* 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; }
/* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { if (t->total == 1) { float axismtx[3][3]; if (t->flag & T_EDIT) { mul_m3_m3m3(axismtx, t->obedit_mat, t->data->axismtx); } else { copy_m3_m3(axismtx, t->data->axismtx); } setConstraint(t, axismtx, mode, text); } else { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); copy_m3_m3(t->con.mtx, t->data->axismtx); t->con.mode = mode; getConstraintMatrix(t); startConstraint(t); t->con.drawExtra = drawObjectConstraint; t->con.applyVec = applyObjectConstraintVec; t->con.applySize = applyObjectConstraintSize; t->con.applyRot = applyObjectConstraintRot; t->redraw = TREDRAW_HARD; } }
/* 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); }
/* v3d and rv3d are allowed to be NULL */ void add_primitive_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d) { Object *obedit = scene->obedit; // XXX get from context bArmature *arm = obedit->data; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; EditBone *bone; /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_v3_m4v3(curs, obedit->imat, give_cursor(scene, v3d)); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit, 0); /* Create a bone */ bone = ED_armature_edit_bone_add(arm, "Bone"); arm->act_edbone = bone; copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z }
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]); } }
static void applyAxisConstraintSize(TransInfo *t, TransData *td, float smat[3][3]) { if (!td && t->con.mode & CON_APPLY) { float tmat[3][3]; if (!(t->con.mode & CON_AXIS0)) { smat[0][0] = 1.0f; } if (!(t->con.mode & CON_AXIS1)) { smat[1][1] = 1.0f; } if (!(t->con.mode & CON_AXIS2)) { smat[2][2] = 1.0f; } mul_m3_m3m3(tmat, smat, t->con.imtx); mul_m3_m3m3(smat, t->con.mtx, tmat); } }
void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]) { float rot[3][3]; /* rotation between segments */ rotation_between_vecs_to_mat3(rot, dir_old, dir_new); /* rotate the frame */ mul_m3_m3m3(mat, rot, mat); }
static void drawObjectConstraint(TransInfo *t) { /* Draw the first one lighter because that's the one who controls the others. * Meaning the transformation is projected on that one and just copied on the others * constraint space. * In a nutshell, the object with light axis is controlled by the user and the others follow. * Without drawing the first light, users have little clue what they are doing. */ short options = DRAWLIGHT; TransData *td = t->data; int i; float tmp_axismtx[3][3]; for (i = 0; i < t->total; i++, td++) { float co[3]; float (*axismtx)[3]; if (t->flag & T_PROP_EDIT) { /* we're sorted, so skip the rest */ if (td->factor == 0.0f) { break; } } if (t->flag & T_OBJECT) { copy_v3_v3(co, td->ob->obmat[3]); axismtx = td->axismtx; } else if (t->flag & T_EDIT) { mul_v3_m4v3(co, t->obedit->obmat, td->center); mul_m3_m3m3(tmp_axismtx, t->obedit_mat, td->axismtx); axismtx = tmp_axismtx; } else if (t->flag & T_POSE) { mul_v3_m4v3(co, t->poseobj->obmat, td->center); axismtx = td->axismtx; } else { copy_v3_v3(co, td->center); axismtx = td->axismtx; } if (t->con.mode & CON_AXIS0) { drawLine(t, co, axismtx[0], 'X', options); } if (t->con.mode & CON_AXIS1) { drawLine(t, co, axismtx[1], 'Y', options); } if (t->con.mode & CON_AXIS2) { drawLine(t, co, axismtx[2], 'Z', options); } options &= ~DRAWLIGHT; } }
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; } }
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); }
static PyObject *Euler_rotate(EulerObject * self, PyObject *value) { float self_rmat[3][3], other_rmat[3][3], rmat[3][3]; if(!BaseMath_ReadCallback(self)) return NULL; if(mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1) return NULL; eulO_to_mat3(self_rmat, self->eul, self->order); mul_m3_m3m3(rmat, self_rmat, other_rmat); mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat); (void)BaseMath_WriteCallback(self); Py_RETURN_NONE; }
static void applyObjectConstraintRot( TransInfo *t, TransDataContainer *tc, TransData *td, float vec[3], float *angle) { if (t->con.mode & CON_APPLY) { int mode = t->con.mode & (CON_AXIS0 | CON_AXIS1 | CON_AXIS2); float tmp_axismtx[3][3]; float(*axismtx)[3]; /* on setup call, use first object */ if (td == NULL) { BLI_assert(tc == NULL); tc = TRANS_DATA_CONTAINER_FIRST_OK(t); td = tc->data; } if (t->flag & T_EDIT) { mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); axismtx = tmp_axismtx; } else { axismtx = td->axismtx; } switch (mode) { case CON_AXIS0: case (CON_AXIS1 | CON_AXIS2): copy_v3_v3(vec, axismtx[0]); break; case CON_AXIS1: case (CON_AXIS0 | CON_AXIS2): copy_v3_v3(vec, axismtx[1]); break; case CON_AXIS2: case (CON_AXIS0 | CON_AXIS1): copy_v3_v3(vec, axismtx[2]); break; } if (angle && (mode & CON_NOFLIP) == 0 && hasNumInput(&t->num) == 0) { if (dot_v3v3(vec, t->viewinv[2]) > 0.0f) { *angle = -(*angle); } } } }
void ED_armature_apply_transform(Object *ob, float mat[4][4]) { EditBone *ebone; bArmature *arm = ob->data; float scale = mat4_to_scale(mat); /* store the scale of the matrix here to use on envelopes */ float mat3[3][3]; copy_m3_m4(mat3, mat); normalize_m3(mat3); /* Put the armature into editmode */ ED_armature_to_edit(ob); /* Do the rotations */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { float delta[3], tmat[3][3]; /* find the current bone's roll matrix */ sub_v3_v3v3(delta, ebone->tail, ebone->head); vec_roll_to_mat3(delta, ebone->roll, tmat); /* transform the roll matrix */ mul_m3_m3m3(tmat, mat3, tmat); /* transform the bone */ mul_m4_v3(mat, ebone->head); mul_m4_v3(mat, ebone->tail); /* apply the transfiormed roll back */ mat3_to_vec_roll(tmat, NULL, &ebone->roll); ebone->rad_head *= scale; ebone->rad_tail *= scale; ebone->dist *= scale; /* we could be smarter and scale by the matrix along the x & z axis */ ebone->xwidth *= scale; ebone->zwidth *= scale; } /* Turn the list into an armature */ ED_armature_from_edit(ob); ED_armature_edit_free(ob); }
/* also sets restposition in armature (arm_mat) */ static void fix_bonelist_roll(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; float premat[3][3]; float postmat[3][3]; float difmat[3][3]; float imat[3][3]; for (curBone = bonelist->first; curBone; curBone = curBone->next) { /* sets local matrix and arm_mat (restpos) */ BKE_armature_where_is_bone(curBone, curBone->parent); /* Find the associated editbone */ for (ebone = editbonelist->first; ebone; ebone = ebone->next) if (ebone->temp.bone == curBone) break; if (ebone) { /* Get the ebone premat */ ED_armature_ebone_to_mat3(ebone, premat); /* Get the bone postmat */ copy_m3_m4(postmat, curBone->arm_mat); invert_m3_m3(imat, premat); mul_m3_m3m3(difmat, imat, postmat); #if 0 printf("Bone %s\n", curBone->name); print_m4("premat", premat); print_m4("postmat", postmat); print_m4("difmat", difmat); printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); /* and set restposition again */ BKE_armature_where_is_bone(curBone, curBone->parent); } fix_bonelist_roll(&curBone->childbase, editbonelist); } }
static int armature_bone_primitive_add_exec(bContext *C, wmOperator *op) { RegionView3D *rv3d = CTX_wm_region_view3d(C); Object *obedit = CTX_data_edit_object(C); EditBone *bone; float obmat[3][3], curs[3], viewmat[3][3], totmat[3][3], imat[3][3]; char name[MAXBONENAME]; RNA_string_get(op->ptr, "name", name); copy_v3_v3(curs, ED_view3d_cursor3d_get(CTX_data_scene(C), CTX_wm_view3d(C))); /* Get inverse point for head and orientation for tail */ invert_m4_m4(obedit->imat, obedit->obmat); mul_m4_v3(obedit->imat, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) copy_m3_m4(obmat, rv3d->viewmat); else unit_m3(obmat); copy_m3_m4(viewmat, obedit->obmat); mul_m3_m3m3(totmat, obmat, viewmat); invert_m3_m3(imat, totmat); ED_armature_deselect_all(obedit); /* Create a bone */ bone = ED_armature_edit_bone_add(obedit->data, name); copy_v3_v3(bone->head, curs); if (rv3d && (U.flag & USER_ADD_VIEWALIGNED)) add_v3_v3v3(bone->tail, bone->head, imat[1]); // bone with unit length 1 else add_v3_v3v3(bone->tail, bone->head, imat[2]); // bone with unit length 1, pointing up Z /* note, notifier might evolve */ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; }
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; }
static void meshcache_do( MeshCacheModifierData *mcmd, Object *ob, DerivedMesh *UNUSED(dm), float (*vertexCos_Real)[3], int numVerts) { const bool use_factor = mcmd->factor < 1.0f; float (*vertexCos_Store)[3] = (use_factor || (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE)) ? MEM_mallocN(sizeof(*vertexCos_Store) * numVerts, __func__) : NULL; float (*vertexCos)[3] = vertexCos_Store ? vertexCos_Store : vertexCos_Real; Scene *scene = mcmd->modifier.scene; const float fps = FPS; char filepath[FILE_MAX]; const char *err_str = NULL; bool ok; float time; /* -------------------------------------------------------------------- */ /* Interpret Time (the reading functions also do some of this ) */ if (mcmd->play_mode == MOD_MESHCACHE_PLAY_CFEA) { const float cfra = BKE_scene_frame_get(scene); switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = cfra; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = cfra / fps; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = cfra / fps; break; } } /* apply offset and scale */ time = (mcmd->frame_scale * time) - mcmd->frame_start; } else { /* if (mcmd->play_mode == MOD_MESHCACHE_PLAY_EVAL) { */ switch (mcmd->time_mode) { case MOD_MESHCACHE_TIME_FRAME: { time = mcmd->eval_frame; break; } case MOD_MESHCACHE_TIME_SECONDS: { time = mcmd->eval_time; break; } case MOD_MESHCACHE_TIME_FACTOR: default: { time = mcmd->eval_factor; break; } } } /* -------------------------------------------------------------------- */ /* Read the File (or error out when the file is bad) */ /* would be nice if we could avoid doing this _every_ frame */ BLI_strncpy(filepath, mcmd->filepath, sizeof(filepath)); BLI_path_abs(filepath, ID_BLEND_PATH(G.main, (ID *)ob)); switch (mcmd->type) { case MOD_MESHCACHE_TYPE_MDD: ok = MOD_meshcache_read_mdd_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; case MOD_MESHCACHE_TYPE_PC2: ok = MOD_meshcache_read_pc2_times(filepath, vertexCos, numVerts, mcmd->interp, time, fps, mcmd->time_mode, &err_str); break; default: ok = false; break; } /* -------------------------------------------------------------------- */ /* tricky shape key integration (slow!) */ if (mcmd->deform_mode == MOD_MESHCACHE_DEFORM_INTEGRATE) { Mesh *me = ob->data; /* we could support any object type */ if (UNLIKELY(ob->type != OB_MESH)) { modifier_setError(&mcmd->modifier, "'Integrate' only valid for Mesh objects"); } else if (UNLIKELY(me->totvert != numVerts)) { modifier_setError(&mcmd->modifier, "'Integrate' original mesh vertex mismatch"); } else if (UNLIKELY(me->totpoly == 0)) { modifier_setError(&mcmd->modifier, "'Integrate' requires faces"); } else { /* the moons align! */ int i; float (*vertexCos_Source)[3] = MEM_mallocN(sizeof(*vertexCos_Source) * numVerts, __func__); float (*vertexCos_New)[3] = MEM_mallocN(sizeof(*vertexCos_New) * numVerts, __func__); MVert *mv = me->mvert; for (i = 0; i < numVerts; i++, mv++) { copy_v3_v3(vertexCos_Source[i], mv->co); } BKE_mesh_calc_relative_deform( me->mpoly, me->totpoly, me->mloop, me->totvert, (const float (*)[3])vertexCos_Source, /* from the original Mesh*/ (const float (*)[3])vertexCos_Real, /* the input we've been given (shape keys!) */ (const float (*)[3])vertexCos, /* the result of this modifier */ vertexCos_New /* the result of this function */ ); /* write the corrected locations back into the result */ memcpy(vertexCos, vertexCos_New, sizeof(*vertexCos) * numVerts); MEM_freeN(vertexCos_Source); MEM_freeN(vertexCos_New); } } /* -------------------------------------------------------------------- */ /* Apply the transformation matrix (if needed) */ if (UNLIKELY(err_str)) { modifier_setError(&mcmd->modifier, "%s", err_str); } else if (ok) { bool use_matrix = false; float mat[3][3]; unit_m3(mat); if (mat3_from_axis_conversion(mcmd->forward_axis, mcmd->up_axis, 1, 2, mat)) { use_matrix = true; } if (mcmd->flip_axis) { float tmat[3][3]; unit_m3(tmat); if (mcmd->flip_axis & (1 << 0)) tmat[0][0] = -1.0f; if (mcmd->flip_axis & (1 << 1)) tmat[1][1] = -1.0f; if (mcmd->flip_axis & (1 << 2)) tmat[2][2] = -1.0f; mul_m3_m3m3(mat, tmat, mat); use_matrix = true; } if (use_matrix) { int i; for (i = 0; i < numVerts; i++) { mul_m3_v3(mat, vertexCos[i]); } } } if (vertexCos_Store) { if (ok) { if (use_factor) { interp_vn_vn(*vertexCos_Real, *vertexCos_Store, mcmd->factor, numVerts * 3); } else { memcpy(vertexCos_Real, vertexCos_Store, sizeof(*vertexCos_Store) * numVerts); } } MEM_freeN(vertexCos_Store); } }
static void drawObjectConstraint(TransInfo *t) { /* Draw the first one lighter because that's the one who controls the others. * Meaning the transformation is projected on that one and just copied on the others * constraint space. * In a nutshell, the object with light axis is controlled by the user and the others follow. * Without drawing the first light, users have little clue what they are doing. */ short options = DRAWLIGHT; int i; float tmp_axismtx[3][3]; FOREACH_TRANS_DATA_CONTAINER (t, tc) { TransData *td = tc->data; for (i = 0; i < tc->data_len; i++, td++) { float co[3]; float(*axismtx)[3]; if (t->flag & T_PROP_EDIT) { /* we're sorted, so skip the rest */ if (td->factor == 0.0f) { break; } } if (t->options & CTX_GPENCIL_STROKES) { /* only draw a constraint line for one point, otherwise we can't see anything */ if ((options & DRAWLIGHT) == 0) { break; } } if (t->flag & T_OBJECT) { copy_v3_v3(co, td->ob->obmat[3]); axismtx = td->axismtx; } else if (t->flag & T_EDIT) { mul_v3_m4v3(co, tc->mat, td->center); mul_m3_m3m3(tmp_axismtx, tc->mat3_unit, td->axismtx); axismtx = tmp_axismtx; } else if (t->flag & T_POSE) { mul_v3_m4v3(co, tc->mat, td->center); axismtx = td->axismtx; } else { copy_v3_v3(co, td->center); axismtx = td->axismtx; } if (t->con.mode & CON_AXIS0) { drawLine(t, co, axismtx[0], 'X', options); } if (t->con.mode & CON_AXIS1) { drawLine(t, co, axismtx[1], 'Y', options); } if (t->con.mode & CON_AXIS2) { drawLine(t, co, axismtx[2], 'Z', options); } options &= ~DRAWLIGHT; } }
/* 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; }
/* This function: * - sets local head/tail rest locations using parent bone's arm_mat. * - calls BKE_armature_where_is_bone() which uses parent's transform (arm_mat) to define this bone's transform. * - fixes (converts) EditBone roll into Bone roll. * - calls again BKE_armature_where_is_bone(), since roll fiddling may have changed things for our bone... * Note that order is crucial here, we can only handle child if all its parents in chain have already been handled * (this is ensured by recursive process). */ static void armature_finalize_restpose(ListBase *bonelist, ListBase *editbonelist) { Bone *curBone; EditBone *ebone; for (curBone = bonelist->first; curBone; curBone = curBone->next) { /* Set bone's local head/tail. * Note that it's important to use final parent's restpose (arm_mat) here, instead of setting those values * from editbone's matrix (see T46010). */ if (curBone->parent) { float parmat_inv[4][4]; invert_m4_m4(parmat_inv, curBone->parent->arm_mat); /* Get the new head and tail */ sub_v3_v3v3(curBone->head, curBone->arm_head, curBone->parent->arm_tail); sub_v3_v3v3(curBone->tail, curBone->arm_tail, curBone->parent->arm_tail); mul_mat3_m4_v3(parmat_inv, curBone->head); mul_mat3_m4_v3(parmat_inv, curBone->tail); } else { copy_v3_v3(curBone->head, curBone->arm_head); copy_v3_v3(curBone->tail, curBone->arm_tail); } /* Set local matrix and arm_mat (restpose). * Do not recurse into children here, armature_finalize_restpose() is already recursive. */ BKE_armature_where_is_bone(curBone, curBone->parent, false); /* Find the associated editbone */ for (ebone = editbonelist->first; ebone; ebone = ebone->next) { if (ebone->temp.bone == curBone) { float premat[3][3]; float postmat[3][3]; float difmat[3][3]; float imat[3][3]; /* Get the ebone premat and its inverse. */ ED_armature_ebone_to_mat3(ebone, premat); invert_m3_m3(imat, premat); /* Get the bone postmat. */ copy_m3_m4(postmat, curBone->arm_mat); mul_m3_m3m3(difmat, imat, postmat); #if 0 printf("Bone %s\n", curBone->name); print_m4("premat", premat); print_m4("postmat", postmat); print_m4("difmat", difmat); printf("Roll = %f\n", RAD2DEGF(-atan2(difmat[2][0], difmat[2][2]))); #endif curBone->roll = -atan2f(difmat[2][0], difmat[2][2]); /* and set restposition again */ BKE_armature_where_is_bone(curBone, curBone->parent, false); break; } } /* Recurse into children... */ armature_finalize_restpose(&curBone->childbase, editbonelist); } }
/* 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); }
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 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); }
/* 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; }
struct chartrans *BKE_text_to_curve(Main *bmain, Scene *scene, Object *ob, int mode) { VFont *vfont, *oldvfont; VFontData *vfd= NULL; Curve *cu; CharInfo *info = NULL, *custrinfo; TextBox *tb; VChar *che; struct chartrans *chartransdata=NULL, *ct; float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4; float twidth, maxlen= 0; int i, slen, j; int curbox; int selstart, selend; int utf8len; short cnr=0, lnr=0, wsnr= 0; wchar_t *mem, *tmp, ascii; /* renark: do calculations including the trailing '\0' of a string * because the cursor can be at that location */ if (ob->type!=OB_FONT) return NULL; // Set font data cu= (Curve *) ob->data; vfont= cu->vfont; if (cu->str == NULL) return NULL; if (vfont == NULL) return NULL; // Create unicode string utf8len = BLI_strlen_utf8(cu->str); mem = MEM_callocN(((utf8len + 1) * sizeof(wchar_t)), "convertedmem"); BLI_strncpy_wchar_from_utf8(mem, cu->str, utf8len + 1); // Count the wchar_t string length slen = wcslen(mem); if (cu->ulheight == 0.0f) cu->ulheight = 0.05f; if (cu->strinfo==NULL) /* old file */ cu->strinfo = MEM_callocN((slen+4) * sizeof(CharInfo), "strinfo compat"); custrinfo= cu->strinfo; if (cu->editfont) custrinfo= cu->editfont->textbufinfo; if (cu->tb==NULL) cu->tb= MEM_callocN(MAXTEXTBOX*sizeof(TextBox), "TextBox compat"); vfd= vfont_get_data(bmain, vfont); /* The VFont Data can not be found */ if (!vfd) { if (mem) MEM_freeN(mem); return NULL; } /* calc offset and rotation of each char */ ct = chartransdata = (struct chartrans*)MEM_callocN((slen+1)* sizeof(struct chartrans),"buildtext"); /* We assume the worst case: 1 character per line (is freed at end anyway) */ linedata= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext2"); linedata2= MEM_mallocN(sizeof(float)*(slen*2 + 1),"buildtext3"); linedata3= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext4"); linedata4= MEM_callocN(sizeof(float)*(slen*2 + 1),"buildtext5"); linedist= cu->linedist; xof= cu->xof + (cu->tb[0].x/cu->fsize); yof= cu->yof + (cu->tb[0].y/cu->fsize); xtrax= 0.5f*cu->spacing-0.5f; oldvfont = NULL; for (i=0; i<slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP|CU_CHINFO_SMALLCAPS_CHECK); if (cu->selboxes) MEM_freeN(cu->selboxes); cu->selboxes = NULL; if (BKE_font_getselection(ob, &selstart, &selend)) cu->selboxes = MEM_callocN((selend-selstart+1)*sizeof(SelBox), "font selboxes"); tb = &(cu->tb[0]); curbox= 0; for (i = 0 ; i<=slen ; i++) { makebreak: // Characters in the list info = &(custrinfo[i]); ascii = mem[i]; if (info->flag & CU_CHINFO_SMALLCAPS) { ascii = towupper(ascii); if (mem[i] != ascii) { mem[i]= ascii; info->flag |= CU_CHINFO_SMALLCAPS_CHECK; } } vfont = which_vfont(cu, info); if (vfont==NULL) break; che= find_vfont_char(vfd, ascii); /* * The character wasn't in the current curve base so load it * But if the font is FO_BUILTIN_NAME then do not try loading since * whole font is in the memory already */ if (che == NULL && strcmp(vfont->name, FO_BUILTIN_NAME)) { BLI_vfontchar_from_freetypefont(vfont, ascii); } /* Try getting the character again from the list */ che= find_vfont_char(vfd, ascii); /* No VFont found */ if (vfont==NULL) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } if (vfont != oldvfont) { vfd= vfont_get_data(bmain, vfont); oldvfont = vfont; } /* VFont Data for VFont couldn't be found */ if (!vfd) { if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; } twidth = char_width(cu, che, info); // Calculate positions if ((tb->w != 0.0f) && (ct->dobreak==0) && ((xof-(tb->x/cu->fsize)+twidth)*cu->fsize) > tb->w + cu->xof*cu->fsize) { // fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]); for (j=i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak==0); j--) { if (mem[j]==' ' || mem[j]=='-') { ct -= (i-(j-1)); cnr -= (i-(j-1)); if (mem[j] == ' ') wsnr--; if (mem[j] == '-') wsnr++; i = j-1; xof = ct->xof; ct[1].dobreak = 1; custrinfo[i+1].flag |= CU_CHINFO_WRAP; goto makebreak; } if (chartransdata[j].dobreak) { // fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]); ct->dobreak= 1; custrinfo[i+1].flag |= CU_CHINFO_WRAP; ct -= 1; cnr -= 1; i--; xof = ct->xof; goto makebreak; } } } if (ascii== '\n' || ascii== '\r' || ascii==0 || ct->dobreak) { ct->xof= xof; ct->yof= yof; ct->linenr= lnr; ct->charnr= cnr; yof-= linedist; maxlen= MAX2(maxlen, (xof-tb->x/cu->fsize)); linedata[lnr]= xof-tb->x/cu->fsize; linedata2[lnr]= cnr; linedata3[lnr]= tb->w/cu->fsize; linedata4[lnr]= wsnr; if ( (tb->h != 0.0f) && ((-(yof-(tb->y/cu->fsize))) > ((tb->h/cu->fsize)-(linedist*cu->fsize)) - cu->yof) && (cu->totbox > (curbox+1)) ) { maxlen= 0; tb++; curbox++; yof= cu->yof + tb->y/cu->fsize; } /* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */ #if 0 if (ascii == '\n' || ascii == '\r') xof = cu->xof; else xof= cu->xof + (tb->x/cu->fsize); #else xof= cu->xof + (tb->x/cu->fsize); #endif lnr++; cnr= 0; wsnr= 0; } else if (ascii==9) { /* TAB */ float tabfac; ct->xof= xof; ct->yof= yof; ct->linenr= lnr; ct->charnr= cnr++; tabfac= (xof-cu->xof+0.01f); tabfac= 2.0f*ceilf(tabfac/2.0f); xof= cu->xof+tabfac; } else { SelBox *sb= NULL; float wsfac; ct->xof= xof; ct->yof= yof; ct->linenr= lnr; ct->charnr= cnr++; if (cu->selboxes && (i>=selstart) && (i<=selend)) { sb = &(cu->selboxes[i-selstart]); sb->y = yof*cu->fsize-linedist*cu->fsize*0.1f; sb->h = linedist*cu->fsize; sb->w = xof*cu->fsize; } if (ascii==32) { wsfac = cu->wordspace; wsnr++; } else wsfac = 1.0f; // Set the width of the character twidth = char_width(cu, che, info); xof += (twidth*wsfac*(1.0f+(info->kern/40.0f)) ) + xtrax; if (sb) sb->w = (xof*cu->fsize) - sb->w; } ct++; } cu->lines= 1; ct= chartransdata; tmp = mem; for (i= 0; i<=slen; i++, tmp++, ct++) { ascii = *tmp; if (ascii== '\n' || ascii== '\r' || ct->dobreak) cu->lines++; } // linedata is now: width of line // linedata2 is now: number of characters // linedata3 is now: maxlen of that line // linedata4 is now: number of whitespaces of line if (cu->spacemode!=CU_LEFT) { ct= chartransdata; if (cu->spacemode==CU_RIGHT) { for (i=0;i<lnr;i++) linedata[i]= linedata3[i]-linedata[i]; for (i=0; i<=slen; i++) { ct->xof+= linedata[ct->linenr]; ct++; } } else if (cu->spacemode==CU_MIDDLE) { for (i=0;i<lnr;i++) linedata[i]= (linedata3[i]-linedata[i])/2; for (i=0; i<=slen; i++) { ct->xof+= linedata[ct->linenr]; ct++; } } else if ((cu->spacemode==CU_FLUSH) && (cu->tb[0].w != 0.0f)) { for (i=0;i<lnr;i++) if (linedata2[i]>1) linedata[i]= (linedata3[i]-linedata[i])/(linedata2[i]-1); for (i=0; i<=slen; i++) { for (j=i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) { /* do nothing */ } // if ((mem[j]!='\r') && (mem[j]!='\n') && (mem[j])) { ct->xof+= ct->charnr*linedata[ct->linenr]; // } ct++; } } else if ((cu->spacemode==CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) { float curofs= 0.0f; for (i=0; i<=slen; i++) { for (j=i; (mem[j]) && (mem[j]!='\n') && (mem[j]!='\r') && (chartransdata[j].dobreak==0) && (j<slen); j++); if ((mem[j]!='\r') && (mem[j]!='\n') && ((chartransdata[j].dobreak!=0))) { if (mem[i]==' ') curofs += (linedata3[ct->linenr]-linedata[ct->linenr])/linedata4[ct->linenr]; ct->xof+= curofs; } if (mem[i]=='\n' || mem[i]=='\r' || chartransdata[i].dobreak) curofs= 0; ct++; } } } /* TEXT ON CURVE */ /* Note: Only OB_CURVE objects could have a path */ if (cu->textoncurve && cu->textoncurve->type==OB_CURVE) { Curve *cucu= cu->textoncurve->data; int oldflag= cucu->flag; cucu->flag |= (CU_PATH+CU_FOLLOW); if (cucu->path==NULL) makeDispListCurveTypes(scene, cu->textoncurve, 0); if (cucu->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; invert_m4_m4(imat, ob->obmat); copy_m3_m4(imat3, imat); copy_m3_m4(cmat, cu->textoncurve->obmat); mul_m3_m3m3(cmat, cmat, imat3); sizefac= normalize_v3(cmat[0])/cu->fsize; minx=miny= 1.0e20f; maxx=maxy= -1.0e20f; ct= chartransdata; for (i=0; i<=slen; i++, ct++) { if (minx>ct->xof) minx= ct->xof; if (maxx<ct->xof) maxx= ct->xof; if (miny>ct->yof) miny= ct->yof; if (maxy<ct->yof) maxy= ct->yof; } /* we put the x-coordinaat exact at the curve, the y is rotated */ /* length correction */ distfac= sizefac*cucu->path->totdist/(maxx-minx); timeofs= 0.0f; if (distfac > 1.0f) { /* path longer than text: spacemode involves */ distfac= 1.0f/distfac; if (cu->spacemode==CU_RIGHT) { timeofs= 1.0f-distfac; } else if (cu->spacemode==CU_MIDDLE) { timeofs= (1.0f-distfac)/2.0f; } else if (cu->spacemode==CU_FLUSH) distfac= 1.0f; } else distfac= 1.0; distfac/= (maxx-minx); timeofs+= distfac*cu->xof; /* not cyclic */ ct= chartransdata; for (i=0; i<=slen; i++, ct++) { float ctime, dtime, vec[4], tvec[4], rotvec[3]; float si, co; /* rotate around center character */ ascii = mem[i]; che= find_vfont_char(vfd, ascii); twidth = char_width(cu, che, info); dtime= distfac*0.5f*twidth; ctime= timeofs + distfac*( ct->xof - minx); CLAMP(ctime, 0.0f, 1.0f); /* calc the right loc AND the right rot separately */ /* vec, tvec need 4 items */ where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL); where_on_path(cu->textoncurve, ctime+dtime, tvec, rotvec, NULL, NULL, NULL); mul_v3_fl(vec, sizefac); ct->rot= (float)(M_PI-atan2(rotvec[1], rotvec[0])); si= (float)sin(ct->rot); co= (float)cos(ct->rot); yof= ct->yof; ct->xof= vec[0] + si*yof; ct->yof= vec[1] + co*yof; } cucu->flag= oldflag; } } if (cu->selboxes) { ct= chartransdata; for (i=0; i<=selend; i++, ct++) { if (i>=selstart) { cu->selboxes[i-selstart].x = ct->xof*cu->fsize; cu->selboxes[i-selstart].y = ct->yof*cu->fsize; } } } if (mode==FO_CURSUP || mode==FO_CURSDOWN || mode==FO_PAGEUP || mode==FO_PAGEDOWN) { /* 2: curs up * 3: curs down */ ct= chartransdata+cu->pos; if ((mode==FO_CURSUP || mode==FO_PAGEUP) && ct->linenr==0); else if ((mode==FO_CURSDOWN || mode==FO_PAGEDOWN) && ct->linenr==lnr); else { switch(mode) { case FO_CURSUP: lnr= ct->linenr-1; break; case FO_CURSDOWN: lnr= ct->linenr+1; break; case FO_PAGEUP: lnr= ct->linenr-10; break; case FO_PAGEDOWN: lnr= ct->linenr+10; break; } cnr= ct->charnr; /* seek for char with lnr en cnr */ cu->pos= 0; ct= chartransdata; for (i= 0; i<slen; i++) { if (ct->linenr==lnr) { if (ct->charnr==cnr) break; if ( (ct+1)->charnr==0) break; } else if (ct->linenr>lnr) break; cu->pos++; ct++; } } } /* cursor first */ if (cu->editfont) { float si, co; ct= chartransdata+cu->pos; si= (float)sin(ct->rot); co= (float)cos(ct->rot); f= cu->editfont->textcurs[0]; f[0]= cu->fsize*(-0.1f*co + ct->xof); f[1]= cu->fsize*(0.1f*si + ct->yof); f[2]= cu->fsize*(0.1f*co + ct->xof); f[3]= cu->fsize*(-0.1f*si + ct->yof); f[4]= cu->fsize*( 0.1f*co + 0.8f*si + ct->xof); f[5]= cu->fsize*(-0.1f*si + 0.8f*co + ct->yof); f[6]= cu->fsize*(-0.1f*co + 0.8f*si + ct->xof); f[7]= cu->fsize*( 0.1f*si + 0.8f*co + ct->yof); } MEM_freeN(linedata); MEM_freeN(linedata2); MEM_freeN(linedata3); MEM_freeN(linedata4); if (mode == FO_SELCHANGE) { MEM_freeN(chartransdata); MEM_freeN(mem); return NULL; } if (mode == FO_EDIT) { /* make nurbdata */ freeNurblist(&cu->nurb); ct= chartransdata; if (cu->sepchar==0) { for (i= 0; i<slen; i++) { unsigned long cha = (uintptr_t) mem[i]; info = &(custrinfo[i]); if (info->mat_nr > (ob->totcol)) { /* printf("Error: Illegal material index (%d) in text object, setting to 0\n", info->mat_nr); */ info->mat_nr = 0; } // We do not want to see any character for \n or \r if (cha != '\n' && cha != '\r') buildchar(bmain, cu, cha, info, ct->xof, ct->yof, ct->rot, i); if ((info->flag & CU_CHINFO_UNDERLINE) && (cu->textoncurve == NULL) && (cha != '\n') && (cha != '\r')) { float ulwidth, uloverlap= 0.0f; if ( (i<(slen-1)) && (mem[i+1] != '\n') && (mem[i+1] != '\r') && ((mem[i+1] != ' ') || (custrinfo[i+1].flag & CU_CHINFO_UNDERLINE)) && ((custrinfo[i+1].flag & CU_CHINFO_WRAP)==0) ) { uloverlap = xtrax + 0.1f; } // Find the character, the characters has to be in the memory already // since character checking has been done earlier already. che= find_vfont_char(vfd, cha); twidth = char_width(cu, che, info); ulwidth = cu->fsize * ((twidth* (1.0f+(info->kern/40.0f)))+uloverlap); build_underline(cu, ct->xof*cu->fsize, ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize, ct->xof*cu->fsize + ulwidth, ct->yof*cu->fsize + (cu->ulpos-0.05f)*cu->fsize - cu->ulheight*cu->fsize, i, info->mat_nr); } ct++; } } else { int outta = 0; for (i= 0; (i<slen) && (outta==0); i++) { ascii = mem[i]; info = &(custrinfo[i]); if (cu->sepchar == (i+1)) { float vecyo[3]; vecyo[0]= ct->xof; vecyo[1]= ct->yof; vecyo[2]= 0.0f; mem[0] = ascii; mem[1] = 0; custrinfo[0]= *info; cu->pos = 1; cu->len = 1; mul_v3_m4v3(ob->loc, ob->obmat, vecyo); outta = 1; cu->sepchar = 0; } ct++; } } } if (mode==FO_DUPLI) { MEM_freeN(mem); return chartransdata; } if (mem) MEM_freeN(mem); MEM_freeN(chartransdata); return NULL; }
PyObject* BL_ArmatureChannel::py_attr_get_joint_rotation(void *self_v, const struct KX_PYATTRIBUTE_DEF *attrdef) { bPoseChannel* pchan = static_cast<bPoseChannel*>(self_v); // decompose the pose matrix in euler rotation float rest_mat[3][3]; float pose_mat[3][3]; float joint_mat[3][3]; float joints[3]; float norm; double sa, ca; // get rotation in armature space copy_m3_m4(pose_mat, pchan->pose_mat); normalize_m3(pose_mat); if (pchan->parent) { // bone has a parent, compute the rest pose of the bone taking actual pose of parent mult_m3_m3m4(rest_mat, pchan->parent->pose_mat, pchan->bone->bone_mat); normalize_m3(rest_mat); } else { // otherwise, the bone matrix in armature space is the rest pose copy_m3_m4(rest_mat, pchan->bone->arm_mat); } // remove the rest pose to get the joint movement transpose_m3(rest_mat); mul_m3_m3m3(joint_mat, rest_mat, pose_mat); joints[0] = joints[1] = joints[2] = 0.f; // returns a 3 element list that gives corresponding joint 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; switch (flag) { case 0: // fixed joint break; case 1: // X only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[1] = joints[2] = 0.f; break; case 2: // Y only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = joints[2] = 0.f; break; case 3: // X+Y mat3_to_eulO( joints, EULER_ORDER_ZYX,joint_mat); joints[2] = 0.f; break; case 4: // Z only mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = joints[1] = 0.f; break; case 5: // X+Z // decompose this as an equivalent rotation vector in X/Z plane joints[0] = joint_mat[1][2]; joints[2] = -joint_mat[1][0]; norm = normalize_v3(joints); if (norm < FLT_EPSILON) { norm = (joint_mat[1][1] < 0.f) ? M_PI : 0.f; } else { norm = acos(joint_mat[1][1]); } mul_v3_fl(joints, norm); break; case 6: // Y+Z mat3_to_eulO( joints, EULER_ORDER_XYZ,joint_mat); joints[0] = 0.f; break; case 7: // X+Y+Z // equivalent axis joints[0] = (joint_mat[1][2]-joint_mat[2][1])*0.5f; joints[1] = (joint_mat[2][0]-joint_mat[0][2])*0.5f; joints[2] = (joint_mat[0][1]-joint_mat[1][0])*0.5f; sa = len_v3(joints); ca = (joint_mat[0][0]+joint_mat[1][1]+joint_mat[1][1]-1.0f)*0.5f; if (sa > FLT_EPSILON) { norm = atan2(sa,ca)/sa; } else { if (ca < 0.0) { norm = M_PI; mul_v3_fl(joints,0.f); if (joint_mat[0][0] > 0.f) { joints[0] = 1.0f; } else if (joint_mat[1][1] > 0.f) { joints[1] = 1.0f; } else { joints[2] = 1.0f; } } else { norm = 0.0; } } mul_v3_fl(joints,norm); break; } return Vector_CreatePyObject(joints, 3, Py_NEW, NULL); }