2009-02-14 13:07:09 +00:00
|
|
|
/**
|
|
|
|
* $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 *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
#include "DNA_action_types.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
|
|
#include "DNA_curve_types.h"
|
|
|
|
#include "DNA_group_types.h"
|
|
|
|
#include "DNA_ipo_types.h"
|
|
|
|
#include "DNA_lattice_types.h"
|
|
|
|
#include "DNA_meta_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_modifier_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "DNA_view3d_types.h"
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
|
|
|
|
#include "BKE_action.h"
|
|
|
|
#include "BKE_anim.h"
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_armature.h"
|
|
|
|
#include "BKE_curve.h"
|
|
|
|
#include "BKE_depsgraph.h"
|
|
|
|
#include "BKE_DerivedMesh.h"
|
|
|
|
#include "BKE_displist.h"
|
|
|
|
#include "BKE_global.h"
|
|
|
|
#include "BKE_lattice.h"
|
|
|
|
#include "BKE_mesh.h"
|
|
|
|
#include "BKE_modifier.h"
|
|
|
|
#include "BKE_object.h"
|
|
|
|
#include "BKE_utildefines.h"
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
|
|
|
|
#include "ED_anim_api.h"
|
|
|
|
#include "ED_armature.h"
|
|
|
|
#include "ED_mesh.h"
|
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
#include "view3d_intern.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* ************************************************** */
|
|
|
|
/* ********************* old transform stuff ******** */
|
|
|
|
/* *********** will get replaced with new transform * */
|
|
|
|
/* ************************************************** */
|
|
|
|
|
|
|
|
typedef struct TransVert {
|
|
|
|
float *loc;
|
|
|
|
float oldloc[3], fac;
|
|
|
|
float *val, oldval;
|
|
|
|
int flag;
|
|
|
|
float *nor;
|
|
|
|
} TransVert;
|
|
|
|
|
|
|
|
static TransVert *transvmain=NULL;
|
|
|
|
static int tottrans= 0;
|
|
|
|
|
|
|
|
/* copied from editobject.c, now uses (almost) proper depgraph */
|
|
|
|
static void special_transvert_update(Scene *scene, Object *obedit)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(obedit) {
|
|
|
|
|
|
|
|
DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
|
|
|
|
|
|
|
|
if(obedit->type==OB_MESH) {
|
|
|
|
Mesh *me= obedit->data;
|
|
|
|
recalc_editnormals(me->edit_mesh); // does face centers too
|
|
|
|
}
|
|
|
|
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
Nurb *nu= cu->editnurb->first;
|
|
|
|
|
|
|
|
while(nu) {
|
|
|
|
test2DNurb(nu);
|
|
|
|
testhandlesNurb(nu); /* test for bezier too */
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(obedit->type==OB_ARMATURE){
|
|
|
|
bArmature *arm= obedit->data;
|
|
|
|
EditBone *ebo;
|
|
|
|
TransVert *tv= transvmain;
|
|
|
|
int a=0;
|
|
|
|
|
|
|
|
/* Ensure all bone tails are correctly adjusted */
|
|
|
|
for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
|
|
|
|
/* adjust tip if both ends selected */
|
|
|
|
if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
|
|
|
|
if (tv) {
|
|
|
|
float diffvec[3];
|
|
|
|
|
|
|
|
VecSubf(diffvec, tv->loc, tv->oldloc);
|
|
|
|
VecAddf(ebo->tail, ebo->tail, diffvec);
|
|
|
|
|
|
|
|
a++;
|
|
|
|
if (a<tottrans) tv++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure all bones are correctly adjusted */
|
|
|
|
for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
|
|
|
|
if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
|
|
|
|
/* If this bone has a parent tip that has been moved */
|
|
|
|
if (ebo->parent->flag & BONE_TIPSEL){
|
|
|
|
VECCOPY (ebo->head, ebo->parent->tail);
|
|
|
|
}
|
|
|
|
/* If this bone has a parent tip that has NOT been moved */
|
|
|
|
else{
|
|
|
|
VECCOPY (ebo->parent->tail, ebo->head);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(arm->flag & ARM_MIRROR_EDIT)
|
|
|
|
transform_armature_mirror_update(obedit);
|
|
|
|
}
|
|
|
|
else if(obedit->type==OB_LATTICE) {
|
|
|
|
Lattice *lt= obedit->data;
|
|
|
|
|
|
|
|
if(lt->editlatt->flag & LT_OUTSIDE)
|
|
|
|
outside_lattice(lt->editlatt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* copied from editobject.c, needs to be replaced with new transform code still */
|
|
|
|
/* mode: 1 = proportional, 2 = all joints (for bones only) */
|
|
|
|
static void make_trans_verts(Object *obedit, float *min, float *max, int mode)
|
|
|
|
{
|
|
|
|
Nurb *nu;
|
|
|
|
BezTriple *bezt;
|
|
|
|
BPoint *bp;
|
|
|
|
TransVert *tv=NULL;
|
|
|
|
MetaElem *ml;
|
|
|
|
EditVert *eve;
|
|
|
|
EditBone *ebo;
|
|
|
|
float total, center[3], centroid[3];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
tottrans= 0; // global!
|
|
|
|
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
centroid[0]=centroid[1]=centroid[2]= 0.0;
|
|
|
|
|
|
|
|
if(obedit->type==OB_MESH) {
|
|
|
|
Mesh *me= obedit->data;
|
|
|
|
EditMesh *em= me->edit_mesh;
|
|
|
|
int proptrans= 0;
|
|
|
|
|
|
|
|
// transform now requires awareness for select mode, so we tag the f1 flags in verts
|
|
|
|
tottrans= 0;
|
|
|
|
if(em->selectmode & SCE_SELECT_VERTEX) {
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
if(eve->h==0 && (eve->f & SELECT)) {
|
|
|
|
eve->f1= SELECT;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
else eve->f1= 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(em->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;
|
|
|
|
}
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* proportional edit exception... */
|
|
|
|
if((mode & 1) && tottrans) {
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
if(eve->h==0) {
|
|
|
|
eve->f1 |= 2;
|
|
|
|
proptrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(proptrans>tottrans) tottrans= proptrans;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* and now make transverts */
|
|
|
|
if(tottrans) {
|
|
|
|
tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
|
|
|
|
|
|
|
|
for(eve= em->verts.first; eve; eve= eve->next) {
|
|
|
|
if(eve->f1) {
|
|
|
|
VECCOPY(tv->oldloc, eve->co);
|
|
|
|
tv->loc= eve->co;
|
|
|
|
if(eve->no[0]!=0.0 || eve->no[1]!=0.0 ||eve->no[2]!=0.0)
|
|
|
|
tv->nor= eve->no; // note this is a hackish signal (ton)
|
|
|
|
tv->flag= eve->f1 & SELECT;
|
|
|
|
tv++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (obedit->type==OB_ARMATURE){
|
|
|
|
bArmature *arm= obedit->data;
|
|
|
|
int totmalloc= BLI_countlist(arm->edbo);
|
|
|
|
|
|
|
|
tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
|
|
|
|
|
|
|
|
for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
|
|
|
|
if(ebo->layer & arm->layer) {
|
|
|
|
short tipsel= (ebo->flag & BONE_TIPSEL);
|
|
|
|
short rootsel= (ebo->flag & BONE_ROOTSEL);
|
|
|
|
short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
|
|
|
|
|
|
|
|
if ((tipsel && rootsel) || (rootsel)) {
|
|
|
|
/* Don't add the tip (unless mode & 2, for getting all joints),
|
|
|
|
* otherwise we get zero-length bones as tips will snap to the same
|
|
|
|
* location as heads.
|
|
|
|
*/
|
|
|
|
if (rootok) {
|
|
|
|
VECCOPY (tv->oldloc, ebo->head);
|
|
|
|
tv->loc= ebo->head;
|
|
|
|
tv->nor= NULL;
|
|
|
|
tv->flag= 1;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((mode & 2) && (tipsel)) {
|
|
|
|
VECCOPY (tv->oldloc, ebo->tail);
|
|
|
|
tv->loc= ebo->tail;
|
|
|
|
tv->nor= NULL;
|
|
|
|
tv->flag= 1;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tipsel) {
|
|
|
|
VECCOPY (tv->oldloc, ebo->tail);
|
|
|
|
tv->loc= ebo->tail;
|
|
|
|
tv->nor= NULL;
|
|
|
|
tv->flag= 1;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
|
|
|
|
Curve *cu= obedit->data;
|
|
|
|
int totmalloc= 0;
|
|
|
|
|
|
|
|
for(nu= cu->editnurb->first; nu; nu= nu->next) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER)
|
|
|
|
totmalloc += 3*nu->pntsu;
|
|
|
|
else
|
|
|
|
totmalloc += nu->pntsu*nu->pntsv;
|
|
|
|
}
|
|
|
|
tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
|
|
|
|
|
|
|
|
nu= cu->editnurb->first;
|
|
|
|
while(nu) {
|
|
|
|
if((nu->type & 7)==CU_BEZIER) {
|
|
|
|
a= nu->pntsu;
|
|
|
|
bezt= nu->bezt;
|
|
|
|
while(a--) {
|
|
|
|
if(bezt->hide==0) {
|
|
|
|
if((mode & 1) || (bezt->f1 & SELECT)) {
|
|
|
|
VECCOPY(tv->oldloc, bezt->vec[0]);
|
|
|
|
tv->loc= bezt->vec[0];
|
|
|
|
tv->flag= bezt->f1 & SELECT;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
if((mode & 1) || (bezt->f2 & SELECT)) {
|
|
|
|
VECCOPY(tv->oldloc, bezt->vec[1]);
|
|
|
|
tv->loc= bezt->vec[1];
|
|
|
|
tv->val= &(bezt->alfa);
|
|
|
|
tv->oldval= bezt->alfa;
|
|
|
|
tv->flag= bezt->f2 & SELECT;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
if((mode & 1) || (bezt->f3 & SELECT)) {
|
|
|
|
VECCOPY(tv->oldloc, bezt->vec[2]);
|
|
|
|
tv->loc= bezt->vec[2];
|
|
|
|
tv->flag= bezt->f3 & SELECT;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bezt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
a= nu->pntsu*nu->pntsv;
|
|
|
|
bp= nu->bp;
|
|
|
|
while(a--) {
|
|
|
|
if(bp->hide==0) {
|
|
|
|
if((mode & 1) || (bp->f1 & SELECT)) {
|
|
|
|
VECCOPY(tv->oldloc, bp->vec);
|
|
|
|
tv->loc= bp->vec;
|
|
|
|
tv->val= &(bp->alfa);
|
|
|
|
tv->oldval= bp->alfa;
|
|
|
|
tv->flag= bp->f1 & SELECT;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nu= nu->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(obedit->type==OB_MBALL) {
|
|
|
|
MetaBall *mb= obedit->data;
|
|
|
|
int totmalloc= BLI_countlist(mb->editelems);
|
|
|
|
|
|
|
|
tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
|
|
|
|
|
|
|
|
ml= mb->editelems->first;
|
|
|
|
while(ml) {
|
|
|
|
if(ml->flag & SELECT) {
|
|
|
|
tv->loc= &ml->x;
|
|
|
|
VECCOPY(tv->oldloc, tv->loc);
|
|
|
|
tv->val= &(ml->rad);
|
|
|
|
tv->oldval= ml->rad;
|
|
|
|
tv->flag= 1;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
ml= ml->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(obedit->type==OB_LATTICE) {
|
|
|
|
Lattice *lt= obedit->data;
|
|
|
|
|
|
|
|
bp= lt->editlatt->def;
|
|
|
|
|
|
|
|
a= lt->editlatt->pntsu*lt->editlatt->pntsv*lt->editlatt->pntsw;
|
|
|
|
|
|
|
|
tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts curve");
|
|
|
|
|
|
|
|
while(a--) {
|
|
|
|
if((mode & 1) || (bp->f1 & SELECT)) {
|
|
|
|
if(bp->hide==0) {
|
|
|
|
VECCOPY(tv->oldloc, bp->vec);
|
|
|
|
tv->loc= bp->vec;
|
|
|
|
tv->flag= bp->f1 & SELECT;
|
|
|
|
tv++;
|
|
|
|
tottrans++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cent etc */
|
|
|
|
tv= transvmain;
|
|
|
|
total= 0.0;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
if(tv->flag & SELECT) {
|
|
|
|
centroid[0]+= tv->oldloc[0];
|
|
|
|
centroid[1]+= tv->oldloc[1];
|
|
|
|
centroid[2]+= tv->oldloc[2];
|
|
|
|
total+= 1.0;
|
|
|
|
DO_MINMAX(tv->oldloc, min, max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(total!=0.0) {
|
|
|
|
centroid[0]/= total;
|
|
|
|
centroid[1]/= total;
|
|
|
|
centroid[2]/= total;
|
|
|
|
}
|
|
|
|
|
|
|
|
center[0]= (min[0]+max[0])/2.0;
|
|
|
|
center[1]= (min[1]+max[1])/2.0;
|
|
|
|
center[2]= (min[2]+max[2])/2.0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *********************** operators ******************** */
|
|
|
|
|
|
|
|
static int snap_sel_to_grid(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
extern float originmat[3][3]; /* XXX object.c */
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
TransVert *tv;
|
|
|
|
Object *ob;
|
|
|
|
float gridf, imat[3][3], bmat[3][3], vec[3];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
gridf= v3d->gridview;
|
|
|
|
|
|
|
|
if(obedit) {
|
|
|
|
tottrans= 0;
|
|
|
|
|
|
|
|
if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 0);
|
|
|
|
if(tottrans==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
Mat3Inv(imat, bmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
|
|
|
|
VECCOPY(vec, tv->loc);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, obedit->obmat[3]);
|
|
|
|
vec[0]= v3d->gridview*floor(.5+ vec[0]/gridf);
|
|
|
|
vec[1]= v3d->gridview*floor(.5+ vec[1]/gridf);
|
|
|
|
vec[2]= v3d->gridview*floor(.5+ vec[2]/gridf);
|
|
|
|
VecSubf(vec, vec, obedit->obmat[3]);
|
|
|
|
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
VECCOPY(tv->loc, vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
special_transvert_update(scene, obedit);
|
|
|
|
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
|
|
|
ob= base->object;
|
|
|
|
|
|
|
|
if(ob->flag & OB_POSEMODE) {
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
bArmature *arm= ob->data;
|
|
|
|
|
|
|
|
for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
|
|
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
|
|
if(pchan->bone->layer & arm->layer) {
|
|
|
|
if((pchan->bone->flag & BONE_CONNECTED)==0) {
|
|
|
|
float vecN[3], nLoc[3];
|
|
|
|
|
|
|
|
/* get nearest grid point to snap to */
|
|
|
|
VECCOPY(nLoc, pchan->pose_mat[3]);
|
|
|
|
vec[0]= gridf * (float)(floor(.5+ nLoc[0]/gridf));
|
|
|
|
vec[1]= gridf * (float)(floor(.5+ nLoc[1]/gridf));
|
|
|
|
vec[2]= gridf * (float)(floor(.5+ nLoc[2]/gridf));
|
|
|
|
|
|
|
|
/* get bone-space location of grid point */
|
|
|
|
armature_loc_pose_to_bone(pchan, vec, vecN);
|
|
|
|
|
|
|
|
/* adjust location */
|
|
|
|
VECCOPY(pchan->loc, vecN);
|
|
|
|
}
|
|
|
|
/* if the bone has a parent and is connected to the parent,
|
|
|
|
* don't do anything - will break chain unless we do auto-ik.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
|
|
|
|
|
|
|
|
/* auto-keyframing */
|
|
|
|
// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
|
|
|
|
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->recalc |= OB_RECALC_OB;
|
|
|
|
|
|
|
|
vec[0]= -ob->obmat[3][0]+v3d->gridview*floor(.5+ ob->obmat[3][0]/gridf);
|
|
|
|
vec[1]= -ob->obmat[3][1]+v3d->gridview*floor(.5+ ob->obmat[3][1]/gridf);
|
|
|
|
vec[2]= -ob->obmat[3][2]+v3d->gridview*floor(.5+ ob->obmat[3][2]/gridf);
|
|
|
|
|
|
|
|
if(ob->parent) {
|
|
|
|
where_is_object(scene, ob);
|
|
|
|
|
|
|
|
Mat3Inv(imat, originmat);
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* auto-keyframing */
|
|
|
|
// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
|
|
|
}
|
|
|
|
ED_anim_dag_flush_update(C);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Selection to Grid";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_selected_to_grid";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_sel_to_grid;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *************************************************** */
|
|
|
|
|
|
|
|
static int snap_sel_to_curs(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
extern float originmat[3][3]; /* XXX object.c */
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
TransVert *tv;
|
|
|
|
Object *ob;
|
|
|
|
float *curs, imat[3][3], bmat[3][3], vec[3];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
if(obedit) {
|
|
|
|
tottrans= 0;
|
|
|
|
|
|
|
|
if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 0);
|
|
|
|
if(tottrans==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
Mat3Inv(imat, bmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
vec[0]= curs[0]-obedit->obmat[3][0];
|
|
|
|
vec[1]= curs[1]-obedit->obmat[3][1];
|
|
|
|
vec[2]= curs[2]-obedit->obmat[3][2];
|
|
|
|
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
VECCOPY(tv->loc, vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
special_transvert_update(scene, obedit);
|
|
|
|
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
|
|
|
ob= base->object;
|
|
|
|
if(ob->flag & OB_POSEMODE) {
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
bArmature *arm= ob->data;
|
|
|
|
float cursp[3];
|
|
|
|
|
|
|
|
Mat4Invert(ob->imat, ob->obmat);
|
|
|
|
VECCOPY(cursp, curs);
|
|
|
|
Mat4MulVecfl(ob->imat, cursp);
|
|
|
|
|
|
|
|
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
|
|
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
|
|
if(pchan->bone->layer & arm->layer) {
|
|
|
|
if((pchan->bone->flag & BONE_CONNECTED)==0) {
|
|
|
|
float curspn[3];
|
|
|
|
|
|
|
|
/* get location of cursor in bone-space */
|
|
|
|
armature_loc_pose_to_bone(pchan, cursp, curspn);
|
|
|
|
|
|
|
|
/* calculate new position */
|
|
|
|
VECCOPY(pchan->loc, curspn);
|
|
|
|
}
|
|
|
|
/* if the bone has a parent and is connected to the parent,
|
|
|
|
* don't do anything - will break chain unless we do auto-ik.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
|
|
|
|
|
|
|
|
/* auto-keyframing */
|
|
|
|
// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
|
|
|
|
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->recalc |= OB_RECALC_OB;
|
|
|
|
|
|
|
|
vec[0]= -ob->obmat[3][0] + curs[0];
|
|
|
|
vec[1]= -ob->obmat[3][1] + curs[1];
|
|
|
|
vec[2]= -ob->obmat[3][2] + curs[2];
|
|
|
|
|
|
|
|
if(ob->parent) {
|
|
|
|
where_is_object(scene, ob);
|
|
|
|
|
|
|
|
Mat3Inv(imat, originmat);
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
/* auto-keyframing */
|
|
|
|
// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
|
|
|
}
|
|
|
|
ED_anim_dag_flush_update(C);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Selection to Cursor";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_sel_to_curs;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *************************************************** */
|
|
|
|
|
|
|
|
static int snap_curs_to_grid(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
float gridf, *curs;
|
|
|
|
|
|
|
|
gridf= v3d->gridview;
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
curs[0]= v3d->gridview*floor(.5+curs[0]/gridf);
|
|
|
|
curs[1]= v3d->gridview*floor(.5+curs[1]/gridf);
|
|
|
|
curs[2]= v3d->gridview*floor(.5+curs[2]/gridf);
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Cursor to Grid";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_curs_to_grid;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* **************************************************** */
|
|
|
|
|
|
|
|
static int snap_curs_to_sel(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
TransVert *tv;
|
|
|
|
float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
|
|
|
|
int count, a;
|
|
|
|
|
|
|
|
curs= give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
count= 0;
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
centroid[0]= centroid[1]= centroid[2]= 0.0;
|
|
|
|
|
|
|
|
if(obedit) {
|
|
|
|
tottrans=0;
|
|
|
|
|
|
|
|
if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 2);
|
|
|
|
if(tottrans==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
VECCOPY(vec, tv->loc);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, obedit->obmat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(v3d->around==V3D_CENTROID) {
|
|
|
|
VecMulf(centroid, 1.0/(float)tottrans);
|
|
|
|
VECCOPY(curs, centroid);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curs[0]= (min[0]+max[0])/2;
|
|
|
|
curs[1]= (min[1]+max[1])/2;
|
|
|
|
curs[2]= (min[2]+max[2])/2;
|
|
|
|
}
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Object *ob= OBACT;
|
|
|
|
|
|
|
|
if(ob && (ob->flag & OB_POSEMODE)) {
|
|
|
|
bArmature *arm= ob->data;
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
|
|
|
|
if(arm->layer & pchan->bone->layer) {
|
|
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
|
|
VECCOPY(vec, pchan->pose_head);
|
|
|
|
Mat4MulVecfl(ob->obmat, vec);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
|
|
|
VECCOPY(vec, base->object->obmat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
|
|
|
}
|
|
|
|
if(count) {
|
|
|
|
if(v3d->around==V3D_CENTROID) {
|
|
|
|
VecMulf(centroid, 1.0/(float)count);
|
|
|
|
VECCOPY(curs, centroid);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
curs[0]= (min[0]+max[0])/2;
|
|
|
|
curs[1]= (min[1]+max[1])/2;
|
|
|
|
curs[2]= (min[2]+max[2])/2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene); // hrm
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Cursor to Selected";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_curs_to_sel;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ********************************************** */
|
|
|
|
|
|
|
|
static int snap_curs_to_active(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
float *curs;
|
|
|
|
|
|
|
|
curs = give_cursor(scene, v3d);
|
|
|
|
|
|
|
|
if (obedit) {
|
|
|
|
if (obedit->type == OB_MESH) {
|
|
|
|
/* check active */
|
|
|
|
Mesh *me= obedit->data;
|
|
|
|
EditSelection ese;
|
|
|
|
|
|
|
|
if (EM_get_actSelection(me->edit_mesh, &ese)) {
|
|
|
|
EM_editselection_center(curs, &ese);
|
|
|
|
}
|
|
|
|
|
|
|
|
Mat4MulVecfl(obedit->obmat, curs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (BASACT) {
|
|
|
|
VECCOPY(curs, BASACT->object->obmat[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SCENE|ND_TRANSFORM, scene);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Cursor to Active";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_cursor_to_active";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_curs_to_active;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************** */
|
|
|
|
|
|
|
|
static int snap_selected_to_center(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
extern float originmat[3][3]; /* XXX object.c */
|
|
|
|
Object *obedit= CTX_data_edit_object(C);
|
|
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
View3D *v3d= CTX_wm_view3d(C);
|
|
|
|
TransVert *tv;
|
|
|
|
Object *ob;
|
|
|
|
float snaploc[3], imat[3][3], bmat[3][3], vec[3], min[3], max[3], centroid[3];
|
|
|
|
int count, a;
|
|
|
|
|
|
|
|
/*calculate the snaplocation (centerpoint) */
|
|
|
|
count= 0;
|
|
|
|
INIT_MINMAX(min, max);
|
|
|
|
centroid[0]= centroid[1]= centroid[2]= 0.0f;
|
|
|
|
snaploc[0]= snaploc[1]= snaploc[2]= 0.0f;
|
|
|
|
|
|
|
|
if(obedit) {
|
|
|
|
tottrans= 0;
|
|
|
|
|
|
|
|
if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 0);
|
|
|
|
if(tottrans==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
Mat3Inv(imat, bmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
VECCOPY(vec, tv->loc);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, obedit->obmat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(v3d->around==V3D_CENTROID) {
|
|
|
|
VecMulf(centroid, 1.0/(float)tottrans);
|
|
|
|
VECCOPY(snaploc, centroid);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
snaploc[0]= (min[0]+max[0])/2;
|
|
|
|
snaploc[1]= (min[1]+max[1])/2;
|
|
|
|
snaploc[2]= (min[2]+max[2])/2;
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
|
|
|
ob= base->object;
|
|
|
|
if(ob->flag & OB_POSEMODE) {
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
bArmature *arm= ob->data;
|
|
|
|
|
|
|
|
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
|
|
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
|
|
if(pchan->bone->layer & arm->layer) {
|
|
|
|
VECCOPY(vec, pchan->pose_mat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* not armature bones (i.e. objects) */
|
|
|
|
VECCOPY(vec, base->object->obmat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
|
|
|
|
|
|
|
if(count) {
|
|
|
|
if(v3d->around==V3D_CENTROID) {
|
|
|
|
VecMulf(centroid, 1.0/(float)count);
|
|
|
|
VECCOPY(snaploc, centroid);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
snaploc[0]= (min[0]+max[0])/2;
|
|
|
|
snaploc[1]= (min[1]+max[1])/2;
|
|
|
|
snaploc[2]= (min[2]+max[2])/2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Snap the selection to the snaplocation (duh!) */
|
|
|
|
if(obedit) {
|
|
|
|
tottrans= 0;
|
|
|
|
|
|
|
|
if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 0);
|
|
|
|
if(tottrans==0) return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
Mat3Inv(imat, bmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
vec[0]= snaploc[0]-obedit->obmat[3][0];
|
|
|
|
vec[1]= snaploc[1]-obedit->obmat[3][1];
|
|
|
|
vec[2]= snaploc[2]-obedit->obmat[3][2];
|
|
|
|
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
VECCOPY(tv->loc, vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
special_transvert_update(scene, obedit);
|
|
|
|
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
|
|
|
|
CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
|
|
|
|
ob= base->object;
|
|
|
|
if(ob->flag & OB_POSEMODE) {
|
|
|
|
bPoseChannel *pchan;
|
|
|
|
bArmature *arm= ob->data;
|
|
|
|
|
|
|
|
for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
|
|
|
|
if(pchan->bone->flag & BONE_SELECTED) {
|
|
|
|
if(pchan->bone->layer & arm->layer) {
|
|
|
|
if((pchan->bone->flag & BONE_CONNECTED)==0) {
|
|
|
|
/* get location of cursor in bone-space */
|
|
|
|
armature_loc_pose_to_bone(pchan, snaploc, vec);
|
|
|
|
|
|
|
|
/* calculate new position */
|
|
|
|
VECCOPY(pchan->loc, vec);
|
|
|
|
}
|
|
|
|
/* if the bone has a parent and is connected to the parent,
|
|
|
|
* don't do anything - will break chain unless we do auto-ik.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* auto-keyframing */
|
|
|
|
ob->pose->flag |= POSE_DO_UNLOCK;
|
|
|
|
// XXX autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
|
|
|
|
DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->recalc |= OB_RECALC_OB;
|
|
|
|
|
|
|
|
vec[0]= -ob->obmat[3][0] + snaploc[0];
|
|
|
|
vec[1]= -ob->obmat[3][1] + snaploc[1];
|
|
|
|
vec[2]= -ob->obmat[3][2] + snaploc[2];
|
|
|
|
|
|
|
|
if(ob->parent) {
|
|
|
|
where_is_object(scene, ob);
|
|
|
|
|
|
|
|
Mat3Inv(imat, originmat);
|
|
|
|
Mat3MulVecfl(imat, vec);
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ob->loc[0]+= vec[0];
|
|
|
|
ob->loc[1]+= vec[1];
|
|
|
|
ob->loc[2]+= vec[2];
|
|
|
|
}
|
|
|
|
/* auto-keyframing */
|
|
|
|
// XXX autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CTX_DATA_END;
|
|
|
|
}
|
|
|
|
|
|
|
|
ED_anim_dag_flush_update(C);
|
|
|
|
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VIEW3D_OT_snap_selected_to_center(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Selection to Center";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_selected_to_center";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec= snap_selected_to_center;
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int minmax_verts(Object *obedit, float *min, float *max)
|
|
|
|
{
|
|
|
|
TransVert *tv;
|
|
|
|
float centroid[3], vec[3], bmat[3][3];
|
|
|
|
int a;
|
|
|
|
|
|
|
|
tottrans=0;
|
|
|
|
if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE)
|
|
|
|
make_trans_verts(obedit, bmat[0], bmat[1], 2);
|
|
|
|
|
|
|
|
if(tottrans==0) return 0;
|
|
|
|
|
|
|
|
Mat3CpyMat4(bmat, obedit->obmat);
|
|
|
|
|
|
|
|
tv= transvmain;
|
|
|
|
for(a=0; a<tottrans; a++, tv++) {
|
|
|
|
VECCOPY(vec, tv->loc);
|
|
|
|
Mat3MulVecfl(bmat, vec);
|
|
|
|
VecAddf(vec, vec, obedit->obmat[3]);
|
|
|
|
VecAddf(centroid, centroid, vec);
|
|
|
|
DO_MINMAX(vec, min, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(transvmain);
|
|
|
|
transvmain= NULL;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************* */
|
|
|
|
|
|
|
|
static int snap_menu_invoke(bContext *C, wmOperator *unused, wmEvent *event)
|
|
|
|
{
|
UI: Layout Engine
* Buttons are now created first, and after that the layout is computed.
This means the layout engine now works at button level, and makes it
easier to write templates. Otherwise you had to store all info and
create the buttons later.
* Added interface_templates.c as a separate file to put templates in.
These can contain regular buttons, and can be put in a Free layout,
which means you can specify manual coordinates, but still get nested
correct inside other layouts.
* API was changed to allow better nesting. Previously items were added
in the last added layout specifier, i.e. one level up in the layout
hierarchy. This doesn't work well in always, so now when creating things
like rows or columns it always returns a layout which you have to add
the items in. All py scripts were updated to follow this.
* Computing the layout now goes in two passes, first estimating the
required width/height of all nested layouts, and then in the second
pass using the results of that to decide on the actual locations.
* Enum and array buttons now follow the direction of the layout, i.e.
they are vertical or horizontal depending if they are in a column or row.
* Color properties now get a color picker, and only get the additional
RGB sliders with Expand=True.
* File/directory string properties now get a button next to them for
opening the file browse, though this is not implemented yet.
* Layout items can now be aligned, set align=True when creating a column,
row, etc.
* Buttons now get a minimum width of one icon (avoids squashing icon
buttons).
* Moved some more space variables into Style.
2009-05-15 11:19:59 +00:00
|
|
|
uiPopupMenu *pup= uiPupMenuBegin(C, "Snap", 0);
|
2009-04-22 18:39:44 +00:00
|
|
|
uiLayout *layout= uiPupMenuLayout(pup);
|
2009-02-14 13:07:09 +00:00
|
|
|
|
2009-04-22 18:39:44 +00:00
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_grid");
|
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_cursor");
|
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_selected_to_center");
|
|
|
|
uiItemS(layout);
|
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_selected");
|
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_grid");
|
|
|
|
uiItemO(layout, NULL, 0, "VIEW3D_OT_snap_cursor_to_active");
|
2009-02-14 13:07:09 +00:00
|
|
|
|
2009-04-22 18:39:44 +00:00
|
|
|
uiPupMenuEnd(C, pup);
|
2009-02-14 13:07:09 +00:00
|
|
|
|
|
|
|
/* this operator is only for a menu, not used further */
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only used as menu */
|
|
|
|
void VIEW3D_OT_snap_menu(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name= "Snap Menu";
|
|
|
|
ot->idname= "VIEW3D_OT_snap_menu";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke= snap_menu_invoke;
|
|
|
|
|
|
|
|
ot->poll= ED_operator_view3d_active;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|