diff options
Diffstat (limited to 'source/blender/src/transform_conversions.c')
-rw-r--r-- | source/blender/src/transform_conversions.c | 4343 |
1 files changed, 0 insertions, 4343 deletions
diff --git a/source/blender/src/transform_conversions.c b/source/blender/src/transform_conversions.c deleted file mode 100644 index 496d5120bb9..00000000000 --- a/source/blender/src/transform_conversions.c +++ /dev/null @@ -1,4343 +0,0 @@ -/** - * $Id$ - * - * ***** BEGIN GPL LICENSE BLOCK ***** - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - * - * The Original Code is: all of this file. - * - * Contributor(s): none yet. - * - * ***** END GPL LICENSE BLOCK ***** - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifndef WIN32 -#include <unistd.h> -#else -#include <io.h> -#endif -#include <string.h> -#include <math.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_action_types.h" -#include "DNA_armature_types.h" -#include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_effect_types.h" -#include "DNA_image_types.h" -#include "DNA_ipo_types.h" -#include "DNA_key_types.h" -#include "DNA_lamp_types.h" -#include "DNA_lattice_types.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" -#include "DNA_meta_types.h" -#include "DNA_modifier_types.h" -#include "DNA_nla_types.h" -#include "DNA_object_types.h" -#include "DNA_object_force.h" -#include "DNA_particle_types.h" -#include "DNA_scene_types.h" -#include "DNA_screen_types.h" -#include "DNA_space_types.h" -#include "DNA_texture_types.h" -#include "DNA_view3d_types.h" -#include "DNA_world_types.h" -#include "DNA_userdef_types.h" -#include "DNA_property_types.h" -#include "DNA_vfont_types.h" -#include "DNA_constraint_types.h" -#include "DNA_listBase.h" -#include "DNA_gpencil_types.h" - -#include "BKE_action.h" -#include "BKE_armature.h" -#include "BKE_blender.h" -#include "BKE_cloth.h" -#include "BKE_curve.h" -#include "BKE_constraint.h" -#include "BKE_depsgraph.h" -#include "BKE_displist.h" -#include "BKE_DerivedMesh.h" -#include "BKE_effect.h" -#include "BKE_font.h" -#include "BKE_global.h" -#include "BKE_ipo.h" -#include "BKE_lattice.h" -#include "BKE_key.h" -#include "BKE_main.h" -#include "BKE_mball.h" -#include "BKE_mesh.h" -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_particle.h" -#include "BKE_pointcache.h" -#include "BKE_softbody.h" -#include "BKE_utildefines.h" -#include "BKE_bmesh.h" - -#include "BIF_editaction.h" -#include "BIF_editview.h" -#include "BIF_editlattice.h" -#include "BIF_editconstraint.h" -#include "BIF_editarmature.h" -#include "BIF_editmesh.h" -#include "BIF_editnla.h" -#include "BIF_editsima.h" -#include "BIF_editparticle.h" -#include "BIF_gl.h" -#include "BIF_keyframing.h" -#include "BIF_poseobject.h" -#include "BIF_meshtools.h" -#include "BIF_mywindow.h" -#include "BIF_resources.h" -#include "BIF_retopo.h" -#include "BIF_screen.h" -#include "BIF_space.h" -#include "BIF_toolbox.h" - -#include "BSE_view.h" -#include "BSE_drawipo.h" -#include "BSE_edit.h" -#include "BSE_editipo.h" -#include "BSE_editipo_types.h" -#include "BSE_editaction_types.h" - -#include "BDR_drawaction.h" // list of keyframes in action -#include "BDR_editobject.h" // reset_slowparents() -#include "BDR_gpencil.h" -#include "BDR_unwrapper.h" - -#include "BLI_arithb.h" -#include "BLI_blenlib.h" -#include "BLI_editVert.h" - -#include "editmesh.h" - -#include "blendef.h" - -#include "mydevice.h" - -extern ListBase editNurb; -extern ListBase editelems; - -#include "transform.h" - -#include "BLO_sys_types.h" // for intptr_t support - -/* local function prototype - for Object/Bone Constraints */ -static short constraints_list_needinv(TransInfo *t, ListBase *list); -/* local function prototype - for finding number of keyframes that are selected for editing */ -static int count_ipo_keys(Ipo *ipo, char side, float cfra); - -/* ************************** Functions *************************** */ - -static void qsort_trans_data(TransInfo *t, TransData *head, TransData *tail) { - TransData pivot = *head; - TransData *ihead = head; - TransData *itail = tail; - short connected = t->flag & T_PROP_CONNECTED; - - while (head < tail) - { - if (connected) { - while ((tail->dist >= pivot.dist) && (head < tail)) - tail--; - } - else { - while ((tail->rdist >= pivot.rdist) && (head < tail)) - tail--; - } - - if (head != tail) - { - *head = *tail; - head++; - } - - if (connected) { - while ((head->dist <= pivot.dist) && (head < tail)) - head++; - } - else { - while ((head->rdist <= pivot.rdist) && (head < tail)) - head++; - } - - if (head != tail) - { - *tail = *head; - tail--; - } - } - - *head = pivot; - if (ihead < head) { - qsort_trans_data(t, ihead, head-1); - } - if (itail > head) { - qsort_trans_data(t, head+1, itail); - } -} - -void sort_trans_data_dist(TransInfo *t) { - TransData *start = t->data; - int i = 1; - - while(i < t->total && start->flag & TD_SELECTED) { - start++; - i++; - } - qsort_trans_data(t, start, t->data + t->total - 1); -} - -static void sort_trans_data(TransInfo *t) -{ - TransData *sel, *unsel; - TransData temp; - unsel = t->data; - sel = t->data; - sel += t->total - 1; - while (sel > unsel) { - while (unsel->flag & TD_SELECTED) { - unsel++; - if (unsel == sel) { - return; - } - } - while (!(sel->flag & TD_SELECTED)) { - sel--; - if (unsel == sel) { - return; - } - } - temp = *unsel; - *unsel = *sel; - *sel = temp; - sel--; - unsel++; - } -} - -/* distance calculated from not-selected vertex to nearest selected vertex - warning; this is loops inside loop, has minor N^2 issues, but by sorting list it is OK */ -static void set_prop_dist(TransInfo *t, short with_dist) -{ - TransData *tob; - int a; - - for(a=0, tob= t->data; a<t->total; a++, tob++) { - - tob->rdist= 0.0f; // init, it was mallocced - - if((tob->flag & TD_SELECTED)==0) { - TransData *td; - int i; - float dist, vec[3]; - - tob->rdist = -1.0f; // signal for next loop - - for (i = 0, td= t->data; i < t->total; i++, td++) { - if(td->flag & TD_SELECTED) { - VecSubf(vec, tob->center, td->center); - Mat3MulVecfl(tob->mtx, vec); - dist = Normalize(vec); - if (tob->rdist == -1.0f) { - tob->rdist = dist; - } - else if (dist < tob->rdist) { - tob->rdist = dist; - } - } - else break; // by definition transdata has selected items in beginning - } - if (with_dist) { - tob->dist = tob->rdist; - } - } - } -} - -/* ************************** CONVERSIONS ************************* */ - -/* ********************* texture space ********* */ - -static void createTransTexspace(TransInfo *t) -{ - TransData *td; - Object *ob; - ID *id; - int *texflag; - - ob= OBACT; - - if (ob==NULL) { // Shouldn't logically happen, but still... - t->total = 0; - return; - } - - id= ob->data; - if(id==NULL || !ELEM3( GS(id->name), ID_ME, ID_CU, ID_MB )) { - t->total = 0; - return; - } - - t->total = 1; - td= t->data= MEM_callocN(sizeof(TransData), "TransTexspace"); - td->ext= t->ext= MEM_callocN(sizeof(TransDataExtension), "TransTexspace"); - - td->flag= TD_SELECTED; - VECCOPY(td->center, ob->obmat[3]); - td->ob = ob; - - Mat3CpyMat4(td->mtx, ob->obmat); - Mat3CpyMat4(td->axismtx, ob->obmat); - Mat3Ortho(td->axismtx); - Mat3Inv(td->smtx, td->mtx); - - if (give_obdata_texspace(ob, &texflag, &td->loc, &td->ext->size, &td->ext->rot)) { - *texflag &= ~AUTOSPACE; - } - - VECCOPY(td->iloc, td->loc); - VECCOPY(td->ext->irot, td->ext->rot); - VECCOPY(td->ext->isize, td->ext->size); -} - -/* ********************* edge (for crease) ***** */ - -static void createTransEdge(TransInfo *t) { - TransData *td = NULL; - EditMesh *em = G.editMesh; - EditEdge *eed; - float mtx[3][3], smtx[3][3]; - int count=0, countsel=0; - int propmode = t->flag & T_PROP_EDIT; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - if (eed->f & SELECT) countsel++; - if (propmode) count++; - } - } - - if (countsel == 0) - return; - - if(propmode) { - t->total = count; - } - else { - t->total = countsel; - } - - td= t->data= MEM_callocN(t->total * sizeof(TransData), "TransCrease"); - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT || propmode)) { - /* need to set center for center calculations */ - VecAddf(td->center, eed->v1->co, eed->v2->co); - VecMulf(td->center, 0.5f); - - td->loc= NULL; - if (eed->f & SELECT) - td->flag= TD_SELECTED; - else - td->flag= 0; - - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->ext = NULL; - td->tdi = NULL; - if (t->mode == TFM_BWEIGHT) { - td->val = &(eed->bweight); - td->ival = eed->bweight; - } - else { - td->val = &(eed->crease); - td->ival = eed->crease; - } - - td++; - } - } -} - -/* ********************* pose mode ************* */ - -static bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan) -{ - bConstraint *con= pchan->constraints.first; - - for(;con; con= con->next) { - if(con->type==CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) { - bKinematicConstraint *data= con->data; - - if(data->tar==NULL) - return data; - if(data->tar->type==OB_ARMATURE && data->subtarget[0]==0) - return data; - } - } - return NULL; -} - -static short apply_targetless_ik(Object *ob) -{ - bPoseChannel *pchan, *parchan, *chanlist[256]; - bKinematicConstraint *data; - int segcount, apply= 0; - - /* now we got a difficult situation... we have to find the - target-less IK pchans, and apply transformation to the all - pchans that were in the chain */ - - for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { - data= has_targetless_ik(pchan); - if(data && (data->flag & CONSTRAINT_IK_AUTO)) { - - /* fill the array with the bones of the chain (armature.c does same, keep it synced) */ - segcount= 0; - - /* exclude tip from chain? */ - if(!(data->flag & CONSTRAINT_IK_TIP)) - parchan= pchan->parent; - else - parchan= pchan; - - /* Find the chain's root & count the segments needed */ - for (; parchan; parchan=parchan->parent){ - chanlist[segcount]= parchan; - segcount++; - - if(segcount==data->rootbone || segcount>255) break; // 255 is weak - } - for(;segcount;segcount--) { - Bone *bone; - float rmat[4][4], tmat[4][4], imat[4][4]; - - /* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */ - /* we put in channel the entire result of rmat= (channel * constraint * IK) */ - /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */ - /* rmat = pose_mat(b) * inv( pose_mat(b-1) * offs_bone ) */ - - parchan= chanlist[segcount-1]; - bone= parchan->bone; - bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */ - - if(parchan->parent) { - Bone *parbone= parchan->parent->bone; - float offs_bone[4][4]; - - /* offs_bone = yoffs(b-1) + root(b) + bonemat(b) */ - Mat4CpyMat3(offs_bone, bone->bone_mat); - - /* The bone's root offset (is in the parent's coordinate system) */ - VECCOPY(offs_bone[3], bone->head); - - /* Get the length translation of parent (length along y axis) */ - offs_bone[3][1]+= parbone->length; - - /* pose_mat(b-1) * offs_bone */ - if(parchan->bone->flag & BONE_HINGE) { - /* the rotation of the parent restposition */ - Mat4CpyMat4(rmat, parbone->arm_mat); /* rmat used as temp */ - - /* the location of actual parent transform */ - VECCOPY(rmat[3], offs_bone[3]); - offs_bone[3][0]= offs_bone[3][1]= offs_bone[3][2]= 0.0f; - Mat4MulVecfl(parchan->parent->pose_mat, rmat[3]); - - Mat4MulMat4(tmat, offs_bone, rmat); - } - else if(parchan->bone->flag & BONE_NO_SCALE) { - Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat); - Mat4Ortho(tmat); - } - else - Mat4MulMat4(tmat, offs_bone, parchan->parent->pose_mat); - - Mat4Invert(imat, tmat); - } - else { - Mat4CpyMat3(tmat, bone->bone_mat); - - VECCOPY(tmat[3], bone->head); - Mat4Invert(imat, tmat); - } - /* result matrix */ - Mat4MulMat4(rmat, parchan->pose_mat, imat); - - /* apply and decompose, doesn't work for constraints or non-uniform scale well */ - { - float rmat3[3][3], qmat[3][3], imat[3][3], smat[3][3]; - - Mat3CpyMat4(rmat3, rmat); - - /* quaternion */ - Mat3ToQuat(rmat3, parchan->quat); - - /* for size, remove rotation */ - /* causes problems with some constraints (so apply only if needed) */ - if (data->flag & CONSTRAINT_IK_STRETCH) { - QuatToMat3(parchan->quat, qmat); - Mat3Inv(imat, qmat); - Mat3MulMat3(smat, rmat3, imat); - Mat3ToSize(smat, parchan->size); - } - - /* causes problems with some constraints (e.g. childof), so disable this */ - /* as it is IK shouldn't affect location directly */ - /* VECCOPY(parchan->loc, rmat[3]); */ - } - - } - - apply= 1; - data->flag &= ~CONSTRAINT_IK_AUTO; - } - } - - return apply; -} - -static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, TransData *td) -{ - Bone *bone= pchan->bone; - float pmat[3][3], omat[3][3]; - float cmat[3][3], tmat[3][3]; - float vec[3]; - - VECCOPY(vec, pchan->pose_mat[3]); - VECCOPY(td->center, vec); - - td->ob = ob; - td->flag= TD_SELECTED|TD_USEQUAT; - if (bone->flag & BONE_HINGE_CHILD_TRANSFORM) - { - td->flag |= TD_NOCENTER; - } - - if (bone->flag & BONE_TRANSFORM_CHILD) - { - td->flag |= TD_NOCENTER; - td->flag |= TD_NO_LOC; - } - - td->protectflag= pchan->protectflag; - - td->loc = pchan->loc; - VECCOPY(td->iloc, pchan->loc); - - td->ext->rot= NULL; - td->ext->quat= pchan->quat; - td->ext->size= pchan->size; - - QUATCOPY(td->ext->iquat, pchan->quat); - VECCOPY(td->ext->isize, pchan->size); - - /* proper way to get parent transform + own transform + constraints transform */ - Mat3CpyMat4(omat, ob->obmat); - - if(pchan->parent) { - if(pchan->bone->flag & BONE_HINGE) - Mat3CpyMat4(pmat, pchan->parent->bone->arm_mat); - else - Mat3CpyMat4(pmat, pchan->parent->pose_mat); - - if (constraints_list_needinv(t, &pchan->constraints)) { - Mat3CpyMat4(tmat, pchan->constinv); - Mat3Inv(cmat, tmat); - Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, cmat, 0,0,0,0); // dang mulserie swaps args - } - else - Mat3MulSerie(td->mtx, pchan->bone->bone_mat, pmat, omat, 0,0,0,0,0); // dang mulserie swaps args - } - else { - if (constraints_list_needinv(t, &pchan->constraints)) { - Mat3CpyMat4(tmat, pchan->constinv); - Mat3Inv(cmat, tmat); - Mat3MulSerie(td->mtx, pchan->bone->bone_mat, omat, cmat, 0,0,0,0,0); // dang mulserie swaps args - } - else - Mat3MulMat3(td->mtx, omat, pchan->bone->bone_mat); // Mat3MulMat3 has swapped args! - } - - Mat3Inv(td->smtx, td->mtx); - - /* for axismat we use bone's own transform */ - Mat3CpyMat4(pmat, pchan->pose_mat); - Mat3MulMat3(td->axismtx, omat, pmat); - Mat3Ortho(td->axismtx); - - if(t->mode==TFM_BONESIZE) { - bArmature *arm= t->poseobj->data; - - if(arm->drawtype==ARM_ENVELOPE) { - td->loc= NULL; - td->val= &bone->dist; - td->ival= bone->dist; - } - else { - // abusive storage of scale in the loc pointer :) - td->loc= &bone->xwidth; - VECCOPY (td->iloc, td->loc); - td->val= NULL; - } - } - - /* in this case we can do target-less IK grabbing */ - if(t->mode==TFM_TRANSLATION) { - bKinematicConstraint *data= has_targetless_ik(pchan); - if(data) { - if(data->flag & CONSTRAINT_IK_TIP) { - VECCOPY(data->grabtarget, pchan->pose_tail); - } - else { - VECCOPY(data->grabtarget, pchan->pose_head); - } - td->loc = data->grabtarget; - VECCOPY(td->iloc, td->loc); - data->flag |= CONSTRAINT_IK_AUTO; - - /* only object matrix correction */ - Mat3CpyMat3 (td->mtx, omat); - Mat3Inv (td->smtx, td->mtx); - } - } - - /* store reference to first constraint */ - td->con= pchan->constraints.first; -} - -static void bone_children_clear_transflag(TransInfo *t, ListBase *lb) -{ - Bone *bone= lb->first; - - for(;bone;bone= bone->next) { - if((bone->flag & BONE_HINGE) && (bone->flag & BONE_CONNECTED)) - { - bone->flag |= BONE_HINGE_CHILD_TRANSFORM; - } - else if (bone->flag & BONE_TRANSFORM && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) - { - bone->flag |= BONE_TRANSFORM_CHILD; - } - else - { - bone->flag &= ~BONE_TRANSFORM; - } - - bone_children_clear_transflag(t, &bone->childbase); - } -} - -/* sets transform flags in the bones, returns total */ -static void set_pose_transflags(TransInfo *t, Object *ob) -{ - bArmature *arm= ob->data; - bPoseChannel *pchan; - Bone *bone; - int hastranslation; - - t->total= 0; - - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - bone= pchan->bone; - if(bone->layer & arm->layer) { - if(bone->flag & BONE_SELECTED) - bone->flag |= BONE_TRANSFORM; - else - bone->flag &= ~BONE_TRANSFORM; - - bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM; - bone->flag &= ~BONE_TRANSFORM_CHILD; - } - } - - /* make sure no bone can be transformed when a parent is transformed */ - /* since pchans are depsgraph sorted, the parents are in beginning of list */ - if(t->mode!=TFM_BONESIZE) { - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - bone= pchan->bone; - if(bone->flag & BONE_TRANSFORM) - bone_children_clear_transflag(t, &bone->childbase); - } - } - /* now count, and check if we have autoIK or have to switch from translate to rotate */ - hastranslation= 0; - - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - bone= pchan->bone; - if(bone->flag & BONE_TRANSFORM) { - - t->total++; - - if(t->mode==TFM_TRANSLATION) { - if( has_targetless_ik(pchan)==NULL ) { - if(pchan->parent && (pchan->bone->flag & BONE_CONNECTED)) { - if(pchan->bone->flag & BONE_HINGE_CHILD_TRANSFORM) - hastranslation= 1; - } - else if((pchan->protectflag & OB_LOCK_LOC)!=OB_LOCK_LOC) - hastranslation= 1; - } - else - hastranslation= 1; - } - } - } - - /* if there are no translatable bones, do rotation */ - if(t->mode==TFM_TRANSLATION && !hastranslation) - t->mode= TFM_ROTATION; -} - - -/* -------- Auto-IK ---------- */ - -/* adjust pose-channel's auto-ik chainlen */ -static void pchan_autoik_adjust (bPoseChannel *pchan, short chainlen) -{ - bConstraint *con; - - /* don't bother to search if no valid constraints */ - if ((pchan->constflag & (PCHAN_HAS_IK|PCHAN_HAS_TARGET))==0) - return; - - /* check if pchan has ik-constraint */ - for (con= pchan->constraints.first; con; con= con->next) { - if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce!=0.0)) { - bKinematicConstraint *data= con->data; - - /* only accept if a temporary one (for auto-ik) */ - if (data->flag & CONSTRAINT_IK_TEMP) { - /* chainlen is new chainlen, but is limited by maximum chainlen */ - if ((chainlen==0) || (chainlen > data->max_rootbone)) - data->rootbone= data->max_rootbone; - else - data->rootbone= chainlen; - } - } - } -} - -/* change the chain-length of auto-ik */ -void transform_autoik_update (TransInfo *t, short mode) -{ - short *chainlen= &G.scene->toolsettings->autoik_chainlen; - bPoseChannel *pchan; - - /* mode determines what change to apply to chainlen */ - if (mode == 1) { - /* mode=1 is from WHEELMOUSEDOWN... increases len */ - (*chainlen)++; - } - else if (mode == -1) { - /* mode==-1 is from WHEELMOUSEUP... decreases len */ - if (*chainlen > 0) (*chainlen)--; - } - - /* sanity checks (don't assume t->poseobj is set, or that it is an armature) */ - if (ELEM(NULL, t->poseobj, t->poseobj->pose)) - return; - - /* apply to all pose-channels */ - for (pchan=t->poseobj->pose->chanbase.first; pchan; pchan=pchan->next) { - pchan_autoik_adjust(pchan, *chainlen); - } -} - -/* frees temporal IKs */ -static void pose_grab_with_ik_clear(Object *ob) -{ - bKinematicConstraint *data; - bPoseChannel *pchan; - bConstraint *con; - - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - /* clear all temporary lock flags */ - pchan->ikflag &= ~(BONE_IK_NO_XDOF_TEMP|BONE_IK_NO_YDOF_TEMP|BONE_IK_NO_ZDOF_TEMP); - - pchan->constflag &= ~(PCHAN_HAS_IK|PCHAN_HAS_TARGET); - /* remove all temporary IK-constraints added */ - for (con= pchan->constraints.first; con; con= con->next) { - if (con->type==CONSTRAINT_TYPE_KINEMATIC) { - data= con->data; - if (data->flag & CONSTRAINT_IK_TEMP) { - BLI_remlink(&pchan->constraints, con); - MEM_freeN(con->data); - MEM_freeN(con); - continue; - } - pchan->constflag |= PCHAN_HAS_IK; - if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) - pchan->constflag |= PCHAN_HAS_TARGET; - } - } - } -} - -/* adds the IK to pchan - returns if added */ -static short pose_grab_with_ik_add(bPoseChannel *pchan) -{ - bKinematicConstraint *data; - bConstraint *con; - bConstraint *targetless = 0; - - /* Sanity check */ - if (pchan == NULL) - return 0; - - /* Rule: not if there's already an IK on this channel */ - for (con= pchan->constraints.first; con; con= con->next) { - if (con->type==CONSTRAINT_TYPE_KINEMATIC) { - bKinematicConstraint *data= con->data; - if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) { - targetless = con; - /* but, if this is a targetless IK, we make it auto anyway (for the children loop) */ - if (con->enforce!=0.0) { - targetless->flag |= CONSTRAINT_IK_AUTO; - return 0; - } - } - if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) - return 0; - } - } - - con = add_new_constraint(CONSTRAINT_TYPE_KINEMATIC); - BLI_addtail(&pchan->constraints, con); - pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */ - data= con->data; - if (targetless) { /* if exists use values from last targetless IK-constraint as base */ - *data = *((bKinematicConstraint*)targetless->data); - } - else - data->flag= CONSTRAINT_IK_TIP; - data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO; - VECCOPY(data->grabtarget, pchan->pose_tail); - data->rootbone= 1; - - /* we include only a connected chain */ - while ((pchan) && (pchan->bone->flag & BONE_CONNECTED)) { - /* here, we set ik-settings for bone from pchan->protectflag */ - if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP; - if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP; - if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP; - - /* now we count this pchan as being included */ - data->rootbone++; - pchan= pchan->parent; - } - - /* make a copy of maximum chain-length */ - data->max_rootbone= data->rootbone; - - return 1; -} - -/* bone is a candidate to get IK, but we don't do it if it has children connected */ -static short pose_grab_with_ik_children(bPose *pose, Bone *bone) -{ - Bone *bonec; - short wentdeeper=0, added=0; - - /* go deeper if children & children are connected */ - for (bonec= bone->childbase.first; bonec; bonec= bonec->next) { - if (bonec->flag & BONE_CONNECTED) { - wentdeeper= 1; - added+= pose_grab_with_ik_children(pose, bonec); - } - } - if (wentdeeper==0) { - bPoseChannel *pchan= get_pose_channel(pose, bone->name); - if (pchan) - added+= pose_grab_with_ik_add(pchan); - } - - return added; -} - -/* main call which adds temporal IK chains */ -static short pose_grab_with_ik(Object *ob) -{ - bArmature *arm; - bPoseChannel *pchan, *parent; - Bone *bonec; - short tot_ik= 0; - - if ((ob==NULL) || (ob->pose==NULL) || (ob->flag & OB_POSEMODE)==0) - return 0; - - arm = ob->data; - - /* Rule: allow multiple Bones (but they must be selected, and only one ik-solver per chain should get added) */ - for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if (pchan->bone->layer & arm->layer) { - if (pchan->bone->flag & BONE_SELECTED) { - /* Rule: no IK for solitatry (unconnected) bones */ - for (bonec=pchan->bone->childbase.first; bonec; bonec=bonec->next) { - if (bonec->flag & BONE_CONNECTED) { - break; - } - } - if ((pchan->bone->flag & BONE_CONNECTED)==0 && (bonec == NULL)) - continue; - - /* rule: if selected Bone is not a root bone, it gets a temporal IK */ - if (pchan->parent) { - /* only adds if there's no IK yet (and no parent bone was selected) */ - for (parent= pchan->parent; parent; parent= parent->parent) { - if (parent->bone->flag & BONE_SELECTED) - break; - } - if (parent == NULL) - tot_ik += pose_grab_with_ik_add(pchan); - } - else { - /* rule: go over the children and add IK to the tips */ - tot_ik += pose_grab_with_ik_children(ob->pose, pchan->bone); - } - } - } - } - - return (tot_ik) ? 1 : 0; -} - - -/* only called with pose mode active object now */ -static void createTransPose(TransInfo *t, Object *ob) -{ - bArmature *arm; - bPoseChannel *pchan; - TransData *td; - TransDataExtension *tdx; - short ik_on= 0; - int i; - - t->total= 0; - - /* check validity of state */ - arm=get_armature (ob); - if (arm==NULL || ob->pose==NULL) return; - - if (arm->flag & ARM_RESTPOS) { - if(ELEM(t->mode, TFM_DUMMY, TFM_BONESIZE)==0) { - notice("Pose edit not possible while Rest Position is enabled"); - return; - } - } - if (!(ob->lay & G.vd->lay)) return; - - /* do we need to add temporal IK chains? */ - if ((arm->flag & ARM_AUTO_IK) && t->mode==TFM_TRANSLATION) { - ik_on= pose_grab_with_ik(ob); - if (ik_on) t->flag |= T_AUTOIK; - } - - /* set flags and count total (warning, can change transform to rotate) */ - set_pose_transflags(t, ob); - - if(t->total==0) return; - - t->flag |= T_POSE; - t->poseobj= ob; /* we also allow non-active objects to be transformed, in weightpaint */ - - /* make sure the lock is set OK, unlock can be accidentally saved? */ - ob->pose->flag |= POSE_LOCKED; - ob->pose->flag &= ~POSE_DO_UNLOCK; - - /* init trans data */ - td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransPoseBone"); - tdx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransPoseBoneExt"); - for(i=0; i<t->total; i++, td++, tdx++) { - td->ext= tdx; - td->tdi = NULL; - td->val = NULL; - } - - /* use pose channels to fill trans data */ - td= t->data; - for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { - if(pchan->bone->flag & BONE_TRANSFORM) { - add_pose_transdata(t, pchan, ob, td); - td++; - } - } - - if(td != (t->data+t->total)) printf("Bone selection count error\n"); - - /* initialise initial auto=ik chainlen's? */ - if (ik_on) transform_autoik_update(t, 0); -} - -/* ********************* armature ************** */ - -static void createTransArmatureVerts(TransInfo *t) -{ - EditBone *ebo; - bArmature *arm= G.obedit->data; - TransData *td; - float mtx[3][3], smtx[3][3], delta[3], bonemat[3][3]; - - t->total = 0; - for (ebo=G.edbo.first;ebo;ebo=ebo->next) { - if(ebo->layer & arm->layer) { - if (t->mode==TFM_BONESIZE) { - if (ebo->flag & BONE_SELECTED) - t->total++; - } - else if (t->mode==TFM_BONE_ROLL) { - if (ebo->flag & BONE_SELECTED) - t->total++; - } - else { - if (ebo->flag & BONE_TIPSEL) - t->total++; - if (ebo->flag & BONE_ROOTSEL) - t->total++; - } - } - } - - if (!t->total) return; - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransEditBone"); - - for (ebo=G.edbo.first;ebo;ebo=ebo->next){ - ebo->oldlength= ebo->length; // length==0.0 on extrude, used for scaling radius of bone points - - if(ebo->layer & arm->layer) { - if (t->mode==TFM_BONE_ENVELOPE) { - - if (ebo->flag & BONE_ROOTSEL){ - td->val= &ebo->rad_head; - td->ival= *td->val; - - VECCOPY (td->center, ebo->head); - td->flag= TD_SELECTED; - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->loc = NULL; - td->ext = NULL; - td->tdi = NULL; - - td++; - } - if (ebo->flag & BONE_TIPSEL){ - td->val= &ebo->rad_tail; - td->ival= *td->val; - VECCOPY (td->center, ebo->tail); - td->flag= TD_SELECTED; - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->loc = NULL; - td->ext = NULL; - td->tdi = NULL; - - td++; - } - - } - else if (t->mode==TFM_BONESIZE) { - if (ebo->flag & BONE_SELECTED) { - if(arm->drawtype==ARM_ENVELOPE) { - td->loc= NULL; - td->val= &ebo->dist; - td->ival= ebo->dist; - } - else { - // abusive storage of scale in the loc pointer :) - td->loc= &ebo->xwidth; - VECCOPY (td->iloc, td->loc); - td->val= NULL; - } - VECCOPY (td->center, ebo->head); - td->flag= TD_SELECTED; - - /* use local bone matrix */ - VecSubf(delta, ebo->tail, ebo->head); - vec_roll_to_mat3(delta, ebo->roll, bonemat); - Mat3MulMat3(td->mtx, mtx, bonemat); - Mat3Inv(td->smtx, td->mtx); - - Mat3CpyMat3(td->axismtx, td->mtx); - Mat3Ortho(td->axismtx); - - td->ext = NULL; - td->tdi = NULL; - - td++; - } - } - else if (t->mode==TFM_BONE_ROLL) { - if (ebo->flag & BONE_SELECTED) { - td->loc= NULL; - td->val= &(ebo->roll); - td->ival= ebo->roll; - - VECCOPY (td->center, ebo->head); - td->flag= TD_SELECTED; - - td->ext = NULL; - td->tdi = NULL; - - td++; - } - } - else { - if (ebo->flag & BONE_TIPSEL){ - VECCOPY (td->iloc, ebo->tail); - VECCOPY (td->center, td->iloc); - td->loc= ebo->tail; - td->flag= TD_SELECTED; - if (ebo->flag & BONE_EDITMODE_LOCKED) - td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE; - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - - td++; - } - if (ebo->flag & BONE_ROOTSEL){ - VECCOPY (td->iloc, ebo->head); - VECCOPY (td->center, td->iloc); - td->loc= ebo->head; - td->flag= TD_SELECTED; - if (ebo->flag & BONE_EDITMODE_LOCKED) - td->protectflag = OB_LOCK_LOC|OB_LOCK_ROT|OB_LOCK_SCALE; - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - - td++; - } - } - } - } -} - -/* ********************* meta elements ********* */ - -static void createTransMBallVerts(TransInfo *t) -{ - MetaElem *ml; - TransData *td; - TransDataExtension *tx; - float mtx[3][3], smtx[3][3]; - int count=0, countsel=0; - int propmode = t->flag & T_PROP_EDIT; - - /* count totals */ - for(ml= editelems.first; ml; ml= ml->next) { - if(ml->flag & SELECT) countsel++; - if(propmode) count++; - } - - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; - - if(propmode) t->total = count; - else t->total = countsel; - - td = t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(MBall EditMode)"); - tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "MetaElement_TransExtension"); - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - for(ml= editelems.first; ml; ml= ml->next) { - if(propmode || (ml->flag & SELECT)) { - td->loc= &ml->x; - VECCOPY(td->iloc, td->loc); - VECCOPY(td->center, td->loc); - - if(ml->flag & SELECT) td->flag= TD_SELECTED | TD_USEQUAT | TD_SINGLESIZE; - else td->flag= TD_USEQUAT; - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->ext = tx; - td->tdi = NULL; - - /* Radius of MetaElem (mass of MetaElem influence) */ - if(ml->flag & MB_SCALE_RAD){ - td->val = &ml->rad; - td->ival = ml->rad; - } - else{ - td->val = &ml->s; - td->ival = ml->s; - } - - /* expx/expy/expz determine "shape" of some MetaElem types */ - tx->size = &ml->expx; - tx->isize[0] = ml->expx; - tx->isize[1] = ml->expy; - tx->isize[2] = ml->expz; - - /* quat is used for rotation of MetaElem */ - tx->quat = ml->quat; - QUATCOPY(tx->iquat, ml->quat); - - tx->rot = NULL; - - td++; - tx++; - } - } -} - -/* ********************* curve/surface ********* */ - -static void calc_distanceCurveVerts(TransData *head, TransData *tail) { - TransData *td, *td_near = NULL; - for (td = head; td<=tail; td++) { - if (td->flag & TD_SELECTED) { - td_near = td; - td->dist = 0.0f; - } - else if(td_near) { - float dist; - dist = VecLenf(td_near->center, td->center); - if (dist < (td-1)->dist) { - td->dist = (td-1)->dist; - } - else { - td->dist = dist; - } - } - else { - td->dist = MAXFLOAT; - td->flag |= TD_NOTCONNECTED; - } - } - td_near = NULL; - for (td = tail; td>=head; td--) { - if (td->flag & TD_SELECTED) { - td_near = td; - td->dist = 0.0f; - } - else if(td_near) { - float dist; - dist = VecLenf(td_near->center, td->center); - if (td->flag & TD_NOTCONNECTED || dist < td->dist || (td+1)->dist < td->dist) { - td->flag &= ~TD_NOTCONNECTED; - if (dist < (td+1)->dist) { - td->dist = (td+1)->dist; - } - else { - td->dist = dist; - } - } - } - } -} - -/* Utility function for getting the handle data from bezier's */ -TransDataCurveHandleFlags *initTransDataCurveHandes(TransData *td, struct BezTriple *bezt) { - TransDataCurveHandleFlags *hdata; - td->flag |= TD_BEZTRIPLE; - hdata = td->hdata = MEM_mallocN(sizeof(TransDataCurveHandleFlags), "CuHandle Data"); - hdata->ih1 = bezt->h1; - hdata->h1 = &bezt->h1; - hdata->ih2 = bezt->h2; /* incase the second is not selected */ - hdata->h2 = &bezt->h2; - return hdata; -} - -static void createTransCurveVerts(TransInfo *t) -{ - TransData *td = NULL; - Nurb *nu; - BezTriple *bezt; - BPoint *bp; - float mtx[3][3], smtx[3][3]; - int a; - int count=0, countsel=0; - int propmode = t->flag & T_PROP_EDIT; - - /* count total of vertices, check identical as in 2nd loop for making transdata! */ - for(nu= editNurb.first; nu; nu= nu->next) { - if((nu->type & 7)==CU_BEZIER) { - for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) { - if(bezt->hide==0) { - if (G.f & G_HIDDENHANDLES) { - if(bezt->f2 & SELECT) countsel+=3; - if(propmode) count+= 3; - } else { - if(bezt->f1 & SELECT) countsel++; - if(bezt->f2 & SELECT) countsel++; - if(bezt->f3 & SELECT) countsel++; - if(propmode) count+= 3; - } - } - } - } - else { - for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) { - if(bp->hide==0) { - if(propmode) count++; - if(bp->f1 & SELECT) countsel++; - } - } - } - } - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; - - if(propmode) t->total = count; - else t->total = countsel; - t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Curve EditMode)"); - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - td = t->data; - for(nu= editNurb.first; nu; nu= nu->next) { - if((nu->type & 7)==CU_BEZIER) { - TransData *head, *tail; - head = tail = td; - for(a=0, bezt= nu->bezt; a<nu->pntsu; a++, bezt++) { - if(bezt->hide==0) { - TransDataCurveHandleFlags *hdata = NULL; - - if( propmode || - ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) || - ((bezt->f1 & SELECT) && (G.f & G_HIDDENHANDLES)==0) - ) { - VECCOPY(td->iloc, bezt->vec[0]); - td->loc= bezt->vec[0]; - VECCOPY(td->center, bezt->vec[1]); - if (G.f & G_HIDDENHANDLES) { - if(bezt->f2 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - } else { - if(bezt->f1 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - } - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - - hdata = initTransDataCurveHandes(td, bezt); - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td++; - count++; - tail++; - } - - /* This is the Curve Point, the other two are handles */ - if(propmode || (bezt->f2 & SELECT)) { - VECCOPY(td->iloc, bezt->vec[1]); - td->loc= bezt->vec[1]; - VECCOPY(td->center, td->loc); - if(bezt->f2 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - td->ext = NULL; - td->tdi = NULL; - - if (t->mode==TFM_CURVE_SHRINKFATTEN) { /* || t->mode==TFM_RESIZE) {*/ /* TODO - make points scale */ - td->val = &(bezt->radius); - td->ival = bezt->radius; - } else if (t->mode==TFM_TILT) { - td->val = &(bezt->alfa); - td->ival = bezt->alfa; - } else { - td->val = NULL; - } - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - if ((bezt->f1&SELECT)==0 && (bezt->f3&SELECT)==0) - /* If the middle is selected but the sides arnt, this is needed */ - if (hdata==NULL) { /* if the handle was not saved by the previous handle */ - hdata = initTransDataCurveHandes(td, bezt); - } - - td++; - count++; - tail++; - } - if( propmode || - ((bezt->f2 & SELECT) && (G.f & G_HIDDENHANDLES)) || - ((bezt->f3 & SELECT) && (G.f & G_HIDDENHANDLES)==0) - ) { - VECCOPY(td->iloc, bezt->vec[2]); - td->loc= bezt->vec[2]; - VECCOPY(td->center, bezt->vec[1]); - if (G.f & G_HIDDENHANDLES) { - if(bezt->f2 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - } else { - if(bezt->f3 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - } - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - - if (hdata==NULL) { /* if the handle was not saved by the previous handle */ - hdata = initTransDataCurveHandes(td, bezt); - } - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td++; - count++; - tail++; - } - } - else if (propmode && head != tail) { - calc_distanceCurveVerts(head, tail-1); - head = tail; - } - } - if (propmode && head != tail) - calc_distanceCurveVerts(head, tail-1); - - /* TODO - in the case of tilt and radius we can also avoid allocating the initTransDataCurveHandes - * but for now just dont change handle types */ - if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT) == 0) - testhandlesNurb(nu); /* sets the handles based on their selection, do this after the data is copied to the TransData */ - } - else { - TransData *head, *tail; - head = tail = td; - for(a= nu->pntsu*nu->pntsv, bp= nu->bp; a>0; a--, bp++) { - if(bp->hide==0) { - if(propmode || (bp->f1 & SELECT)) { - VECCOPY(td->iloc, bp->vec); - td->loc= bp->vec; - VECCOPY(td->center, td->loc); - if(bp->f1 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - td->ext = NULL; - td->tdi = NULL; - - if (t->mode==TFM_CURVE_SHRINKFATTEN || t->mode==TFM_RESIZE) { - td->val = &(bp->radius); - td->ival = bp->radius; - } else { - td->val = &(bp->alfa); - td->ival = bp->alfa; - } - - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td++; - count++; - tail++; - } - } - else if (propmode && head != tail) { - calc_distanceCurveVerts(head, tail-1); - head = tail; - } - } - if (propmode && head != tail) - calc_distanceCurveVerts(head, tail-1); - } - } -} - -/* ********************* lattice *************** */ - -static void createTransLatticeVerts(TransInfo *t) -{ - TransData *td = NULL; - BPoint *bp; - float mtx[3][3], smtx[3][3]; - int a; - int count=0, countsel=0; - int propmode = t->flag & T_PROP_EDIT; - - bp= editLatt->def; - a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw; - while(a--) { - if(bp->hide==0) { - if(bp->f1 & SELECT) countsel++; - if(propmode) count++; - } - bp++; - } - - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; - - if(propmode) t->total = count; - else t->total = countsel; - t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Lattice EditMode)"); - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - td = t->data; - bp= editLatt->def; - a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw; - while(a--) { - if(propmode || (bp->f1 & SELECT)) { - if(bp->hide==0) { - VECCOPY(td->iloc, bp->vec); - td->loc= bp->vec; - VECCOPY(td->center, td->loc); - if(bp->f1 & SELECT) td->flag= TD_SELECTED; - else td->flag= 0; - Mat3CpyMat3(td->smtx, smtx); - Mat3CpyMat3(td->mtx, mtx); - - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - - td++; - count++; - } - } - bp++; - } -} - -/* ******************* particle edit **************** */ -static void createTransParticleVerts(TransInfo *t) -{ - TransData *td = NULL; - TransDataExtension *tx; - Base *base = BASACT; - Object *ob = OBACT; - ParticleSystem *psys = PE_get_current(ob); - ParticleSystemModifierData *psmd = NULL; - ParticleEditSettings *pset = PE_settings(); - ParticleData *pa = NULL; - ParticleEdit *edit; - ParticleEditKey *key; - float mat[4][4]; - int i,k, totpart, transformparticle; - int count = 0, hasselected = 0; - int propmode = t->flag & T_PROP_EDIT; - - if(psys==NULL || G.scene->selectmode==SCE_SELECT_PATH) return; - - psmd = psys_get_modifier(ob,psys); - - edit = psys->edit; - totpart = psys->totpart; - base->flag |= BA_HAS_RECALC_DATA; - - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { - pa->flag &= ~PARS_TRANSFORM; - transformparticle= 0; - - if((pa->flag & PARS_HIDE)==0) { - for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) { - if((key->flag&PEK_HIDE)==0) { - if(key->flag&PEK_SELECT) { - hasselected= 1; - transformparticle= 1; - } - else if(propmode) - transformparticle= 1; - } - } - } - - if(transformparticle) { - count += pa->totkey; - pa->flag |= PARS_TRANSFORM; - } - } - - /* note: in prop mode we need at least 1 selected */ - if (hasselected==0) return; - - t->total = count; - td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransObData(Particle Mode)"); - - if(t->mode == TFM_BAKE_TIME) - tx = t->ext = MEM_callocN(t->total * sizeof(TransDataExtension), "Particle_TransExtension"); - else - tx = t->ext = NULL; - - Mat4One(mat); - - Mat4Invert(ob->imat,ob->obmat); - - for(i=0, pa=psys->particles; i<totpart; i++, pa++) { - TransData *head, *tail; - head = tail = td; - - if(!(pa->flag & PARS_TRANSFORM)) continue; - - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); - - for(k=0, key=edit->keys[i]; k<pa->totkey; k++, key++) { - VECCOPY(key->world_co, key->co); - Mat4MulVecfl(mat, key->world_co); - td->loc = key->world_co; - - VECCOPY(td->iloc, td->loc); - VECCOPY(td->center, td->loc); - - if(key->flag & PEK_SELECT) - td->flag |= TD_SELECTED; - else if(!propmode) - td->flag |= TD_SKIP; - - Mat3One(td->mtx); - Mat3One(td->smtx); - - /* don't allow moving roots */ - if(k==0 && pset->flag & PE_LOCK_FIRST) - td->protectflag |= OB_LOCK_LOC; - - td->ob = ob; - td->ext = tx; - td->tdi = NULL; - if(t->mode == TFM_BAKE_TIME) { - td->val = key->time; - td->ival = *(key->time); - /* abuse size and quat for min/max values */ - td->flag |= TD_NO_EXT; - if(k==0) tx->size = 0; - else tx->size = (key - 1)->time; - - if(k == pa->totkey - 1) tx->quat = 0; - else tx->quat = (key + 1)->time; - } - - td++; - if(tx) - tx++; - tail++; - } - if (propmode && head != tail) - calc_distanceCurveVerts(head, tail - 1); - } -} - -void flushTransParticles(TransInfo *t) -{ - Object *ob = OBACT; - ParticleSystem *psys = PE_get_current(ob); - ParticleSystemModifierData *psmd; - ParticleData *pa; - ParticleEditKey *key; - TransData *td; - float mat[4][4], imat[4][4], co[3]; - int i, k, propmode = t->flag & T_PROP_EDIT; - - psmd = psys_get_modifier(ob, psys); - - /* we do transform in world space, so flush world space position - * back to particle local space */ - td= t->data; - for(i=0, pa=psys->particles; i<psys->totpart; i++, pa++, td++) { - if(!(pa->flag & PARS_TRANSFORM)) continue; - - psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, mat); - Mat4Invert(imat,mat); - - for(k=0, key=psys->edit->keys[i]; k<pa->totkey; k++, key++) { - VECCOPY(co, key->world_co); - Mat4MulVecfl(imat, co); - - /* optimization for proportional edit */ - if(!propmode || !FloatCompare(key->co, co, 0.0001f)) { - VECCOPY(key->co, co); - pa->flag |= PARS_EDIT_RECALC; - } - } - } - - PE_update_object(OBACT, 1); -} - -/* ********************* mesh ****************** */ - -/* proportional distance based on connectivity */ -#define E_VEC(a) (vectors + (3 * (a)->tmp.l)) -#define E_NEAR(a) (nears[((a)->tmp.l)]) -#define THRESHOLD 0.0001f -static void editmesh_set_connectivity_distance(int total, float *vectors, EditVert **nears) -{ - EditMesh *em = G.editMesh; - EditVert *eve; - EditEdge *eed; - int i= 0, done= 1; - - /* f2 flag is used for 'selection' */ - /* tmp.l is offset on scratch array */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - eve->tmp.l = i++; - - if(eve->f & SELECT) { - eve->f2= 2; - E_NEAR(eve) = eve; - E_VEC(eve)[0] = 0.0f; - E_VEC(eve)[1] = 0.0f; - E_VEC(eve)[2] = 0.0f; - } - else { - eve->f2 = 0; - } - } - } - - - /* Floodfill routine */ - /* - At worst this is n*n of complexity where n is number of edges - Best case would be n if the list is ordered perfectly. - Estimate is n log n in average (so not too bad) - */ - while(done) { - done= 0; - - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0) { - EditVert *v1= eed->v1, *v2= eed->v2; - float *vec2 = E_VEC(v2); - float *vec1 = E_VEC(v1); - - if (v1->f2 + v2->f2 == 4) - continue; - - if (v1->f2) { - if (v2->f2) { - float nvec[3]; - float len1 = VecLength(vec1); - float len2 = VecLength(vec2); - float lenn; - /* for v2 if not selected */ - if (v2->f2 != 2) { - VecSubf(nvec, v2->co, E_NEAR(v1)->co); - lenn = VecLength(nvec); - /* 1 < n < 2 */ - if (lenn - len1 > THRESHOLD && len2 - lenn > THRESHOLD) { - VECCOPY(vec2, nvec); - E_NEAR(v2) = E_NEAR(v1); - done = 1; - } - /* n < 1 < 2 */ - else if (len2 - len1 > THRESHOLD && len1 - lenn > THRESHOLD) { - VECCOPY(vec2, vec1); - E_NEAR(v2) = E_NEAR(v1); - done = 1; - } - } - /* for v1 if not selected */ - if (v1->f2 != 2) { - VecSubf(nvec, v1->co, E_NEAR(v2)->co); - lenn = VecLength(nvec); - /* 2 < n < 1 */ - if (lenn - len2 > THRESHOLD && len1 - lenn > THRESHOLD) { - VECCOPY(vec1, nvec); - E_NEAR(v1) = E_NEAR(v2); - done = 1; - } - /* n < 2 < 1 */ - else if (len1 - len2 > THRESHOLD && len2 - lenn > THRESHOLD) { - VECCOPY(vec1, vec2); - E_NEAR(v1) = E_NEAR(v2); - done = 1; - } - } - } - else { - v2->f2 = 1; - VecSubf(vec2, v2->co, E_NEAR(v1)->co); - /* 2 < 1 */ - if (VecLength(vec1) - VecLength(vec2) > THRESHOLD) { - VECCOPY(vec2, vec1); - } - E_NEAR(v2) = E_NEAR(v1); - done = 1; - } - } - else if (v2->f2) { - v1->f2 = 1; - VecSubf(vec1, v1->co, E_NEAR(v2)->co); - /* 2 < 1 */ - if (VecLength(vec2) - VecLength(vec1) > THRESHOLD) { - VECCOPY(vec1, vec2); - } - E_NEAR(v1) = E_NEAR(v2); - done = 1; - } - } - } - } -} - -/* loop-in-a-loop I know, but we need it! (ton) */ -static void get_face_center(float *cent, EditVert *eve) -{ - EditMesh *em = G.editMesh; - EditFace *efa; - - for(efa= em->faces.first; efa; efa= efa->next) - if(efa->f & SELECT) - if(efa->v1==eve || efa->v2==eve || efa->v3==eve || efa->v4==eve) - break; - if(efa) { - VECCOPY(cent, efa->cent); - } -} - -//way to overwrite what data is edited with transform -//static void VertsToTransData(TransData *td, EditVert *eve, BakeKey *key) -static void VertsToTransData(TransData *td, EditVert *eve) -{ - td->flag = 0; - //if(key) - // td->loc = key->co; - //else - td->loc = eve->co; - - VECCOPY(td->center, td->loc); - if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) - get_face_center(td->center, eve); - VECCOPY(td->iloc, td->loc); - - // Setting normals - VECCOPY(td->axismtx[2], eve->no); - td->axismtx[0][0] = - td->axismtx[0][1] = - td->axismtx[0][2] = - td->axismtx[1][0] = - td->axismtx[1][1] = - td->axismtx[1][2] = 0.0f; - - td->ext = NULL; - td->tdi = NULL; - td->val = NULL; - td->tdmir = NULL; - if (BIF_GetTransInfo()->mode == TFM_BWEIGHT) { - td->val = &(eve->bweight); - td->ival = eve->bweight; - } - -#ifdef WITH_VERSE - if(eve->vvert) { - td->verse = (void*)eve->vvert; - td->flag |= TD_VERSE_VERT; - } - else - td->flag &= ~TD_VERSE_VERT; -#endif -} - -/* *********************** CrazySpace correction. Now without doing subsurf optimal ****************** */ - -static void make_vertexcos__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s) -{ - float *vec = userData; - - vec+= 3*index; - VECCOPY(vec, co); -} - -static int modifiers_disable_subsurf_temporary(Object *ob) -{ - ModifierData *md; - int disabled = 0; - - for(md=ob->modifiers.first; md; md=md->next) - if(md->type==eModifierType_Subsurf) - if(md->mode & eModifierMode_OnCage) { - md->mode ^= eModifierMode_DisableTemporary; - disabled= 1; - } - - return disabled; -} - -/* disable subsurf temporal, get mapped cos, and enable it */ -static float *get_crazy_mapped_editverts(void) -{ - DerivedMesh *dm; - float *vertexcos; - - /* disable subsurf temporal, get mapped cos, and enable it */ - if(modifiers_disable_subsurf_temporary(G.obedit)) { - /* need to make new derivemesh */ - makeDerivedMesh(G.obedit, CD_MASK_BAREMESH); - } - - /* now get the cage */ - dm= editmesh_get_derived_cage(CD_MASK_BAREMESH); - - vertexcos= MEM_mallocN(3*sizeof(float)*G.totvert, "vertexcos map"); - dm->foreachMappedVert(dm, make_vertexcos__mapFunc, vertexcos); - - dm->release(dm); - - /* set back the flag, no new cage needs to be built, transform does it */ - modifiers_disable_subsurf_temporary(G.obedit); - - return vertexcos; -} - -#define TAN_MAKE_VEC(a, b, c) a[0]= b[0] + 0.2f*(b[0]-c[0]); a[1]= b[1] + 0.2f*(b[1]-c[1]); a[2]= b[2] + 0.2f*(b[2]-c[2]) -static void set_crazy_vertex_quat(float *quat, float *v1, float *v2, float *v3, float *def1, float *def2, float *def3) -{ - float vecu[3], vecv[3]; - float q1[4], q2[4]; - - TAN_MAKE_VEC(vecu, v1, v2); - TAN_MAKE_VEC(vecv, v1, v3); - triatoquat(v1, vecu, vecv, q1); - - TAN_MAKE_VEC(vecu, def1, def2); - TAN_MAKE_VEC(vecv, def1, def3); - triatoquat(def1, vecu, vecv, q2); - - QuatSub(quat, q2, q1); -} -#undef TAN_MAKE_VEC - -static void set_crazyspace_quats(float *origcos, float *mappedcos, float *quats) -{ - EditMesh *em = G.editMesh; - EditVert *eve, *prev; - EditFace *efa; - float *v1, *v2, *v3, *v4, *co1, *co2, *co3, *co4; - intptr_t index= 0; - - /* two abused locations in vertices */ - for(eve= em->verts.first; eve; eve= eve->next, index++) { - eve->tmp.p = NULL; - eve->prev= (EditVert *)index; - } - - /* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */ - for(efa= em->faces.first; efa; efa= efa->next) { - - /* retrieve mapped coordinates */ - v1= mappedcos + 3*(intptr_t)(efa->v1->prev); - v2= mappedcos + 3*(intptr_t)(efa->v2->prev); - v3= mappedcos + 3*(intptr_t)(efa->v3->prev); - - co1= (origcos)? origcos + 3*(intptr_t)(efa->v1->prev): efa->v1->co; - co2= (origcos)? origcos + 3*(intptr_t)(efa->v2->prev): efa->v2->co; - co3= (origcos)? origcos + 3*(intptr_t)(efa->v3->prev): efa->v3->co; - - if(efa->v2->tmp.p==NULL && efa->v2->f1) { - set_crazy_vertex_quat(quats, co2, co3, co1, v2, v3, v1); - efa->v2->tmp.p= (void*)quats; - quats+= 4; - } - - if(efa->v4) { - v4= mappedcos + 3*(intptr_t)(efa->v4->prev); - co4= (origcos)? origcos + 3*(intptr_t)(efa->v4->prev): efa->v4->co; - - if(efa->v1->tmp.p==NULL && efa->v1->f1) { - set_crazy_vertex_quat(quats, co1, co2, co4, v1, v2, v4); - efa->v1->tmp.p= (void*)quats; - quats+= 4; - } - if(efa->v3->tmp.p==NULL && efa->v3->f1) { - set_crazy_vertex_quat(quats, co3, co4, co2, v3, v4, v2); - efa->v3->tmp.p= (void*)quats; - quats+= 4; - } - if(efa->v4->tmp.p==NULL && efa->v4->f1) { - set_crazy_vertex_quat(quats, co4, co1, co3, v4, v1, v3); - efa->v4->tmp.p= (void*)quats; - quats+= 4; - } - } - else { - if(efa->v1->tmp.p==NULL && efa->v1->f1) { - set_crazy_vertex_quat(quats, co1, co2, co3, v1, v2, v3); - efa->v1->tmp.p= (void*)quats; - quats+= 4; - } - if(efa->v3->tmp.p==NULL && efa->v3->f1) { - set_crazy_vertex_quat(quats, co3, co1, co2, v3, v1, v2); - efa->v3->tmp.p= (void*)quats; - quats+= 4; - } - } - } - - /* restore abused prev pointer */ - for(prev= NULL, eve= em->verts.first; eve; prev= eve, eve= eve->next) - eve->prev= prev; - -} - -void createTransBMeshVerts(TransInfo *t, BME_Mesh *bm, BME_TransData_Head *td) { - BME_Vert *v; - BME_TransData *vtd; - TransData *tob; - int i; - - tob = t->data = MEM_callocN(td->len*sizeof(TransData), "TransObData(Bevel tool)"); - - for (i=0,v=bm->verts.first;v;v=v->next) { - if ( (vtd = BME_get_transdata(td,v)) ) { - tob->loc = vtd->loc; - tob->val = &vtd->factor; - VECCOPY(tob->iloc,vtd->co); - VECCOPY(tob->center,vtd->org); - VECCOPY(tob->axismtx[0],vtd->vec); - tob->axismtx[1][0] = vtd->max ? *vtd->max : 0; - tob++; - i++; - } - } - /* since td is a memarena, it can hold more transdata than actual elements - * (i.e. we can't depend on td->len to determine the number of actual elements) */ - t->total = i; -} - -static void createTransEditVerts(TransInfo *t) -{ - TransData *tob = NULL; - EditMesh *em = G.editMesh; - EditVert *eve; - EditVert **nears = NULL; - EditVert *eve_act = NULL; - float *vectors = NULL, *mappedcos = NULL, *quats= NULL; - float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; - int count=0, countsel=0, a, totleft; - int propmode = t->flag & T_PROP_EDIT; - int mirror = 0; - - if ((t->context & CTX_NO_MIRROR) == 0 && (G.scene->toolsettings->editbutflag & B_MESH_X_MIRROR)) - { - mirror = 1; - } - - // transform now requires awareness for select mode, so we tag the f1 flags in verts - if(G.scene->selectmode & SCE_SELECT_VERTEX) { - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0 && (eve->f & SELECT)) - eve->f1= SELECT; - else - eve->f1= 0; - } - } - else if(G.scene->selectmode & SCE_SELECT_EDGE) { - EditEdge *eed; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->h==0 && (eed->f & SELECT)) - eed->v1->f1= eed->v2->f1= SELECT; - } - } - else { - EditFace *efa; - for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0; - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->h==0 && (efa->f & SELECT)) { - efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT; - if(efa->v4) efa->v4->f1= SELECT; - } - } - } - - /* now we can count */ - for(eve= em->verts.first; eve; eve= eve->next) { - if(eve->h==0) { - if(eve->f1) countsel++; - if(propmode) count++; - } - } - - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; - - /* check active */ - if (G.editMesh->selected.last) { - EditSelection *ese = G.editMesh->selected.last; - if ( ese->type == EDITVERT ) { - eve_act = (EditVert *)ese->data; - } - } - - - if(propmode) { - t->total = count; - - /* allocating scratch arrays */ - vectors = (float *)MEM_mallocN(t->total * 3 * sizeof(float), "scratch vectors"); - nears = (EditVert**)MEM_mallocN(t->total * sizeof(EditVert*), "scratch nears"); - } - else t->total = countsel; - tob= t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(Mesh EditMode)"); - - Mat3CpyMat4(mtx, G.obedit->obmat); - Mat3Inv(smtx, mtx); - - if(propmode) editmesh_set_connectivity_distance(t->total, vectors, nears); - - /* detect CrazySpace [tm] */ - if(propmode==0) { - if(modifiers_getCageIndex(G.obedit, NULL)>=0) { - if(modifiers_isDeformed(G.obedit)) { - /* check if we can use deform matrices for modifier from the - start up to stack, they are more accurate than quats */ - totleft= editmesh_get_first_deform_matrices(&defmats, &defcos); - - /* if we still have more modifiers, also do crazyspace - correction with quats, relative to the coordinates after - the modifiers that support deform matrices (defcos) */ - if(totleft > 0) { - mappedcos= get_crazy_mapped_editverts(); - quats= MEM_mallocN( (t->total)*sizeof(float)*4, "crazy quats"); - set_crazyspace_quats((float*)defcos, mappedcos, quats); - if(mappedcos) - MEM_freeN(mappedcos); - } - - if(defcos) - MEM_freeN(defcos); - } - } - } - - /* find out which half we do */ - if(mirror) { - for (eve=em->verts.first; eve; eve=eve->next) { - if(eve->h==0 && eve->f1 && eve->co[0]!=0.0f) { - if(eve->co[0]<0.0f) - mirror = -1; - break; - } - } - } - - for (a=0, eve=em->verts.first; eve; eve=eve->next, a++) { - if(eve->h==0) { - if(propmode || eve->f1) { - VertsToTransData(tob, eve); - - /* selected */ - if(eve->f1) tob->flag |= TD_SELECTED; - - /* active */ - if(eve == eve_act) tob->flag |= TD_ACTIVE; - - if(propmode) { - if (eve->f2) { - float vec[3]; - VECCOPY(vec, E_VEC(eve)); - Mat3MulVecfl(mtx, vec); - tob->dist= VecLength(vec); - } - else { - tob->flag |= TD_NOTCONNECTED; - tob->dist = MAXFLOAT; - } - } - - /* CrazySpace */ - if(defmats || (quats && eve->tmp.p)) { - float mat[3][3], imat[3][3], qmat[3][3]; - - /* use both or either quat and defmat correction */ - if(quats && eve->tmp.f) { - QuatToMat3(eve->tmp.p, qmat); - - if(defmats) - Mat3MulSerie(mat, mtx, qmat, defmats[a], - NULL, NULL, NULL, NULL, NULL); - else - Mat3MulMat3(mat, mtx, qmat); - } - else - Mat3MulMat3(mat, mtx, defmats[a]); - - Mat3Inv(imat, mat); - - Mat3CpyMat3(tob->smtx, imat); - Mat3CpyMat3(tob->mtx, mat); - } - else { - Mat3CpyMat3(tob->smtx, smtx); - Mat3CpyMat3(tob->mtx, mtx); - } - - /* Mirror? */ - if( (mirror>0 && tob->iloc[0]>0.0f) || (mirror<0 && tob->iloc[0]<0.0f)) { - EditVert *vmir= editmesh_get_x_mirror_vert(G.obedit, tob->iloc); /* initializes octree on first call */ - if(vmir != eve) tob->tdmir = vmir; - } - tob++; - } - } - } - if (propmode) { - MEM_freeN(vectors); - MEM_freeN(nears); - } - /* crazy space free */ - if(quats) - MEM_freeN(quats); - if(defmats) - MEM_freeN(defmats); -} - -/* ********************* UV ****************** */ - -static void UVsToTransData(TransData *td, TransData2D *td2d, float *uv, int selected) -{ - float aspx, aspy; - - transform_aspect_ratio_tface_uv(&aspx, &aspy); - - /* uv coords are scaled by aspects. this is needed for rotations and - proportional editing to be consistent with the stretchted uv coords - that are displayed. this also means that for display and numinput, - and when the the uv coords are flushed, these are converted each time */ - td2d->loc[0] = uv[0]*aspx; - td2d->loc[1] = uv[1]*aspy; - td2d->loc[2] = 0.0f; - td2d->loc2d = uv; - - td->flag = 0; - td->loc = td2d->loc; - VECCOPY(td->center, td->loc); - VECCOPY(td->iloc, td->loc); - - memset(td->axismtx, 0, sizeof(td->axismtx)); - td->axismtx[2][2] = 1.0f; - - td->ext= NULL; td->tdi= NULL; td->val= NULL; - - if(selected) { - td->flag |= TD_SELECTED; - td->dist= 0.0; - } - else { - td->dist= MAXFLOAT; - } - Mat3One(td->mtx); - Mat3One(td->smtx); -} - -static void createTransUVs(TransInfo *t) -{ - TransData *td = NULL; - TransData2D *td2d = NULL; - MTFace *tf; - int count=0, countsel=0; - int propmode = t->flag & T_PROP_EDIT; - int efa_s1,efa_s2,efa_s3,efa_s4; - - EditMesh *em = G.editMesh; - EditFace *efa; - - if(is_uv_tface_editing_allowed()==0) return; - - /* count */ - if (G.sima->flag & SI_BE_SQUARE && !propmode) { - for (efa= em->faces.first; efa; efa= efa->next) { - /* store face pointer for second loop, prevent second lookup */ - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (simaFaceDraw_Check(efa, tf)) { - efa->tmp.p = tf; - - efa_s1 = simaUVSel_Check(efa, tf, 0); - efa_s2 = simaUVSel_Check(efa, tf, 1); - efa_s3 = simaUVSel_Check(efa, tf, 2); - if (efa->v4) { - efa_s4 = simaUVSel_Check(efa, tf, 3); - if ( efa_s1 || efa_s2 || efa_s3 || efa_s4 ) { - countsel += 4; /* all corners of this quad need their edges moved. so we must store TD for each */ - } - } else { - /* tri's are delt with normally when SI_BE_SQUARE's enabled */ - if (efa_s1) countsel++; - if (efa_s2) countsel++; - if (efa_s3) countsel++; - } - } else { - efa->tmp.p = NULL; - } - } - } else { - for (efa= em->faces.first; efa; efa= efa->next) { - tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (simaFaceDraw_Check(efa, tf)) { - efa->tmp.p = tf; - - if (simaUVSel_Check(efa, tf, 0)) countsel++; - if (simaUVSel_Check(efa, tf, 1)) countsel++; - if (simaUVSel_Check(efa, tf, 2)) countsel++; - if (efa->v4 && simaUVSel_Check(efa, tf, 3)) countsel++; - if(propmode) - count += (efa->v4)? 4: 3; - } else { - efa->tmp.p = NULL; - } - } - } - - /* note: in prop mode we need at least 1 selected */ - if (countsel==0) return; - - t->total= (propmode)? count: countsel; - t->data= MEM_callocN(t->total*sizeof(TransData), "TransObData(UV Editing)"); - /* for each 2d uv coord a 3d vector is allocated, so that they can be - treated just as if they were 3d verts */ - t->data2d= MEM_callocN(t->total*sizeof(TransData2D), "TransObData2D(UV Editing)"); - - if(G.sima->flag & SI_CLIP_UV) - t->flag |= T_CLIP_UV; - - td= t->data; - td2d= t->data2d; - - if (G.sima->flag & SI_BE_SQUARE && !propmode) { - for (efa= em->faces.first; efa; efa= efa->next) { - tf=(MTFace *)efa->tmp.p; - if (tf) { - efa_s1 = simaUVSel_Check(efa, tf, 0); - efa_s2 = simaUVSel_Check(efa, tf, 1); - efa_s3 = simaUVSel_Check(efa, tf, 2); - - if (efa->v4) { - efa_s4 = simaUVSel_Check(efa, tf, 3); - - if ( efa_s1 || efa_s2 || efa_s3 || efa_s4 ) { - /* all corners of this quad need their edges moved. so we must store TD for each */ - - UVsToTransData(td, td2d, tf->uv[0], efa_s1); - if (!efa_s1) td->flag |= TD_SKIP; - td++; td2d++; - - UVsToTransData(td, td2d, tf->uv[1], efa_s2); - if (!efa_s2) td->flag |= TD_SKIP; - td++; td2d++; - - UVsToTransData(td, td2d, tf->uv[2], efa_s3); - if (!efa_s3) td->flag |= TD_SKIP; - td++; td2d++; - - UVsToTransData(td, td2d, tf->uv[3], efa_s4); - if (!efa_s4) td->flag |= TD_SKIP; - td++; td2d++; - } - } else { - /* tri's are delt with normally when SI_BE_SQUARE's enabled */ - if (efa_s1) UVsToTransData(td++, td2d++, tf->uv[0], 1); - if (efa_s2) UVsToTransData(td++, td2d++, tf->uv[1], 1); - if (efa_s3) UVsToTransData(td++, td2d++, tf->uv[2], 1); - } - } - } - } else { - for (efa= em->faces.first; efa; efa= efa->next) { - /*tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE); - if (simaFaceDraw_Check(efa, tf)) {*/ - if ((tf=(MTFace *)efa->tmp.p)) { - if (propmode) { - UVsToTransData(td++, td2d++, tf->uv[0], simaUVSel_Check(efa, tf, 0)); - UVsToTransData(td++, td2d++, tf->uv[1], simaUVSel_Check(efa, tf, 1)); - UVsToTransData(td++, td2d++, tf->uv[2], simaUVSel_Check(efa, tf, 2)); - if(efa->v4) - UVsToTransData(td++, td2d++, tf->uv[3], simaUVSel_Check(efa, tf, 3)); - } else { - if(simaUVSel_Check(efa, tf, 0)) UVsToTransData(td++, td2d++, tf->uv[0], 1); - if(simaUVSel_Check(efa, tf, 1)) UVsToTransData(td++, td2d++, tf->uv[1], 1); - if(simaUVSel_Check(efa, tf, 2)) UVsToTransData(td++, td2d++, tf->uv[2], 1); - if(efa->v4 && simaUVSel_Check(efa, tf, 3)) UVsToTransData(td++, td2d++, tf->uv[3], 1); - } - } - } - } - - if (G.sima->flag & SI_LIVE_UNWRAP) - unwrap_lscm_live_begin(); -} - -void flushTransUVs(TransInfo *t) -{ - TransData2D *td; - int a, width, height; - Object *ob= OBACT; - EditMesh *em = G.editMesh; - float aspx, aspy, invx, invy; - - transform_aspect_ratio_tface_uv(&aspx, &aspy); - transform_width_height_tface_uv(&width, &height); - invx= 1.0f/aspx; - invy= 1.0f/aspy; - - /* flush to 2d vector from internally used 3d vector */ - for(a=0, td= t->data2d; a<t->total; a++, td++) { - td->loc2d[0]= td->loc[0]*invx; - td->loc2d[1]= td->loc[1]*invy; - - if((G.sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) { - td->loc2d[0]= (float)floor(width*td->loc2d[0] + 0.5f)/width; - td->loc2d[1]= (float)floor(height*td->loc2d[1] + 0.5f)/height; - } - } - - if((G.sima->flag & SI_BE_SQUARE) && (t->flag & T_PROP_EDIT)==0 && (t->state != TRANS_CANCEL)) - be_square_tface_uv(em); - - /* this is overkill if G.sima->lock is not set, but still needed */ - object_uvs_changed(ob); -} - -int clipUVTransform(TransInfo *t, float *vec, int resize) -{ - TransData *td; - int a, clipx=1, clipy=1; - float aspx, aspy, min[2], max[2]; - - transform_aspect_ratio_tface_uv(&aspx, &aspy); - min[0]= min[1]= 0.0f; - max[0]= aspx; max[1]= aspy; - - for(a=0, td= t->data; a<t->total; a++, td++) { - DO_MINMAX2(td->loc, min, max); - } - - if(resize) { - if(min[0] < 0.0f && t->center[0] > 0.0f && t->center[0] < aspx*0.5f) - vec[0] *= t->center[0]/(t->center[0] - min[0]); - else if(max[0] > aspx && t->center[0] < aspx) - vec[0] *= (t->center[0] - aspx)/(t->center[0] - max[0]); - else - clipx= 0; - - if(min[1] < 0.0f && t->center[1] > 0.0f && t->center[1] < aspy*0.5f) - vec[1] *= t->center[1]/(t->center[1] - min[1]); - else if(max[1] > aspy && t->center[1] < aspy) - vec[1] *= (t->center[1] - aspy)/(t->center[1] - max[1]); - else - clipy= 0; - } - else { - if(min[0] < 0.0f) - vec[0] -= min[0]; - else if(max[0] > aspx) - vec[0] -= max[0]-aspx; - else - clipx= 0; - - if(min[1] < 0.0f) - vec[1] -= min[1]; - else if(max[1] > aspy) - vec[1] -= max[1]-aspy; - else - clipy= 0; - } - - return (clipx || clipy); -} - -/* ********************* IPO EDITOR ************************* */ - -/* for IPO Editor transform - but actual creation of transform structures is not performed here - * due to bad globals that would need to be imported specially for this - */ -static void createTransIpoData(TransInfo *t) -{ - /* in editipo.c due to some globals that are defined in that file... */ - make_ipo_transdata(t); -} - -/* this function is called on recalcData to apply the transforms applied - * to the transdata on to the actual keyframe data - */ -void flushTransIpoData(TransInfo *t) -{ - TransData2D *td; - int a; - - /* flush to 2d vector from internally used 3d vector */ - for (a=0, td= t->data2d; a<t->total; a++, td++) { - /* we need to unapply the nla-scaling from the time in some situations */ - if (NLA_IPO_SCALED) - td->loc2d[0]= get_action_frame(OBACT, td->loc[0]); - else - td->loc2d[0]= td->loc[0]; - - /* when the icu that point comes from is a bitflag holder, don't allow adjusting values */ - if ((t->data[a].flag & TD_TIMEONLY)==0) - td->loc2d[1]= td->loc[1]; - } -} - -/* ********************* ACTION/NLA EDITOR ****************** */ - -/* Called by special_aftertrans_update to make sure selected gp-frames replace - * any other gp-frames which may reside on that frame (that are not selected). - * It also makes sure gp-frames are still stored in chronological order after - * transform. - */ -static void posttrans_gpd_clean (bGPdata *gpd) -{ - bGPDlayer *gpl; - - for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { - ListBase sel_buffer = {NULL, NULL}; - bGPDframe *gpf, *gpfn; - bGPDframe *gfs, *gfsn; - - /* loop 1: loop through and isolate selected gp-frames to buffer - * (these need to be sorted as they are isolated) - */ - for (gpf= gpl->frames.first; gpf; gpf= gpfn) { - short added= 0; - gpfn= gpf->next; - - if (gpf->flag & GP_FRAME_SELECT) { - BLI_remlink(&gpl->frames, gpf); - - /* find place to add them in buffer - * - go backwards as most frames will still be in order, - * so doing it this way will be faster - */ - for (gfs= sel_buffer.last; gfs; gfs= gfs->prev) { - /* if current (gpf) occurs after this one in buffer, add! */ - if (gfs->framenum < gpf->framenum) { - BLI_insertlinkafter(&sel_buffer, gfs, gpf); - added= 1; - break; - } - } - if (added == 0) - BLI_addhead(&sel_buffer, gpf); - } - } - - /* error checking: it is unlikely, but may be possible to have none selected */ - if (sel_buffer.first == NULL) - continue; - - /* if all were selected (i.e. gpl->frames is empty), then just transfer sel-buf over */ - if (gpl->frames.first == NULL) { - gpl->frames.first= sel_buffer.first; - gpl->frames.last= sel_buffer.last; - - continue; - } - - /* loop 2: remove duplicates of frames in buffers */ - for (gpf= gpl->frames.first; gpf && sel_buffer.first; gpf= gpfn) { - gpfn= gpf->next; - - /* loop through sel_buffer, emptying stuff from front of buffer if ok */ - for (gfs= sel_buffer.first; gfs && gpf; gfs= gfsn) { - gfsn= gfs->next; - - /* if this buffer frame needs to go before current, add it! */ - if (gfs->framenum < gpf->framenum) { - /* transfer buffer frame to frames list (before current) */ - BLI_remlink(&sel_buffer, gfs); - BLI_insertlinkbefore(&gpl->frames, gpf, gfs); - } - /* if this buffer frame is on same frame, replace current with it and stop */ - else if (gfs->framenum == gpf->framenum) { - /* transfer buffer frame to frames list (before current) */ - BLI_remlink(&sel_buffer, gfs); - BLI_insertlinkbefore(&gpl->frames, gpf, gfs); - - /* get rid of current frame */ - gpencil_layer_delframe(gpl, gpf); - } - } - } - - /* if anything is still in buffer, append to end */ - for (gfs= sel_buffer.first; gfs; gfs= gfsn) { - gfsn= gfs->next; - - BLI_remlink(&sel_buffer, gfs); - BLI_addtail(&gpl->frames, gfs); - } - } -} - -/* Called by special_aftertrans_update to make sure selected keyframes replace - * any other keyframes which may reside on that frame (that is not selected). - */ -static void posttrans_ipo_clean (Ipo *ipo) -{ - IpoCurve *icu; - int i; - - /* delete any keyframes that occur on same frame as selected keyframe, but is not selected */ - for (icu= ipo->curve.first; icu; icu= icu->next) { - float *selcache; /* cache for frame numbers of selected frames (icu->totvert*sizeof(float)) */ - int len, index; /* number of frames in cache, item index */ - - /* allocate memory for the cache */ - // TODO: investigate using GHash for this instead? - if (icu->totvert == 0) - continue; - selcache= MEM_callocN(sizeof(float)*icu->totvert, "IcuSelFrameNums"); - len= 0; - index= 0; - - /* We do 2 loops, 1 for marking keyframes for deletion, one for deleting - * as there is no guarantee what order the keyframes are exactly, even though - * they have been sorted by time. - */ - - /* Loop 1: find selected keyframes */ - for (i = 0; i < icu->totvert; i++) { - BezTriple *bezt= &icu->bezt[i]; - - if (BEZSELECTED(bezt)) { - selcache[index]= bezt->vec[1][0]; - index++; - len++; - } - } - - /* Loop 2: delete unselected keyframes on the same frames (if any keyframes were found) */ - if (len) { - for (i = 0; i < icu->totvert; i++) { - BezTriple *bezt= &icu->bezt[i]; - - if (BEZSELECTED(bezt) == 0) { - /* check beztriple should be removed according to cache */ - for (index= 0; index < len; index++) { - if (IS_EQ(bezt->vec[1][0], selcache[index])) { - delete_icu_key(icu, i, 0); - break; - } - else if (bezt->vec[1][0] > selcache[index]) - break; - } - } - } - - testhandles_ipocurve(icu); - } - - /* free cache */ - MEM_freeN(selcache); - } -} - -/* Called by special_aftertrans_update to make sure selected keyframes replace - * any other keyframes which may reside on that frame (that is not selected). - * remake_action_ipos should have already been called - */ -static void posttrans_action_clean (bAction *act) -{ - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - int filter; - - /* filter data */ - filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS); - actdata_filter(&act_data, filter, act, ACTCONT_ACTION); - - /* loop through relevant data, removing keyframes from the ipo-blocks that were attached - * - all keyframes are converted in/out of global time - */ - for (ale= act_data.first; ale; ale= ale->next) { - if (NLA_ACTION_SCALED) { - actstrip_map_ipo_keys(OBACT, ale->key_data, 0, 1); - posttrans_ipo_clean(ale->key_data); - actstrip_map_ipo_keys(OBACT, ale->key_data, 1, 1); - } - else - posttrans_ipo_clean(ale->key_data); - } - - /* free temp data */ - BLI_freelistN(&act_data); -} - -/* Called by special_aftertrans_update to make sure selected keyframes replace - * any other keyframes which may reside on that frame (that is not selected). - * remake_all_ipos should have already been called - */ -static void posttrans_nla_clean (TransInfo *t) -{ - Base *base; - Object *ob; - bActionStrip *strip; - bActionChannel *achan; - bConstraintChannel *conchan; - float cfra; - char side; - int i; - - /* which side of the current frame should be allowed */ - if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse); - side = (xmouse > CFRA) ? 'R' : 'L'; - } - else { - /* normal transform - both sides of current frame are considered */ - side = 'B'; - } - - /* only affect keyframes */ - for (base=G.scene->base.first; base; base=base->next) { - ob= base->object; - - /* Check object ipos */ - i= count_ipo_keys(ob->ipo, side, (float)CFRA); - if (i) posttrans_ipo_clean(ob->ipo); - - /* Check object constraint ipos */ - for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) { - i= count_ipo_keys(conchan->ipo, side, (float)CFRA); - if (i) posttrans_ipo_clean(conchan->ipo); - } - - /* skip actions and nlastrips if object is collapsed */ - if (ob->nlaflag & OB_NLA_COLLAPSED) - continue; - - /* Check action ipos */ - if (ob->action) { - /* exclude if strip is selected too */ - for (strip=ob->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) { - if (strip->act == ob->action) - break; - } - } - if (strip==NULL) { - cfra = get_action_frame(ob, (float)CFRA); - - for (achan=ob->action->chanbase.first; achan; achan=achan->next) { - if (EDITABLE_ACHAN(achan)) { - i= count_ipo_keys(achan->ipo, side, cfra); - if (i) { - actstrip_map_ipo_keys(ob, achan->ipo, 0, 1); - posttrans_ipo_clean(achan->ipo); - actstrip_map_ipo_keys(ob, achan->ipo, 1, 1); - } - - /* Check action constraint ipos */ - if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { - for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { - if (EDITABLE_CONCHAN(conchan)) { - i = count_ipo_keys(conchan->ipo, side, cfra); - if (i) { - actstrip_map_ipo_keys(ob, conchan->ipo, 0, 1); - posttrans_ipo_clean(conchan->ipo); - actstrip_map_ipo_keys(ob, conchan->ipo, 1, 1); - } - } - } - } - } - } - } - } - } -} - -/* ----------------------------- */ - -/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */ -static short FrameOnMouseSide(char side, float frame, float cframe) -{ - /* both sides, so it doesn't matter */ - if (side == 'B') return 1; - - /* only on the named side */ - if (side == 'R') - return (frame >= cframe) ? 1 : 0; - else - return (frame <= cframe) ? 1 : 0; -} - -/* fully select selected beztriples, but only include if it's on the right side of cfra */ -static int count_ipo_keys(Ipo *ipo, char side, float cfra) -{ - IpoCurve *icu; - BezTriple *bezt; - int i, count = 0; - - if (ipo == NULL) - return count; - - /* only include points that occur on the right side of cfra */ - for (icu= ipo->curve.first; icu; icu= icu->next) { - for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) { - if (bezt->f2 & SELECT) { - /* fully select the other two keys */ - bezt->f1 |= SELECT; - bezt->f3 |= SELECT; - - /* increment by 3, as there are 3 points (3 * x-coordinates) that need transform */ - if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) - count += 3; - } - } - } - - return count; -} - -/* fully select selected beztriples, but only include if it's on the right side of cfra */ -static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra) -{ - bGPDframe *gpf; - int count = 0; - - if (gpl == NULL) - return count; - - /* only include points that occur on the right side of cfra */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - if (gpf->flag & GP_FRAME_SELECT) { - if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) - count++; - } - } - - return count; -} - -/* This function assigns the information to transdata */ -static void TimeToTransData(TransData *td, float *time, Object *ob) -{ - /* memory is calloc'ed, so that should zero everything nicely for us */ - td->val = time; - td->ival = *(time); - - /* store the Object where this keyframe exists as a keyframe of the - * active action as td->ob. Usually, this member is only used for constraints - * drawing - */ - td->ob= ob; -} - -/* This function advances the address to which td points to, so it must return - * the new address so that the next time new transform data is added, it doesn't - * overwrite the existing ones... i.e. td = IpoToTransData(td, ipo, ob, side, cfra); - * - * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data - * on the named side are used. - */ -static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side, float cfra) -{ - IpoCurve *icu; - BezTriple *bezt; - int i; - - if (ipo == NULL) - return td; - - for (icu= ipo->curve.first; icu; icu= icu->next) { - for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) { - /* only add selected keyframes (for now, proportional edit is not enabled) */ - if (BEZSELECTED(bezt)) { - /* only add if on the right 'side' of the current frame */ - if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) { - /* each control point needs to be added separetely */ - TimeToTransData(td, bezt->vec[0], ob); - td++; - - TimeToTransData(td, bezt->vec[1], ob); - td++; - - TimeToTransData(td, bezt->vec[2], ob); - td++; - } - } - } - } - - return td; -} - -/* helper struct for gp-frame transforms (only used here) */ -typedef struct tGPFtransdata { - float val; /* where transdata writes transform */ - int *sdata; /* pointer to gpf->framenum */ -} tGPFtransdata; - -/* This function helps flush transdata written to tempdata into the gp-frames */ -void flushTransGPactionData (TransInfo *t) -{ - tGPFtransdata *tfd; - int i; - - /* find the first one to start from */ - if (t->mode == TFM_TIME_SLIDE) - tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 ); - else - tfd= (tGPFtransdata *)(t->customData); - - /* flush data! */ - for (i = 0; i < t->total; i++, tfd++) { - *(tfd->sdata)= (int)floor(tfd->val + 0.5); - } -} - -/* This function advances the address to which td points to, so it must return - * the new address so that the next time new transform data is added, it doesn't - * overwrite the existing ones... i.e. td = GPLayerToTransData(td, ipo, ob, side, cfra); - * - * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data - * on the named side are used. - */ -static int GPLayerToTransData (TransData *td, tGPFtransdata *tfd, bGPDlayer *gpl, char side, float cfra) -{ - bGPDframe *gpf; - int count= 0; - - /* check for select frames on right side of current frame */ - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - if (gpf->flag & GP_FRAME_SELECT) { - if (FrameOnMouseSide(side, (float)gpf->framenum, cfra)) { - /* memory is calloc'ed, so that should zero everything nicely for us */ - td->val= &tfd->val; - td->ival= (float)gpf->framenum; - - tfd->val= (float)gpf->framenum; - tfd->sdata= &gpf->framenum; - - /* advance td now */ - td++; - tfd++; - count++; - } - } - } - - return count; -} - -static void createTransActionData(TransInfo *t) -{ - TransData *td = NULL; - tGPFtransdata *tfd = NULL; - Object *ob= NULL; - - ListBase act_data = {NULL, NULL}; - bActListElem *ale; - void *data; - short datatype; - int filter; - - int count=0; - float cfra; - char side; - - /* determine what type of data we are operating on */ - data = get_action_context(&datatype); - if (data == NULL) return; - - /* filter data */ - if (datatype == ACTCONT_GPENCIL) - filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT); - else - filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS); - actdata_filter(&act_data, filter, data, datatype); - - /* is the action scaled? if so, the it should belong to the active object */ - if (NLA_ACTION_SCALED) - ob= OBACT; - - /* which side of the current frame should be allowed */ - if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse); - side = (xmouse > CFRA) ? 'R' : 'L'; - } - else { - /* normal transform - both sides of current frame are considered */ - side = 'B'; - } - - /* convert current-frame to action-time (slightly less accurate, espcially under - * higher scaling ratios, but is faster than converting all points) - */ - if (ob) - cfra = get_action_frame(ob, (float)CFRA); - else - cfra = (float)CFRA; - - /* loop 1: fully select ipo-keys and count how many BezTriples are selected */ - for (ale= act_data.first; ale; ale= ale->next) { - if (ale->type == ACTTYPE_GPLAYER) - count += count_gplayer_frames(ale->data, side, cfra); - else - count += count_ipo_keys(ale->key_data, side, cfra); - } - - /* stop if trying to build list if nothing selected */ - if (count == 0) { - /* cleanup temp list */ - BLI_freelistN(&act_data); - return; - } - - /* allocate memory for data */ - t->total= count; - - t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(Action Editor)"); - td= t->data; - - if (datatype == ACTCONT_GPENCIL) { - if (t->mode == TFM_TIME_SLIDE) { - t->customData= MEM_callocN((sizeof(float)*2)+(sizeof(tGPFtransdata)*count), "TimeSlide + tGPFtransdata"); - tfd= (tGPFtransdata *)( (float *)(t->customData) + 2 ); - } - else { - t->customData= MEM_callocN(sizeof(tGPFtransdata)*count, "tGPFtransdata"); - tfd= (tGPFtransdata *)(t->customData); - } - } - else if (t->mode == TFM_TIME_SLIDE) - t->customData= MEM_callocN(sizeof(float)*2, "TimeSlide Min/Max"); - - /* loop 2: build transdata array */ - for (ale= act_data.first; ale; ale= ale->next) { - if (ale->type == ACTTYPE_GPLAYER) { - bGPDlayer *gpl= (bGPDlayer *)ale->data; - int i; - - i = GPLayerToTransData(td, tfd, gpl, side, cfra); - td += i; - tfd += i; - } - else { - Ipo *ipo= (Ipo *)ale->key_data; - - td= IpoToTransData(td, ipo, ob, side, cfra); - } - } - - /* check if we're supposed to be setting minx/maxx for TimeSlide */ - if (t->mode == TFM_TIME_SLIDE) { - float min=999999999.0f, max=-999999999.0f; - int i; - - td= (t->data + 1); - for (i=1; i < count; i+=3, td+=3) { - if (min > *(td->val)) min= *(td->val); - if (max < *(td->val)) max= *(td->val); - } - - /* minx/maxx values used by TimeSlide are stored as a - * calloced 2-float array in t->customData. This gets freed - * in postTrans (T_FREE_CUSTOMDATA). - */ - *((float *)(t->customData)) = min; - *((float *)(t->customData) + 1) = max; - } - - /* cleanup temp list */ - BLI_freelistN(&act_data); -} - -static void createTransNlaData(TransInfo *t) -{ - Base *base; - bActionStrip *strip; - bActionChannel *achan; - bConstraintChannel *conchan; - - TransData *td = NULL; - int count=0, i; - float cfra; - char side; - - /* which side of the current frame should be allowed */ - if (t->mode == TFM_TIME_EXTEND) { - /* only side on which mouse is gets transformed */ - float xmouse, ymouse; - - areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse); - side = (xmouse > CFRA) ? 'R' : 'L'; - } - else { - /* normal transform - both sides of current frame are considered */ - side = 'B'; - } - - /* Ensure that partial selections result in beztriple selections */ - for (base=G.scene->base.first; base; base=base->next) { - /* Check object ipos */ - i= count_ipo_keys(base->object->ipo, side, (float)CFRA); - if (i) base->flag |= BA_HAS_RECALC_OB; - count += i; - - /* Check object constraint ipos */ - for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) - count += count_ipo_keys(conchan->ipo, side, (float)CFRA); - - /* skip actions and nlastrips if object is collapsed */ - if (base->object->nlaflag & OB_NLA_COLLAPSED) - continue; - - /* Check action ipos */ - if (base->object->action) { - /* exclude if strip is selected too */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) { - if (strip->act == base->object->action) - break; - } - } - if (strip==NULL) { - cfra = get_action_frame(base->object, (float)CFRA); - - for (achan=base->object->action->chanbase.first; achan; achan=achan->next) { - if (EDITABLE_ACHAN(achan)) { - i= count_ipo_keys(achan->ipo, side, cfra); - if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; - count += i; - - /* Check action constraint ipos */ - if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { - for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { - if (EDITABLE_CONCHAN(conchan)) - count += count_ipo_keys(conchan->ipo, side, cfra); - } - } - } - } - } - } - - /* Check nlastrips */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) { - base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA; - - if (FrameOnMouseSide(side, strip->start, (float)CFRA)) count++; - if (FrameOnMouseSide(side, strip->end, (float)CFRA)) count++; - } - } - } - - /* If nothing is selected, bail out */ - if (count == 0) - return; - - /* allocate memory for data */ - t->total= count; - t->data= MEM_callocN(t->total*sizeof(TransData), "TransData (NLA Editor)"); - - /* build the transdata structure */ - td= t->data; - for (base=G.scene->base.first; base; base=base->next) { - /* Manipulate object ipos */ - /* - no scaling of keyframe times is allowed here */ - td= IpoToTransData(td, base->object->ipo, NULL, side, (float)CFRA); - - /* Manipulate object constraint ipos */ - /* - no scaling of keyframe times is allowed here */ - for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next) - td= IpoToTransData(td, conchan->ipo, NULL, side, (float)CFRA); - - /* skip actions and nlastrips if object collapsed */ - if (base->object->nlaflag & OB_NLA_COLLAPSED) - continue; - - /* Manipulate action ipos */ - if (base->object->action) { - /* exclude if strip that active action belongs to is selected too */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) { - if (strip->act == base->object->action) - break; - } - } - - /* can include if no strip found */ - if (strip==NULL) { - cfra = get_action_frame(base->object, (float)CFRA); - - for (achan=base->object->action->chanbase.first; achan; achan=achan->next) { - if (EDITABLE_ACHAN(achan)) { - td= IpoToTransData(td, achan->ipo, base->object, side, cfra); - - /* Manipulate action constraint ipos */ - if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) { - for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) { - if (EDITABLE_CONCHAN(conchan)) - td= IpoToTransData(td, conchan->ipo, base->object, side, cfra); - } - } - } - } - } - } - - /* Manipulate nlastrips */ - for (strip=base->object->nlastrips.first; strip; strip=strip->next) { - if (strip->flag & ACTSTRIP_SELECT) { - /* first TransData is the start, second is the end */ - if (FrameOnMouseSide(side, strip->start, (float)CFRA)) { - td->val = &strip->start; - td->ival = strip->start; - td++; - } - if (FrameOnMouseSide(side, strip->end, (float)CFRA)) { - td->val = &strip->end; - td->ival = strip->end; - td++; - } - } - } - } -} - -/* **************** IpoKey stuff, for Object TransData ********** */ - -/* storage of bezier triple. thats why -3 and +3! */ -static void set_tdi_old(float *old, float *poin) -{ - old[0]= *(poin); - old[3]= *(poin-3); - old[6]= *(poin+3); -} - -/* while transforming */ -void add_tdi_poin(float *poin, float *old, float delta) -{ - if(poin) { - poin[0]= old[0]+delta; - poin[-3]= old[3]+delta; - poin[3]= old[6]+delta; - } -} - -/* fill ipokey transdata with old vals and pointers */ -static void ipokey_to_transdata(IpoKey *ik, TransData *td) -{ - extern int ob_ar[]; // blenkernel ipo.c - TransDataIpokey *tdi= td->tdi; - BezTriple *bezt; - int a, delta= 0; - - td->val= NULL; // is read on ESC - - for(a=0; a<OB_TOTIPO; a++) { - if(ik->data[a]) { - bezt= ik->data[a]; - - switch( ob_ar[a] ) { - case OB_LOC_X: - case OB_DLOC_X: - tdi->locx= &(bezt->vec[1][1]); break; - case OB_LOC_Y: - case OB_DLOC_Y: - tdi->locy= &(bezt->vec[1][1]); break; - case OB_LOC_Z: - case OB_DLOC_Z: - tdi->locz= &(bezt->vec[1][1]); break; - - case OB_DROT_X: - delta= 1; - case OB_ROT_X: - tdi->rotx= &(bezt->vec[1][1]); break; - case OB_DROT_Y: - delta= 1; - case OB_ROT_Y: - tdi->roty= &(bezt->vec[1][1]); break; - case OB_DROT_Z: - delta= 1; - case OB_ROT_Z: - tdi->rotz= &(bezt->vec[1][1]); break; - - case OB_SIZE_X: - case OB_DSIZE_X: - tdi->sizex= &(bezt->vec[1][1]); break; - case OB_SIZE_Y: - case OB_DSIZE_Y: - tdi->sizey= &(bezt->vec[1][1]); break; - case OB_SIZE_Z: - case OB_DSIZE_Z: - tdi->sizez= &(bezt->vec[1][1]); break; - } - } - } - - /* oldvals for e.g. undo */ - if(tdi->locx) set_tdi_old(tdi->oldloc, tdi->locx); - if(tdi->locy) set_tdi_old(tdi->oldloc+1, tdi->locy); - if(tdi->locz) set_tdi_old(tdi->oldloc+2, tdi->locz); - - /* remember, for mapping curves ('1'=10 degrees) */ - if(tdi->rotx) set_tdi_old(tdi->oldrot, tdi->rotx); - if(tdi->roty) set_tdi_old(tdi->oldrot+1, tdi->roty); - if(tdi->rotz) set_tdi_old(tdi->oldrot+2, tdi->rotz); - - /* this is not allowed to be dsize! */ - if(tdi->sizex) set_tdi_old(tdi->oldsize, tdi->sizex); - if(tdi->sizey) set_tdi_old(tdi->oldsize+1, tdi->sizey); - if(tdi->sizez) set_tdi_old(tdi->oldsize+2, tdi->sizez); - - tdi->flag= TOB_IPO; - if(delta) tdi->flag |= TOB_IPODROT; -} - - -/* *************************** Object Transform data ******************* */ - -/* Little helper function for ObjectToTransData used to give certain - * constraints (ChildOf, FollowPath, and others that may be added) - * inverse corrections for transform, so that they aren't in CrazySpace. - * These particular constraints benefit from this, but others don't, hence - * this semi-hack ;-) - Aligorith - */ -static short constraints_list_needinv(TransInfo *t, ListBase *list) -{ - bConstraint *con; - - /* loop through constraints, checking if there's one of the mentioned - * constraints needing special crazyspace corrections - */ - if (list) { - for (con= list->first; con; con=con->next) { - /* only consider constraint if it is enabled, and has influence on result */ - if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0)) { - /* (affirmative) returns for specific constraints here... */ - /* constraints that require this regardless */ - if (con->type == CONSTRAINT_TYPE_CHILDOF) return 1; - if (con->type == CONSTRAINT_TYPE_FOLLOWPATH) return 1; - if (con->type == CONSTRAINT_TYPE_CLAMPTO) return 1; - - /* constraints that require this only under special conditions */ - if (con->type == CONSTRAINT_TYPE_ROTLIKE) { - /* CopyRot constraint only does this when rotating, and offset is on */ - bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data; - - if ((data->flag & ROTLIKE_OFFSET) && (t->mode == TFM_ROTATION)) - return 1; - } - } - } - } - - /* no appropriate candidates found */ - return 0; -} - -/* transcribe given object into TransData for Transforming */ -static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) -{ - Object *track; - ListBase fakecons = {NULL, NULL}; - float obmtx[3][3]; - short constinv; - short skip_invert = 0; - - /* axismtx has the real orientation */ - Mat3CpyMat4(td->axismtx, ob->obmat); - Mat3Ortho(td->axismtx); - - td->con= ob->constraints.first; - - /* hack: tempolarily disable tracking and/or constraints when getting - * object matrix, if tracking is on, or if constraints don't need - * inverse correction to stop it from screwing up space conversion - * matrix later - */ - constinv = constraints_list_needinv(t, &ob->constraints); - - /* disable constraints inversion for dummy pass */ - if (t->mode == TFM_DUMMY) - skip_invert = 1; - - if (skip_invert == 0 && (ob->track || constinv==0)) { - track= ob->track; - ob->track= NULL; - - if (constinv == 0) { - fakecons.first = ob->constraints.first; - fakecons.last = ob->constraints.last; - ob->constraints.first = ob->constraints.last = NULL; - } - - where_is_object(ob); - - if (constinv == 0) { - ob->constraints.first = fakecons.first; - ob->constraints.last = fakecons.last; - } - - ob->track= track; - } - else - where_is_object(ob); - - td->ob = ob; - - td->loc = ob->loc; - VECCOPY(td->iloc, td->loc); - - td->ext->rot = ob->rot; - VECCOPY(td->ext->irot, ob->rot); - VECCOPY(td->ext->drot, ob->drot); - - td->ext->size = ob->size; - VECCOPY(td->ext->isize, ob->size); - VECCOPY(td->ext->dsize, ob->dsize); - - VECCOPY(td->center, ob->obmat[3]); - - Mat4CpyMat4(td->ext->obmat, ob->obmat); - - /* is there a need to set the global<->data space conversion matrices? */ - if (ob->parent || constinv) { - float totmat[3][3], obinv[3][3]; - - /* Get the effect of parenting, and/or certain constraints. - * NOTE: some Constraints, and also Tracking should never get this - * done, as it doesn't work well. - */ - object_to_mat3(ob, obmtx); - Mat3CpyMat4(totmat, ob->obmat); - Mat3Inv(obinv, totmat); - Mat3MulMat3(td->smtx, obmtx, obinv); - Mat3Inv(td->mtx, td->smtx); - } - else { - /* no conversion to/from dataspace */ - Mat3One(td->smtx); - Mat3One(td->mtx); - } - - /* set active flag */ - if (BASACT && BASACT->object == ob) - { - td->flag |= TD_ACTIVE; - } - -#ifdef WITH_VERSE - if(ob->vnode) { - td->verse = (void*)ob; - td->flag |= TD_VERSE_OBJECT; - } - else - td->flag &= ~TD_VERSE_OBJECT; -#endif -} - - -/* sets flags in Bases to define whether they take part in transform */ -/* it deselects Bases, so we have to call the clear function always after */ -static void set_trans_object_base_flags(TransInfo *t) -{ - /* - if Base selected and has parent selected: - base->flag= BA_WAS_SEL - */ - Base *base; - - /* don't do it if we're not actually going to recalculate anything */ - if(t->mode == TFM_DUMMY) - return; - - /* makes sure base flags and object flags are identical */ - copy_baseflags(); - - /* handle pending update events, otherwise they got copied below */ - for (base= FIRSTBASE; base; base= base->next) { - if(base->object->recalc) - object_handle_update(base->object); - } - - for (base= FIRSTBASE; base; base= base->next) { - base->flag &= ~BA_WAS_SEL; - - if(TESTBASELIB(base)) { - Object *ob= base->object; - Object *parsel= ob->parent; - - /* if parent selected, deselect */ - while(parsel) { - if(parsel->flag & SELECT) break; - parsel= parsel->parent; - } - - if(parsel) - { - if (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL) - { - base->flag |= BA_TRANSFORM_CHILD; - } - else - { - base->flag &= ~SELECT; - base->flag |= BA_WAS_SEL; - } - } - /* used for flush, depgraph will change recalcs if needed :) */ - ob->recalc |= OB_RECALC_OB; - } - } - - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DAG_scene_flush_update(G.scene, -1, 0); - - /* and we store them temporal in base (only used for transform code) */ - /* this because after doing updates, the object->recalc is cleared */ - for (base= FIRSTBASE; base; base= base->next) { - if(base->object->recalc & OB_RECALC_OB) - base->flag |= BA_HAS_RECALC_OB; - if(base->object->recalc & OB_RECALC_DATA) - base->flag |= BA_HAS_RECALC_DATA; - } -} - -static void clear_trans_object_base_flags(void) -{ - Base *base; - - base= FIRSTBASE; - while(base) { - if(base->flag & BA_WAS_SEL) base->flag |= SELECT; - base->flag &= ~(BA_WAS_SEL|BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA|BA_DO_IPO|BA_TRANSFORM_CHILD); - - base = base->next; - } -} - -/* auto-keyframing feature - checks for whether anything should be done for the current frame */ -short autokeyframe_cfra_can_key(Object *ob) -{ - ListBase keys = {NULL, NULL}; - ActKeyColumn *ak; - float cfra; - short found= 0; - - /* only filter if auto-key mode requires this */ - if (IS_AUTOKEY_ON == 0) - return 0; - else if (IS_AUTOKEY_MODE(NORMAL)) - return 1; - - /* sanity check */ - if (ob == NULL) - return 0; - - /* get keyframes that object has (bone anim is stored on ob too) */ - if (ob->action) - action_to_keylist(ob->action, &keys, NULL, NULL); - else if (ob->ipo) - ipo_to_keylist(ob->ipo, &keys, NULL, NULL); - else - return 0; - - /* get current frame (will apply nla-scaling as necessary) */ - // ack... this is messy... - cfra= frame_to_float(CFRA); - cfra= get_action_frame(ob, cfra); - - /* check if a keyframe occurs on current frame */ - for (ak= keys.first; ak; ak= ak->next) { - if (IS_EQ(cfra, ak->cfra)) { - found= 1; - break; - } - } - - /* free temp list */ - BLI_freelistN(&keys); - - return found; -} - -/* auto-keyframing feature - for objects - * tmode: should be a transform mode - */ -void autokeyframe_ob_cb_func(Object *ob, int tmode) -{ - ID *id= (ID *)(ob); - IpoCurve *icu; - - if (autokeyframe_cfra_can_key(ob)) { - char *actname = NULL; - short flag = 0; - - if (ob->ipoflag & OB_ACTION_OB) - actname= "Object"; - - if (IS_AUTOKEY_FLAG(INSERTNEEDED)) - flag |= INSERTKEY_NEEDED; - if (IS_AUTOKEY_FLAG(AUTOMATKEY)) - flag |= INSERTKEY_MATRIX; - - if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { - /* only key on available channels */ - if ((ob->ipo) || (ob->action)) { - if (ob->action && actname) { - bActionChannel *achan; - achan= get_action_channel(ob->action, actname); - - if (achan && achan->ipo) - icu= achan->ipo->curve.first; - else - icu= NULL; - } - else - icu= ob->ipo->curve.first; - - for (; icu; icu= icu->next) { - icu->flag &= ~IPO_SELECT; - insertkey(id, ID_OB, actname, NULL, icu->adrcode, flag); - } - } - } - else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) { - short doLoc=0, doRot=0, doScale=0; - - /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */ - if (tmode == TFM_TRANSLATION) { - doLoc = 1; - } - else if (tmode == TFM_ROTATION) { - if (G.vd->around == V3D_ACTIVE) { - if (ob != OBACT) - doLoc = 1; - } - else if (G.vd->around == V3D_CURSOR) - doLoc = 1; - - if ((G.vd->flag & V3D_ALIGN)==0) - doRot = 1; - } - else if (tmode == TFM_RESIZE) { - if (G.vd->around == V3D_ACTIVE) { - if (ob != OBACT) - doLoc = 1; - } - else if (G.vd->around == V3D_CURSOR) - doLoc = 1; - - if ((G.vd->flag & V3D_ALIGN)==0) - doScale = 1; - } - - if (doLoc) { - insertkey(id, ID_OB, actname, NULL, OB_LOC_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_LOC_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_LOC_Z, flag); - } - if (doRot) { - insertkey(id, ID_OB, actname, NULL, OB_ROT_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_ROT_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_ROT_Z, flag); - } - if (doScale) { - insertkey(id, ID_OB, actname, NULL, OB_SIZE_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z, flag); - } - } - else { - insertkey(id, ID_OB, actname, NULL, OB_LOC_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_LOC_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_LOC_Z, flag); - - insertkey(id, ID_OB, actname, NULL, OB_ROT_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_ROT_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_ROT_Z, flag); - - insertkey(id, ID_OB, actname, NULL, OB_SIZE_X, flag); - insertkey(id, ID_OB, actname, NULL, OB_SIZE_Y, flag); - insertkey(id, ID_OB, actname, NULL, OB_SIZE_Z, flag); - } - - remake_object_ipos(ob); - allqueue(REDRAWMARKER, 0); - allqueue(REDRAWOOPS, 0); - } -} - -/* auto-keyframing feature - for poses/pose-channels - * tmode: should be a transform mode - * targetless_ik: has targetless ik been done on any channels? - */ -void autokeyframe_pose_cb_func(Object *ob, int tmode, short targetless_ik) -{ - ID *id= (ID *)(ob); - bArmature *arm= ob->data; - bAction *act; - bPose *pose; - bPoseChannel *pchan; - IpoCurve *icu; - - pose= ob->pose; - act= ob->action; - - if (autokeyframe_cfra_can_key(ob)) { - short flag= 0; - - if (act == NULL) - act= ob->action= add_empty_action("Action"); - - if (IS_AUTOKEY_FLAG(INSERTNEEDED)) - flag |= INSERTKEY_NEEDED; - if (IS_AUTOKEY_FLAG(AUTOMATKEY)) - flag |= INSERTKEY_MATRIX; - - for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - /* clear any 'unkeyed' flag it may have */ - pchan->bone->flag &= ~BONE_UNKEYED; - - /* only insert into available channels? */ - if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { - bActionChannel *achan; - - achan= get_action_channel(act, pchan->name); - if (achan && achan->ipo) { - for (icu= achan->ipo->curve.first; icu; icu= icu->next) - insertkey(id, ID_PO, pchan->name, NULL, icu->adrcode, flag); - } - } - /* only insert keyframe if needed? */ - else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) { - short doLoc=0, doRot=0, doScale=0; - - /* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */ - if (tmode == TFM_TRANSLATION) { - if (targetless_ik) - doRot= 1; - else - doLoc = 1; - } - else if (tmode == TFM_ROTATION) { - if (ELEM(G.vd->around, V3D_CURSOR, V3D_ACTIVE)) - doLoc = 1; - - if ((G.vd->flag & V3D_ALIGN)==0) - doRot = 1; - } - else if (tmode == TFM_RESIZE) { - if (ELEM(G.vd->around, V3D_CURSOR, V3D_ACTIVE)) - doLoc = 1; - - if ((G.vd->flag & V3D_ALIGN)==0) - doScale = 1; - } - - if (doLoc) { - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, flag); - } - if (doRot) { - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, flag); - } - if (doScale) { - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, flag); - } - } - /* insert keyframe in any channel that's appropriate */ - else { - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_SIZE_Z, flag); - - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_W, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_QUAT_Z, flag); - - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_X, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Y, flag); - insertkey(id, ID_PO, pchan->name, NULL, AC_LOC_Z, flag); - } - } - } - - remake_action_ipos(act); - allqueue(REDRAWMARKER, 0); - allqueue(REDRAWOOPS, 0); - - /* locking can be disabled */ - ob->pose->flag &= ~(POSE_DO_UNLOCK|POSE_LOCKED); - - /* do the bone paths */ - if (arm->pathflag & ARM_PATH_ACFRA) { - //pose_clear_paths(ob); - pose_recalculate_paths(ob); - } - } - else { - /* tag channels that should have unkeyed data */ - for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) { - if (pchan->bone->flag & BONE_TRANSFORM) { - /* tag this channel */ - pchan->bone->flag |= BONE_UNKEYED; - } - } - } -} - -/* very bad call!!! - copied from editnla.c! */ -static void recalc_all_ipos(void) -{ - Ipo *ipo; - IpoCurve *icu; - - /* Go to each ipo */ - for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){ - for (icu = ipo->curve.first; icu; icu=icu->next){ - sort_time_ipocurve(icu); - testhandles_ipocurve(icu); - } - } -} - -/* inserting keys, refresh ipo-keys, pointcache, redraw events... (ton) */ -/* note: transdata has been freed already! */ -void special_aftertrans_update(TransInfo *t) -{ - Object *ob; - Base *base; - short redrawipo=0, resetslowpar=1; - int cancelled= (t->state == TRANS_CANCEL); - short duplicate= (t->undostr && strstr(t->undostr, "Duplicate")) ? 1 : 0; - - if (t->spacetype==SPACE_VIEW3D) { - if (G.obedit) { - if (cancelled==0) { - EM_automerge(1); - /* when snapping, delay retopo until after automerge */ - if (G.qual & LR_CTRLKEY) { - retopo_do_all(); - } - } - } - } - if (t->spacetype == SPACE_ACTION) { - void *data; - short datatype; - - /* determine what type of data we are operating on */ - data = get_action_context(&datatype); - if (data == NULL) return; - ob = OBACT; - - if (datatype == ACTCONT_ACTION) { - /* Depending on the lock status, draw necessary views */ - if (ob) { - ob->ctime= -1234567.0f; - - if(ob->pose || ob_get_key(ob)) - DAG_object_flush_update(G.scene, ob, OB_RECALC); - else - DAG_object_flush_update(G.scene, ob, OB_RECALC_OB); - } - - /* Do curve cleanups? */ - if ( (G.saction->flag & SACTION_NOTRANSKEYCULL)==0 && - ((cancelled == 0) || (duplicate)) ) - { - posttrans_action_clean((bAction *)data); - } - - /* Do curve updates */ - remake_action_ipos((bAction *)data); - } - else if (datatype == ACTCONT_SHAPEKEY) { - /* fix up the Ipocurves and redraw stuff */ - Key *key= (Key *)data; - if (key->ipo) { - IpoCurve *icu; - - if ( (G.saction->flag & SACTION_NOTRANSKEYCULL)==0 && - ((cancelled == 0) || (duplicate)) ) - { - posttrans_ipo_clean(key->ipo); - } - - for (icu = key->ipo->curve.first; icu; icu=icu->next) { - sort_time_ipocurve(icu); - testhandles_ipocurve(icu); - } - } - - DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA); - } - else if (datatype == ACTCONT_GPENCIL) { - /* remove duplicate frames and also make sure points are in order! */ - if ((cancelled == 0) || (duplicate)) - { - ScrArea *sa; - - /* BAD... we need to loop over all screen areas for current screen... - * - sync this with actdata_filter_gpencil() in editaction.c - */ - for (sa= G.curscreen->areabase.first; sa; sa= sa->next) { - bGPdata *gpd= gpencil_data_getactive(sa); - - if (gpd) - posttrans_gpd_clean(gpd); - } - } - } - - G.saction->flag &= ~SACTION_MOVING; - } - else if (t->spacetype == SPACE_NLA) { - recalc_all_ipos(); // bad - synchronize_action_strips(); - - /* cleanup */ - for (base=G.scene->base.first; base; base=base->next) - base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA); - - /* after transform, remove duplicate keyframes on a frame that resulted from transform */ - if ( (G.snla->flag & SNLA_NOTRANSKEYCULL)==0 && - ((cancelled == 0) || (duplicate)) ) - { - posttrans_nla_clean(t); - } - } - else if (t->spacetype == SPACE_IPO) { - // FIXME! is there any code from the old transform_ipo that needs to be added back? - - /* after transform, remove duplicate keyframes on a frame that resulted from transform */ - if (G.sipo->ipo) - { - if ( (G.sipo->flag & SIPO_NOTRANSKEYCULL)==0 && - (cancelled == 0) ) - { - /* NOTE: no need to do NLA scaling stuff here, as when there is NLA scaling, - * the transformed handles will get moved wrong (seem to match wrong repeat cycle) - */ - posttrans_ipo_clean(G.sipo->ipo); - } - } - - /* resetting slow-parents isn't really necessary when editing sequence ipo's */ - if (G.sipo->blocktype==ID_SEQ) - resetslowpar= 0; - } - else if (G.obedit) { - if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) - allqueue(REDRAWBUTSEDIT, 0); - - /* table needs to be created for each edit command, since vertices can move etc */ - mesh_octree_table(G.obedit, NULL, 'e'); - } - else if ((t->flag & T_POSE) && (t->poseobj)) { - bArmature *arm; - bPose *pose; - bPoseChannel *pchan; - short targetless_ik= 0; - - ob= t->poseobj; - arm= ob->data; - pose= ob->pose; - - /* this signal does one recalc on pose, then unlocks, so ESC or edit will work */ - pose->flag |= POSE_DO_UNLOCK; - - /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ - if (!cancelled && t->mode==TFM_TRANSLATION) - targetless_ik= apply_targetless_ik(ob); - else { - /* not forget to clear the auto flag */ - for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) { - bKinematicConstraint *data= has_targetless_ik(pchan); - if(data) data->flag &= ~CONSTRAINT_IK_AUTO; - } - } - - if (t->mode==TFM_TRANSLATION) - pose_grab_with_ik_clear(ob); - - /* automatic inserting of keys and unkeyed tagging - only if transform wasn't cancelled (or TFM_DUMMY) */ - if (!cancelled && (t->mode != TFM_DUMMY)) { - autokeyframe_pose_cb_func(ob, t->mode, targetless_ik); - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - } - else if (arm->flag & ARM_DELAYDEFORM) { - /* old optimize trick... this enforces to bypass the depgraph */ - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - ob->recalc= 0; // is set on OK position already by recalcData() - } - else - DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA); - - if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE) - allqueue(REDRAWBUTSEDIT, 0); - - } - else if(G.f & G_PARTICLEEDIT) { - ; - } - else { - base= FIRSTBASE; - - while (base) { - - if(base->flag & BA_DO_IPO) redrawipo= 1; - - ob= base->object; - - if(base->flag & SELECT && (t->mode != TFM_DUMMY)) { - if(BKE_ptcache_object_reset(ob, PTCACHE_RESET_DEPSGRAPH)) - ob->recalc |= OB_RECALC_DATA; - - /* Set autokey if necessary */ - if (!cancelled) - autokeyframe_ob_cb_func(ob, t->mode); - } - - base= base->next; - } - - } - - clear_trans_object_base_flags(); - - if (redrawipo) { - allqueue(REDRAWNLA, 0); - allqueue(REDRAWACTION, 0); - allqueue(REDRAWIPO, 0); - } - - if(resetslowpar) - reset_slowparents(); - - /* note; should actually only be done for all objects when a lamp is moved... (ton) */ - if(t->spacetype==SPACE_VIEW3D && G.vd->drawtype == OB_SHADED) - reshadeall_displist(); -} - -static void createTransObject(TransInfo *t) -{ - TransData *td = NULL; - TransDataExtension *tx; - Object *ob; - Base *base; - IpoKey *ik; - ListBase elems; - - set_trans_object_base_flags(t); - - /* count */ - for(base= FIRSTBASE; base; base= base->next) { - if TESTBASE(base) { - ob= base->object; - - /* store ipo keys? */ - if ((ob->id.lib == 0) && (ob->ipo) && (ob->ipo->showkey) && (ob->ipoflag & OB_DRAWKEY)) { - elems.first= elems.last= NULL; - make_ipokey_transform(ob, &elems, 1); /* '1' only selected keys */ - - pushdata(&elems, sizeof(ListBase)); - - for(ik= elems.first; ik; ik= ik->next) - t->total++; - - if(elems.first==NULL) - t->total++; - } - else { - t->total++; - } - } - } - - if(!t->total) { - /* clear here, main transform function escapes too */ - clear_trans_object_base_flags(); - return; - } - - td = t->data = MEM_callocN(t->total*sizeof(TransData), "TransOb"); - tx = t->ext = MEM_callocN(t->total*sizeof(TransDataExtension), "TransObExtension"); - - for(base= FIRSTBASE; base; base= base->next) { - if TESTBASE(base) { - ob= base->object; - - td->flag = TD_SELECTED; - td->protectflag= ob->protectflag; - td->ext = tx; - - if (base->flag & BA_TRANSFORM_CHILD) - { - td->flag |= TD_NOCENTER; - td->flag |= TD_NO_LOC; - } - - /* select linked objects, but skip them later */ - if (ob->id.lib != 0) { - td->flag |= TD_SKIP; - } - - /* store ipo keys? */ - if((ob->id.lib == 0) && (ob->ipo) && (ob->ipo->showkey) && (ob->ipoflag & OB_DRAWKEY)) { - - popfirst(&elems); // bring back pushed listbase - - if(elems.first) { - int cfraont; - int ipoflag; - - base->flag |= BA_DO_IPO+BA_WAS_SEL; - base->flag &= ~SELECT; - - cfraont= CFRA; - set_no_parent_ipo(1); - ipoflag= ob->ipoflag; - ob->ipoflag &= ~OB_OFFS_OB; - - /* - * This is really EVIL code that pushes down Object values - * (loc, dloc, orig, size, dsize, rot, drot) - * */ - - pushdata((void*)ob->loc, 7 * 3 * sizeof(float)); // tsk! tsk! - - for(ik= elems.first; ik; ik= ik->next) { - - /* weak... this doesn't correct for floating values, giving small errors */ - CFRA= (int)(ik->val/G.scene->r.framelen); - - do_ob_ipo(ob); - ObjectToTransData(t, td, ob); // does where_is_object() - - td->flag= TD_SELECTED; - - td->tdi= MEM_callocN(sizeof(TransDataIpokey), "TransDataIpokey"); - /* also does tdi->flag and oldvals, needs to be after ob_to_transob()! */ - ipokey_to_transdata(ik, td); - - td++; - tx++; - if(ik->next) td->ext= tx; // prevent corrupting mem! - } - free_ipokey(&elems); - - poplast(ob->loc); - set_no_parent_ipo(0); - - CFRA= cfraont; - ob->ipoflag= ipoflag; - - where_is_object(ob); // restore - } - else { - ObjectToTransData(t, td, ob); - td->tdi = NULL; - td->val = NULL; - td++; - tx++; - } - } - else { - ObjectToTransData(t, td, ob); - td->tdi = NULL; - td->val = NULL; - td++; - tx++; - } - } - } -} - -void createTransData(TransInfo *t) -{ - Object *ob= OBACT; - - if (t->context == CTX_TEXTURE) { - t->flag |= T_TEXTURE; - createTransTexspace(t); - } - else if (t->context == CTX_EDGE) { - t->ext = NULL; - t->flag |= T_EDIT; - createTransEdge(t); - if(t->data && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); - } - } - else if (t->context == CTX_BMESH) { - createTransBMeshVerts(t, G.editBMesh->bm, G.editBMesh->td); - } - else if (t->spacetype == SPACE_IMAGE) { - t->flag |= T_POINTS|T_2D_EDIT; - createTransUVs(t); - if(t->data && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); - } - } - else if (t->spacetype == SPACE_ACTION) { - t->flag |= T_POINTS|T_2D_EDIT; - createTransActionData(t); - } - else if (t->spacetype == SPACE_NLA) { - t->flag |= T_POINTS|T_2D_EDIT; - createTransNlaData(t); - } - else if (t->spacetype == SPACE_IPO) { - t->flag |= T_POINTS|T_2D_EDIT; - createTransIpoData(t); - if (t->data && (t->flag & T_PROP_EDIT)) { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); - } - } - else if (G.obedit) { - t->ext = NULL; - if (G.obedit->type == OB_MESH) { - createTransEditVerts(t); - } - else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) { - createTransCurveVerts(t); - } - else if (G.obedit->type==OB_LATTICE) { - createTransLatticeVerts(t); - } - else if (G.obedit->type==OB_MBALL) { - createTransMBallVerts(t); - } - else if (G.obedit->type==OB_ARMATURE) { - t->flag &= ~T_PROP_EDIT; - createTransArmatureVerts(t); - } - else { - printf("not done yet! only have mesh surface curve lattice mball armature\n"); - } - - if(t->data && t->flag & T_PROP_EDIT) { - if (ELEM(G.obedit->type, OB_CURVE, OB_MESH)) { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 0); - sort_trans_data_dist(t); - } - else { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); - } - } - - t->flag |= T_EDIT|T_POINTS; - - /* exception... hackish, we want bonesize to use bone orientation matrix (ton) */ - if(t->mode==TFM_BONESIZE) { - t->flag &= ~(T_EDIT|T_POINTS); - t->flag |= T_POSE; - t->poseobj= ob; /* <- tsk tsk, this is going to give issues one day */ - } - } - else if (ob && (ob->flag & OB_POSEMODE)) { - createTransPose(t, OBACT); - } - else if (G.f & G_WEIGHTPAINT) { - /* exception, we look for the one selected armature */ - Base *base; - for(base=FIRSTBASE; base; base= base->next) { - if(TESTBASELIB(base)) { - if(base->object->type==OB_ARMATURE) - if(base->object->flag & OB_POSEMODE) - break; - } - } - if(base) { - createTransPose(t, base->object); - } - } - else if (G.f & G_PARTICLEEDIT && PE_can_edit(PE_get_current(ob))) { - createTransParticleVerts(t); - - if(t->data && t->flag & T_PROP_EDIT) { - sort_trans_data(t); // makes selected become first in array - set_prop_dist(t, 1); - sort_trans_data_dist(t); - } - - t->flag |= T_POINTS; - } - else { - t->flag &= ~T_PROP_EDIT; /* no proportional edit in object mode */ - createTransObject(t); - t->flag |= T_OBJECT; - } - - if((t->flag & T_OBJECT) && G.vd->camera==OBACT && G.vd->persp==V3D_CAMOB) { - t->flag |= T_CAMERA; - } - - /* temporal...? */ - G.scene->recalc |= SCE_PRV_CHANGED; /* test for 3d preview */ -} - - - - |