=== Transform Snap ===
Snapping for object mode Changes: - Transform snap now working in object mode and not just mesh edit mode - Shift-Tab can be used to toggle snap on/off inside transform too (no more Esc,toggle,restart) - Object mode snap: Closest uses the bounding box corners of all selected objects, Median uses object center and Center uses transform center (same as edit mode). - Object mode snap: all visible meshes can be used to get the snapping point (unlike edit mode snap which is limited to selected mesh: this might be adjusted to make edit mode snap use all visible too). To Do: - Add "Active" snap target method: use active object (or mesh element) as snap target - Add snapping capabilities to Scale - (Maybe) Add "Near pointer" snap target method: use selected element that is closest to mouse pointer as snap target. Active could probably accomplish that already in a less confusing manner, so I might skip this.
This commit is contained in:
@@ -90,6 +90,8 @@ void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text);
|
||||
void BIF_setLocalAxisConstraint(char axis, char *text);
|
||||
void BIF_setLocalLockConstraint(char axis, char *text);
|
||||
|
||||
int BIF_snappingSupported(void);
|
||||
|
||||
struct TransformOrientation;
|
||||
|
||||
void BIF_clearTransformOrientation(void);
|
||||
|
||||
@@ -122,7 +122,7 @@ typedef struct TransDataExtension {
|
||||
float iquat[4]; /* Initial rotation quaternion */
|
||||
float *size; /* Size of the data to transform (Faculative) */
|
||||
float isize[3]; /* Initial size */
|
||||
float obmat[3][3]; /* Object matrix */
|
||||
float obmat[4][4]; /* Object matrix */
|
||||
} TransDataExtension;
|
||||
|
||||
typedef struct TransData2D {
|
||||
|
||||
@@ -1818,7 +1818,7 @@ static uiBlock *view3d_transformmenu(void *arg_unused)
|
||||
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center Cursor", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
|
||||
}
|
||||
|
||||
if (G.obedit != NULL && G.obedit->type==OB_MESH)
|
||||
if (BIF_snappingSupported())
|
||||
{
|
||||
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
@@ -5476,7 +5476,7 @@ void view3d_buttons(void)
|
||||
}
|
||||
|
||||
/* Snap */
|
||||
if(G.obedit && (G.obedit->type == OB_MESH)) { // Only Mesh for now
|
||||
if (BIF_snappingSupported()) {
|
||||
uiBlockBeginAlign(block);
|
||||
|
||||
if (G.scene->snap_flag & SCE_SNAP) {
|
||||
|
||||
@@ -1570,8 +1570,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
|
||||
/* Shift-Tabe handling (other cases are in toets) */
|
||||
if (G.qual == LR_SHIFTKEY)
|
||||
{
|
||||
/* Snap toggle (only edit mesh right now) */
|
||||
if (G.obedit && G.obedit->type==OB_MESH)
|
||||
/* Snap toggle only when supported */
|
||||
if (BIF_snappingSupported())
|
||||
{
|
||||
G.scene->snap_flag ^= SCE_SNAP;
|
||||
allqueue(REDRAWHEADERS, 0);
|
||||
|
||||
@@ -2861,6 +2861,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
|
||||
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) {
|
||||
|
||||
@@ -90,10 +90,22 @@ float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
|
||||
float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
|
||||
|
||||
// Trickery
|
||||
int findNearestVertFromObjects(int *dist, float *loc);
|
||||
int findNearestVertFromObjects(int *dist, float *loc, int selected);
|
||||
|
||||
/****************** IMPLEMENTATIONS *********************/
|
||||
|
||||
int BIF_snappingSupported(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (G.obedit == NULL || G.obedit->type==OB_MESH) /* only support object or mesh */
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void drawSnapping(TransInfo *t)
|
||||
{
|
||||
if ((t->tsnap.status & (SNAP_ON|POINT_INIT|TARGET_INIT)) == (SNAP_ON|POINT_INIT|TARGET_INIT) &&
|
||||
@@ -168,7 +180,13 @@ int handleSnapping(TransInfo *t, int event)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
// Put keyhandling code here
|
||||
if (BIF_snappingSupported() && event == TABKEY && (G.qual & LR_SHIFTKEY) == LR_SHIFTKEY)
|
||||
{
|
||||
/* toggle snap and reinit */
|
||||
G.scene->snap_flag ^= SCE_SNAP;
|
||||
initSnapping(t);
|
||||
status = 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -211,10 +229,19 @@ void initSnapping(TransInfo *t)
|
||||
if (t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) { // Only 3D view or UV
|
||||
setSnappingCallback(t);
|
||||
|
||||
/* Edit mode */
|
||||
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
|
||||
(G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
|
||||
(G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
|
||||
(t->flag & T_PROP_EDIT) == 0) // No PET, obviously
|
||||
(G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
|
||||
((t->flag & T_PROP_EDIT) == 0) ) // No PET, obviously
|
||||
{
|
||||
t->tsnap.status |= SNAP_ON;
|
||||
t->tsnap.modePoint = SNAP_GEO;
|
||||
}
|
||||
/* Object mode */
|
||||
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
|
||||
(G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
|
||||
(G.obedit == NULL) ) // Object Mode
|
||||
{
|
||||
t->tsnap.status |= SNAP_ON;
|
||||
t->tsnap.modePoint = SNAP_GEO;
|
||||
@@ -364,7 +391,28 @@ void CalcSnapGrid(TransInfo *t, float *vec)
|
||||
|
||||
void CalcSnapGeometry(TransInfo *t, float *vec)
|
||||
{
|
||||
if (G.obedit != NULL && G.obedit->type==OB_MESH)
|
||||
if (G.obedit == NULL)
|
||||
{
|
||||
if (t->spacetype == SPACE_VIEW3D)
|
||||
{
|
||||
float vec[3];
|
||||
int found = 0;
|
||||
int dist = 40; // Use a user defined value here
|
||||
|
||||
found = findNearestVertFromObjects(&dist, vec, 0);
|
||||
if (found == 1)
|
||||
{
|
||||
VECCOPY(t->tsnap.snapPoint, vec);
|
||||
|
||||
t->tsnap.status |= POINT_INIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->tsnap.status &= ~POINT_INIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (G.obedit != NULL && G.obedit->type==OB_MESH)
|
||||
{
|
||||
/*if (G.scene->selectmode & B_SEL_VERT)*/
|
||||
|
||||
@@ -378,7 +426,7 @@ void CalcSnapGeometry(TransInfo *t, float *vec)
|
||||
// use findnearestverts in vert mode, others in other modes
|
||||
nearest = findnearestvert(&dist, SELECT, 1);
|
||||
|
||||
found = findNearestVertFromObjects(&dist, vec);
|
||||
found = findNearestVertFromObjects(&dist, vec, SELECT);
|
||||
if (found == 1)
|
||||
{
|
||||
VECCOPY(t->tsnap.snapPoint, vec);
|
||||
@@ -479,7 +527,7 @@ void TargetSnapMedian(TransInfo *t)
|
||||
|
||||
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
|
||||
{
|
||||
VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->iloc);
|
||||
VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->center);
|
||||
}
|
||||
|
||||
VecMulf(t->tsnap.snapTarget, 1.0 / t->total);
|
||||
@@ -500,28 +548,42 @@ void TargetSnapClosest(TransInfo *t)
|
||||
{
|
||||
TransData *closest = NULL, *td = NULL;
|
||||
|
||||
// Base case, only one selected item
|
||||
if (t->total == 1)
|
||||
/* Object mode */
|
||||
if (t->flag & T_OBJECT)
|
||||
{
|
||||
VECCOPY(t->tsnap.snapTarget, t->data[0].iloc);
|
||||
|
||||
if(t->flag & (T_EDIT|T_POSE)) {
|
||||
Object *ob= G.obedit?G.obedit:t->poseobj;
|
||||
Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
|
||||
}
|
||||
|
||||
t->tsnap.dist = t->tsnap.distance(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
|
||||
}
|
||||
// More than one selected item
|
||||
else
|
||||
int i;
|
||||
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
|
||||
{
|
||||
struct BoundBox *bb = object_get_boundbox(td->ob);
|
||||
int j;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
float loc[3];
|
||||
float dist;
|
||||
|
||||
VECCOPY(loc, bb->vec[j]);
|
||||
Mat4MulVecfl(td->ext->obmat, loc);
|
||||
|
||||
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
|
||||
|
||||
if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
|
||||
{
|
||||
VECCOPY(t->tsnap.snapTarget, loc);
|
||||
closest = td;
|
||||
t->tsnap.dist = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
|
||||
{
|
||||
float loc[3];
|
||||
float dist;
|
||||
|
||||
VECCOPY(loc, td->iloc);
|
||||
VECCOPY(loc, td->center);
|
||||
|
||||
if(t->flag & (T_EDIT|T_POSE)) {
|
||||
Object *ob= G.obedit?G.obedit:t->poseobj;
|
||||
@@ -544,7 +606,7 @@ void TargetSnapClosest(TransInfo *t)
|
||||
}
|
||||
/*================================================================*/
|
||||
|
||||
int findNearestVertFromObjects(int *dist, float *loc) {
|
||||
int findNearestVertFromObjects(int *dist, float *loc, int selected) {
|
||||
Base *base;
|
||||
int retval = 0;
|
||||
short mval[2];
|
||||
@@ -553,7 +615,7 @@ int findNearestVertFromObjects(int *dist, float *loc) {
|
||||
|
||||
base= FIRSTBASE;
|
||||
for ( base = FIRSTBASE; base != NULL; base = base->next ) {
|
||||
if ( TESTBASE(base) && base != BASACT ) {
|
||||
if ( base != BASACT && BASE_SELECTABLE(base) && (base->flag & SELECT) == selected ) {
|
||||
Object *ob = base->object;
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
|
||||
Reference in New Issue
Block a user