This is a new incarnation of compatible_eul(), a function called: void Mat3ToCompatibleEul(float mat[][3], float *eul, float *oldrot) It uses the two euler extraction methods as added by Brecht a while ago, and checks for compatibility each, and then picks the best of the two based on minimal difference with 'oldrot'. Gives for rotation key inserting a much higher hitrate for OK eulers.
2879 lines
65 KiB
C
Executable File
2879 lines
65 KiB
C
Executable File
/**
|
|
* $Id$
|
|
*
|
|
* ***** BEGIN GPL/BL DUAL 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. The Blender
|
|
* Foundation also sells licenses for use in proprietary software under
|
|
* the Blender License. See http://www.blender.org/BL/ for information
|
|
* about this.
|
|
*
|
|
* 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/BL DUAL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#ifndef WIN32
|
|
#include <unistd.h>
|
|
#else
|
|
#include <io.h>
|
|
#endif
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_armature_types.h"
|
|
#include "DNA_ipo_types.h" /* some silly ipo flag */
|
|
#include "DNA_listBase.h"
|
|
#include "DNA_meshdata_types.h"
|
|
#include "DNA_mesh_types.h"
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_scene_types.h" /* PET modes */
|
|
#include "DNA_screen_types.h" /* area dimensions */
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_texture_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
#include "DNA_view3d_types.h"
|
|
#include "DNA_space_types.h"
|
|
|
|
#include "BIF_editview.h" /* arrows_move_cursor */
|
|
#include "BIF_gl.h"
|
|
#include "BIF_glutil.h"
|
|
#include "BIF_mywindow.h"
|
|
#include "BIF_resources.h"
|
|
#include "BIF_screen.h"
|
|
#include "BIF_space.h" /* undo */
|
|
#include "BIF_toets.h" /* persptoetsen */
|
|
#include "BIF_mywindow.h" /* warp_pointer */
|
|
#include "BIF_toolbox.h" /* notice */
|
|
#include "BIF_editmesh.h"
|
|
#include "BIF_editsima.h"
|
|
#include "BIF_drawimage.h" /* uvco_to_areaco_noclip */
|
|
|
|
#include "BKE_global.h"
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_bad_level_calls.h"/* popmenu and error */
|
|
|
|
#include "BSE_view.h"
|
|
|
|
#include "BLI_arithb.h"
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_editVert.h"
|
|
|
|
#include "PIL_time.h" /* sleep */
|
|
|
|
#include "blendef.h"
|
|
|
|
#include "mydevice.h"
|
|
|
|
#include "transform.h"
|
|
|
|
/* GLOBAL VARIABLE THAT SHOULD MOVED TO SCREEN MEMBER OR SOMETHING */
|
|
TransInfo Trans = {TFM_INIT, 0}; // enforce init on first usage
|
|
|
|
/******************************** Helper functions ************************************/
|
|
/* ************************** Dashed help line **************************** */
|
|
|
|
|
|
/* bad frontbuffer call... because it is used in transform after force_draw() */
|
|
static void helpline(TransInfo *t, float *vec)
|
|
{
|
|
float vecrot[3], cent[2];
|
|
short mval[2];
|
|
|
|
VECCOPY(vecrot, vec);
|
|
if(t->flag & T_EDIT) {
|
|
Object *ob=G.obedit;
|
|
if(ob) Mat4MulVecfl(ob->obmat, vecrot);
|
|
}
|
|
else if(t->flag & T_POSE) {
|
|
Object *ob=t->poseobj;
|
|
if(ob) Mat4MulVecfl(ob->obmat, vecrot);
|
|
}
|
|
|
|
getmouseco_areawin(mval);
|
|
projectFloatView(t, vecrot, cent); // no overflow in extreme cases
|
|
if(cent[0]!=IS_CLIPPED) {
|
|
persp(PERSP_WIN);
|
|
|
|
glDrawBuffer(GL_FRONT);
|
|
|
|
BIF_ThemeColor(TH_WIRE);
|
|
|
|
setlinestyle(3);
|
|
glBegin(GL_LINE_STRIP);
|
|
glVertex2sv(mval);
|
|
glVertex2fv(cent);
|
|
glEnd();
|
|
setlinestyle(0);
|
|
|
|
persp(PERSP_VIEW);
|
|
bglFlush(); // flush display for frontbuffer
|
|
glDrawBuffer(GL_BACK);
|
|
}
|
|
}
|
|
/* ************************** INPUT FROM MOUSE *************************** */
|
|
|
|
float InputScaleRatio(TransInfo *t, short mval[2]) {
|
|
float ratio, dx, dy;
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
dx = (float)(t->center2d[0] - t->shiftmval[0]);
|
|
dy = (float)(t->center2d[1] - t->shiftmval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
|
|
}
|
|
else {
|
|
dx = (float)(t->center2d[0] - mval[0]);
|
|
dy = (float)(t->center2d[1] - mval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
return ratio;
|
|
}
|
|
|
|
float InputHorizontalRatio(TransInfo *t, short mval[2]) {
|
|
int y, pad;
|
|
|
|
pad = curarea->winx / 10;
|
|
|
|
if (t->flag & T_SHIFT_MOD) {
|
|
/* deal with Shift key by adding motion / 10 to motion before shift press */
|
|
y = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10;
|
|
}
|
|
else {
|
|
y = mval[0];
|
|
}
|
|
return (float)(y - pad) / (float)(curarea->winx - 2 * pad);
|
|
}
|
|
|
|
float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
|
|
float vec[3];
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
short dx = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10 - t->imval[0];
|
|
short dy = t->shiftmval[1] + (mval[1] - t->shiftmval[1]) / 10 - t->imval[1];
|
|
convertViewVec(t, t->vec, dx, dy);
|
|
}
|
|
else {
|
|
convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
|
|
}
|
|
Projf(vec, t->vec, t->viewinv[0]);
|
|
return Inpf(t->viewinv[0], vec) * 2.0f;
|
|
}
|
|
|
|
float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
|
|
float vec[3];
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
short dx = t->shiftmval[0] + (mval[0] - t->shiftmval[0]) / 10 - t->imval[0];
|
|
short dy = t->shiftmval[1] + (mval[1] - t->shiftmval[1]) / 10 - t->imval[1];
|
|
convertViewVec(t, t->vec, dx, dy);
|
|
}
|
|
else {
|
|
convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
|
|
}
|
|
Projf(vec, t->vec, t->viewinv[1]);
|
|
return Inpf(t->viewinv[1], vec) * 2.0f;
|
|
}
|
|
|
|
/* ************************** SPACE DEPENDANT CODE **************************** */
|
|
|
|
void setTransformViewMatrices(TransInfo *t)
|
|
{
|
|
if(t->spacetype==SPACE_VIEW3D) {
|
|
Mat4CpyMat4(t->viewmat, G.vd->viewmat);
|
|
Mat4CpyMat4(t->viewinv, G.vd->viewinv);
|
|
Mat4CpyMat4(t->persmat, G.vd->persmat);
|
|
Mat4CpyMat4(t->persinv, G.vd->persinv);
|
|
t->persp= G.vd->persp;
|
|
}
|
|
else {
|
|
Mat4One(t->viewmat);
|
|
Mat4One(t->viewinv);
|
|
Mat4One(t->persmat);
|
|
Mat4One(t->persinv);
|
|
t->persp = 0; // ortho
|
|
}
|
|
|
|
calculateCenter2D(t);
|
|
|
|
}
|
|
|
|
void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D) {
|
|
window_to_3d(vec, dx, dy);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
float divx, divy, aspx, aspy;
|
|
|
|
transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
|
|
divx= G.v2d->mask.xmax-G.v2d->mask.xmin;
|
|
divy= G.v2d->mask.ymax-G.v2d->mask.ymin;
|
|
|
|
vec[0]= aspx*(G.v2d->cur.xmax-G.v2d->cur.xmin)*(dx)/divx;
|
|
vec[1]= aspy*(G.v2d->cur.ymax-G.v2d->cur.ymin)*(dy)/divy;
|
|
vec[2]= 0.0f;
|
|
}
|
|
}
|
|
|
|
void projectIntView(TransInfo *t, float *vec, int *adr)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D)
|
|
project_int(vec, adr);
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
float aspx, aspy, v[2];
|
|
|
|
transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
v[0]= vec[0]/aspx;
|
|
v[1]= vec[1]/aspy;
|
|
|
|
uvco_to_areaco_noclip(v, adr);
|
|
}
|
|
}
|
|
|
|
void projectFloatView(TransInfo *t, float *vec, float *adr)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D)
|
|
project_float(vec, adr);
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
int a[2];
|
|
|
|
projectIntView(t, vec, a);
|
|
adr[0]= a[0];
|
|
adr[1]= a[1];
|
|
}
|
|
}
|
|
|
|
void convertVecToDisplayNum(float *vec, float *num)
|
|
{
|
|
TransInfo *t= BIF_GetTransInfo();
|
|
|
|
VECCOPY(num, vec);
|
|
|
|
if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
|
|
float aspx, aspy;
|
|
|
|
if((G.sima->flag & SI_COORDFLOATS)==0) {
|
|
int width, height;
|
|
transform_width_height_tface_uv(&width, &height);
|
|
|
|
num[0] *= width;
|
|
num[1] *= height;
|
|
}
|
|
|
|
transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
num[0] /= aspx;
|
|
num[1] /= aspy;
|
|
}
|
|
}
|
|
|
|
void convertDisplayNumToVec(float *num, float *vec)
|
|
{
|
|
TransInfo *t= BIF_GetTransInfo();
|
|
|
|
VECCOPY(vec, num);
|
|
|
|
if ((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
|
|
float aspx, aspy;
|
|
|
|
if((G.sima->flag & SI_COORDFLOATS)==0) {
|
|
int width, height;
|
|
transform_width_height_tface_uv(&width, &height);
|
|
|
|
vec[0] /= width;
|
|
vec[1] /= height;
|
|
}
|
|
|
|
transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
vec[0] *= aspx;
|
|
vec[1] *= aspy;
|
|
}
|
|
}
|
|
|
|
static void viewRedrawForce(TransInfo *t)
|
|
{
|
|
if(t->spacetype==SPACE_VIEW3D)
|
|
force_draw(0);
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
if(G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
|
|
else force_draw(0);
|
|
}
|
|
}
|
|
|
|
static void viewRedrawPost(TransInfo *t)
|
|
{
|
|
if(t->spacetype==SPACE_VIEW3D) {
|
|
allqueue(REDRAWBUTSOBJECT, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
|
|
scrarea_queue_headredraw(curarea);
|
|
}
|
|
|
|
/* ************************** TRANSFORMATIONS **************************** */
|
|
|
|
void BIF_selectOrientation() {
|
|
short val;
|
|
val= pupmenu("Orientation%t|Global|Local|Normal|View");
|
|
if(val>0) {
|
|
if(val==1) G.vd->twmode= V3D_MANIP_GLOBAL;
|
|
else if(val==2) G.vd->twmode= V3D_MANIP_LOCAL;
|
|
else if(val==3) G.vd->twmode= V3D_MANIP_NORMAL;
|
|
else if(val==4) G.vd->twmode= V3D_MANIP_VIEW;
|
|
}
|
|
}
|
|
|
|
static void view_editmove(unsigned short event)
|
|
{
|
|
int refresh = 0;
|
|
/* Regular: Zoom in */
|
|
/* Shift: Scroll up */
|
|
/* Ctrl: Scroll right */
|
|
/* Alt-Shift: Rotate up */
|
|
/* Alt-Ctrl: Rotate right */
|
|
|
|
/* only work in 3D window for now
|
|
* In the end, will have to send to event to a 2D window handler instead
|
|
*/
|
|
if (Trans.flag & T_2D_EDIT)
|
|
return;
|
|
|
|
switch(event) {
|
|
case WHEELUPMOUSE:
|
|
|
|
if( G.qual & LR_SHIFTKEY ) {
|
|
if( G.qual & LR_ALTKEY ) {
|
|
G.qual &= ~LR_SHIFTKEY;
|
|
persptoetsen(PAD2);
|
|
G.qual |= LR_SHIFTKEY;
|
|
} else {
|
|
persptoetsen(PAD2);
|
|
}
|
|
} else if( G.qual & LR_CTRLKEY ) {
|
|
if( G.qual & LR_ALTKEY ) {
|
|
G.qual &= ~LR_CTRLKEY;
|
|
persptoetsen(PAD4);
|
|
G.qual |= LR_CTRLKEY;
|
|
} else {
|
|
persptoetsen(PAD4);
|
|
}
|
|
} else if(U.uiflag & USER_WHEELZOOMDIR)
|
|
persptoetsen(PADMINUS);
|
|
else
|
|
persptoetsen(PADPLUSKEY);
|
|
|
|
refresh = 1;
|
|
break;
|
|
case WHEELDOWNMOUSE:
|
|
if( G.qual & LR_SHIFTKEY ) {
|
|
if( G.qual & LR_ALTKEY ) {
|
|
G.qual &= ~LR_SHIFTKEY;
|
|
persptoetsen(PAD8);
|
|
G.qual |= LR_SHIFTKEY;
|
|
} else {
|
|
persptoetsen(PAD8);
|
|
}
|
|
} else if( G.qual & LR_CTRLKEY ) {
|
|
if( G.qual & LR_ALTKEY ) {
|
|
G.qual &= ~LR_CTRLKEY;
|
|
persptoetsen(PAD6);
|
|
G.qual |= LR_CTRLKEY;
|
|
} else {
|
|
persptoetsen(PAD6);
|
|
}
|
|
} else if(U.uiflag & USER_WHEELZOOMDIR)
|
|
persptoetsen(PADPLUSKEY);
|
|
else
|
|
persptoetsen(PADMINUS);
|
|
|
|
refresh = 1;
|
|
break;
|
|
}
|
|
|
|
if (refresh)
|
|
setTransformViewMatrices(&Trans);
|
|
}
|
|
|
|
void checkFirstTime() {
|
|
if(Trans.mode==TFM_INIT) {
|
|
memset(&Trans, 0, sizeof(TransInfo));
|
|
Trans.propsize = 1.0;
|
|
}
|
|
}
|
|
|
|
static char *transform_to_undostr(TransInfo *t)
|
|
{
|
|
switch (t->mode) {
|
|
case TFM_TRANSLATION:
|
|
return "Translate";
|
|
case TFM_ROTATION:
|
|
return "Rotate";
|
|
case TFM_RESIZE:
|
|
return "Scale";
|
|
case TFM_TOSPHERE:
|
|
return "To Sphere";
|
|
case TFM_SHEAR:
|
|
return "Shear";
|
|
case TFM_WARP:
|
|
return "Warp";
|
|
case TFM_SHRINKFATTEN:
|
|
return "Shrink/Fatten";
|
|
case TFM_TILT:
|
|
return "Tilt";
|
|
case TFM_TRACKBALL:
|
|
return "Trackball";
|
|
case TFM_PUSHPULL:
|
|
return "Push/Pull";
|
|
case TFM_CREASE:
|
|
return "Crease";
|
|
case TFM_BONESIZE:
|
|
return "Bone Width";
|
|
case TFM_BONE_ENVELOPE:
|
|
return "Bone Envelope";
|
|
}
|
|
return "Transform";
|
|
}
|
|
|
|
/* ************************************************* */
|
|
|
|
static void transformEvent(unsigned short event, short val) {
|
|
float mati[3][3] = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
|
|
char cmode = constraintModeToChar(&Trans);
|
|
|
|
if (val) {
|
|
switch (event){
|
|
/* enforce redraw of transform when modifiers are used */
|
|
case LEFTCTRLKEY:
|
|
case RIGHTCTRLKEY:
|
|
Trans.redraw = 1;
|
|
break;
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
/* shift is modifier for higher resolution transform, works nice to store this mouse position */
|
|
getmouseco_areawin(Trans.shiftmval);
|
|
Trans.flag |= T_SHIFT_MOD;
|
|
Trans.redraw = 1;
|
|
break;
|
|
|
|
case SPACEKEY:
|
|
if ((Trans.spacetype==SPACE_VIEW3D) && (G.qual & LR_ALTKEY)) {
|
|
short mval[2];
|
|
|
|
getmouseco_sc(mval);
|
|
BIF_selectOrientation();
|
|
calc_manipulator_stats(curarea);
|
|
Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
|
|
warp_pointer(mval[0], mval[1]);
|
|
}
|
|
else {
|
|
Trans.state = TRANS_CONFIRM;
|
|
}
|
|
break;
|
|
|
|
|
|
case MIDDLEMOUSE:
|
|
if ((Trans.flag & T_NO_CONSTRAINT)==0) {
|
|
/* exception for switching to dolly, or trackball, in camera view */
|
|
if (Trans.flag & T_CAMERA) {
|
|
if (Trans.mode==TFM_TRANSLATION)
|
|
setLocalConstraint(&Trans, (CON_AXIS2), "along local Z");
|
|
else if (Trans.mode==TFM_ROTATION) {
|
|
restoreTransObjects(&Trans);
|
|
initTransModeFlags(&Trans, TFM_TRACKBALL);
|
|
initTrackball(&Trans);
|
|
}
|
|
}
|
|
else {
|
|
Trans.flag |= T_MMB_PRESSED;
|
|
if (Trans.con.mode & CON_APPLY) {
|
|
stopConstraint(&Trans);
|
|
}
|
|
else {
|
|
if (G.qual & LR_CTRLKEY) {
|
|
initSelectConstraint(&Trans, Trans.spacemtx);
|
|
}
|
|
else {
|
|
/* bit hackish... but it prevents mmb select to print the orientation from menu */
|
|
strcpy(Trans.spacename, "global");
|
|
initSelectConstraint(&Trans, mati);
|
|
}
|
|
postSelectConstraint(&Trans);
|
|
}
|
|
}
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case ESCKEY:
|
|
case RIGHTMOUSE:
|
|
Trans.state = TRANS_CANCEL;
|
|
break;
|
|
case LEFTMOUSE:
|
|
case PADENTER:
|
|
case RETKEY:
|
|
Trans.state = TRANS_CONFIRM;
|
|
break;
|
|
case GKEY:
|
|
/* only switch when... */
|
|
if( ELEM3(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
|
|
restoreTransObjects(&Trans);
|
|
initTransModeFlags(&Trans, TFM_TRANSLATION);
|
|
initTranslation(&Trans);
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case SKEY:
|
|
/* only switch when... */
|
|
if( ELEM3(Trans.mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
|
|
restoreTransObjects(&Trans);
|
|
initTransModeFlags(&Trans, TFM_RESIZE);
|
|
initResize(&Trans);
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case RKEY:
|
|
/* only switch when... */
|
|
if( ELEM4(Trans.mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
|
|
|
|
if (Trans.mode == TFM_ROTATION) {
|
|
restoreTransObjects(&Trans);
|
|
initTransModeFlags(&Trans, TFM_TRACKBALL);
|
|
initTrackball(&Trans);
|
|
}
|
|
else {
|
|
restoreTransObjects(&Trans);
|
|
initTransModeFlags(&Trans, TFM_ROTATION);
|
|
initRotation(&Trans);
|
|
}
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case CKEY:
|
|
if (G.qual & LR_ALTKEY) {
|
|
Trans.flag ^= T_PROP_CONNECTED;
|
|
sort_trans_data_dist(&Trans);
|
|
calculatePropRatio(&Trans);
|
|
Trans.redraw= 1;
|
|
}
|
|
else {
|
|
stopConstraint(&Trans);
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case XKEY:
|
|
if ((Trans.flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'X') {
|
|
if (Trans.con.mode & CON_USER) {
|
|
stopConstraint(&Trans);
|
|
}
|
|
else {
|
|
if (G.qual == 0)
|
|
setUserConstraint(&Trans, (CON_AXIS0), "along %s X");
|
|
else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
|
|
setUserConstraint(&Trans, (CON_AXIS1|CON_AXIS2), "locking %s X");
|
|
}
|
|
}
|
|
else {
|
|
if (G.qual == 0)
|
|
setConstraint(&Trans, mati, (CON_AXIS0), "along global X");
|
|
else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
|
|
setConstraint(&Trans, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
|
|
}
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case YKEY:
|
|
if ((Trans.flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'Y') {
|
|
if (Trans.con.mode & CON_USER) {
|
|
stopConstraint(&Trans);
|
|
}
|
|
else {
|
|
if (G.qual == 0)
|
|
setUserConstraint(&Trans, (CON_AXIS1), "along %s Y");
|
|
else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
|
|
setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS2), "locking %s Y");
|
|
}
|
|
}
|
|
else {
|
|
if (G.qual == 0)
|
|
setConstraint(&Trans, mati, (CON_AXIS1), "along global Y");
|
|
else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
|
|
setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
|
|
}
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case ZKEY:
|
|
if ((Trans.flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'Z') {
|
|
if (Trans.con.mode & CON_USER) {
|
|
stopConstraint(&Trans);
|
|
}
|
|
else {
|
|
if (G.qual == 0)
|
|
setUserConstraint(&Trans, (CON_AXIS2), "along %s Z");
|
|
else if ((G.qual == LR_SHIFTKEY) && ((Trans.flag & T_2D_EDIT)==0))
|
|
setUserConstraint(&Trans, (CON_AXIS0|CON_AXIS1), "locking %s Z");
|
|
}
|
|
}
|
|
else if ((Trans.flag & T_2D_EDIT)==0) {
|
|
if (G.qual == 0)
|
|
setConstraint(&Trans, mati, (CON_AXIS2), "along global Z");
|
|
else if (G.qual == LR_SHIFTKEY)
|
|
setConstraint(&Trans, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
|
|
}
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case OKEY:
|
|
if (Trans.flag & T_PROP_EDIT && G.qual==LR_SHIFTKEY) {
|
|
G.scene->prop_mode = (G.scene->prop_mode+1)%6;
|
|
calculatePropRatio(&Trans);
|
|
Trans.redraw= 1;
|
|
}
|
|
break;
|
|
case PADPLUSKEY:
|
|
if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 1.1f;
|
|
calculatePropRatio(&Trans);
|
|
}
|
|
Trans.redraw= 1;
|
|
break;
|
|
case PAGEUPKEY:
|
|
case WHEELDOWNMOUSE:
|
|
if(Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 1.1f;
|
|
calculatePropRatio(&Trans);
|
|
}
|
|
else view_editmove(event);
|
|
Trans.redraw= 1;
|
|
break;
|
|
case PADMINUS:
|
|
if(G.qual & LR_ALTKEY && Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 0.90909090f;
|
|
calculatePropRatio(&Trans);
|
|
}
|
|
Trans.redraw= 1;
|
|
break;
|
|
case PAGEDOWNKEY:
|
|
case WHEELUPMOUSE:
|
|
if(Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 0.90909090f;
|
|
calculatePropRatio(&Trans);
|
|
}
|
|
else view_editmove(event);
|
|
Trans.redraw= 1;
|
|
break;
|
|
}
|
|
Trans.redraw |= handleNumInput(&(Trans.num), event);
|
|
arrows_move_cursor(event);
|
|
}
|
|
else {
|
|
switch (event){
|
|
/* no redraw on release modifier keys! this makes sure you can assign the 'grid' still
|
|
after releasing modifer key */
|
|
case MIDDLEMOUSE:
|
|
if ((Trans.flag & T_NO_CONSTRAINT)==0) {
|
|
Trans.flag &= ~T_MMB_PRESSED;
|
|
postSelectConstraint(&Trans);
|
|
Trans.redraw = 1;
|
|
}
|
|
break;
|
|
case LEFTMOUSE:
|
|
case RIGHTMOUSE:
|
|
if (Trans.context & CTX_TWEAK)
|
|
Trans.state = TRANS_CONFIRM;
|
|
break;
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
/* shift is modifier for higher resolution transform */
|
|
Trans.flag &= ~T_SHIFT_MOD;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void initTransform(int mode, int context) {
|
|
/* added initialize, for external calls to set stuff in TransInfo, like undo string */
|
|
checkFirstTime();
|
|
|
|
Trans.state = TRANS_RUNNING;
|
|
|
|
Trans.context = context;
|
|
|
|
initTrans(&Trans); // internal data, mouse, vectors
|
|
|
|
if(Trans.spacetype==SPACE_VIEW3D) {
|
|
calc_manipulator_stats(curarea);
|
|
Mat3CpyMat4(Trans.spacemtx, G.vd->twmat);
|
|
}
|
|
else
|
|
Mat3One(Trans.spacemtx);
|
|
|
|
initTransModeFlags(&Trans, mode); // modal settings in struct Trans
|
|
|
|
createTransData(&Trans); // make TransData structs from selection
|
|
|
|
if (Trans.total == 0) {
|
|
postTrans(&Trans);
|
|
return;
|
|
}
|
|
|
|
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
|
|
/* EVIL2: we gave as argument also texture space context bit... was cleared */
|
|
mode= Trans.mode;
|
|
|
|
calculatePropRatio(&Trans);
|
|
calculateCenter(&Trans);
|
|
|
|
switch (mode) {
|
|
case TFM_TRANSLATION:
|
|
initTranslation(&Trans);
|
|
break;
|
|
case TFM_ROTATION:
|
|
initRotation(&Trans);
|
|
break;
|
|
case TFM_RESIZE:
|
|
initResize(&Trans);
|
|
break;
|
|
case TFM_TOSPHERE:
|
|
initToSphere(&Trans);
|
|
break;
|
|
case TFM_SHEAR:
|
|
initShear(&Trans);
|
|
break;
|
|
case TFM_WARP:
|
|
initWarp(&Trans);
|
|
break;
|
|
case TFM_SHRINKFATTEN:
|
|
initShrinkFatten(&Trans);
|
|
break;
|
|
case TFM_TILT:
|
|
initTilt(&Trans);
|
|
break;
|
|
case TFM_CURVE_SHRINKFATTEN:
|
|
initCurveShrinkFatten(&Trans);
|
|
break;
|
|
case TFM_TRACKBALL:
|
|
initTrackball(&Trans);
|
|
break;
|
|
case TFM_PUSHPULL:
|
|
initPushPull(&Trans);
|
|
break;
|
|
case TFM_CREASE:
|
|
initCrease(&Trans);
|
|
break;
|
|
case TFM_BONESIZE:
|
|
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
|
|
bArmature *arm= Trans.poseobj->data;
|
|
if(arm->drawtype==ARM_ENVELOPE)
|
|
initBoneEnvelope(&Trans);
|
|
else
|
|
initBoneSize(&Trans);
|
|
}
|
|
break;
|
|
case TFM_BONE_ENVELOPE:
|
|
initBoneEnvelope(&Trans);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Transform()
|
|
{
|
|
short pmval[2] = {0, 0}, mval[2], val;
|
|
unsigned short event;
|
|
|
|
if(Trans.total==0) return; // added, can happen now! (ton)
|
|
|
|
// Emptying event queue
|
|
while( qtest() ) {
|
|
event= extern_qread(&val);
|
|
}
|
|
|
|
Trans.redraw = 1; /* initial draw */
|
|
|
|
while (Trans.state == TRANS_RUNNING) {
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
|
|
if (Trans.flag & T_MMB_PRESSED)
|
|
Trans.con.mode |= CON_SELECT;
|
|
Trans.redraw = 1;
|
|
}
|
|
if (Trans.redraw) {
|
|
pmval[0] = mval[0];
|
|
pmval[1] = mval[1];
|
|
|
|
selectConstraint(&Trans);
|
|
if (Trans.transform) {
|
|
Trans.transform(&Trans, mval); // calls recalcData()
|
|
}
|
|
Trans.redraw = 0;
|
|
}
|
|
|
|
/* essential for idling subloop */
|
|
if( qtest()==0) PIL_sleep_ms(2);
|
|
|
|
while( qtest() ) {
|
|
event= extern_qread(&val);
|
|
transformEvent(event, val);
|
|
}
|
|
}
|
|
|
|
|
|
/* handle restoring objects */
|
|
if(Trans.state == TRANS_CANCEL)
|
|
restoreTransObjects(&Trans); // calls recalcData()
|
|
|
|
/* free data */
|
|
postTrans(&Trans);
|
|
|
|
/* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
|
|
special_aftertrans_update(&Trans);
|
|
|
|
/* send events out for redraws */
|
|
viewRedrawPost(&Trans);
|
|
|
|
/* Undo as last, certainly after special_trans_update! */
|
|
if(Trans.state == TRANS_CANCEL) {
|
|
if(Trans.undostr) BIF_undo_push(Trans.undostr);
|
|
}
|
|
else {
|
|
if(Trans.undostr) BIF_undo_push(Trans.undostr);
|
|
else BIF_undo_push(transform_to_undostr(&Trans));
|
|
}
|
|
Trans.undostr= NULL;
|
|
|
|
}
|
|
|
|
/* ************************** Manipulator init and main **************************** */
|
|
|
|
void initManipulator(int mode)
|
|
{
|
|
Trans.state = TRANS_RUNNING;
|
|
|
|
Trans.context = CTX_NONE;
|
|
|
|
/* automatic switch to scaling bone envelopes */
|
|
if(mode==TFM_RESIZE && G.obedit && G.obedit->type==OB_ARMATURE) {
|
|
bArmature *arm= G.obedit->data;
|
|
if(arm->drawtype==ARM_ENVELOPE)
|
|
mode= TFM_BONE_ENVELOPE;
|
|
}
|
|
|
|
initTrans(&Trans); // internal data, mouse, vectors
|
|
|
|
initTransModeFlags(&Trans, mode); // modal settings in struct Trans
|
|
|
|
G.moving |= G_TRANSFORM_MANIP; // signal to draw manipuls while transform
|
|
createTransData(&Trans); // make TransData structs from selection
|
|
|
|
if (Trans.total == 0)
|
|
return;
|
|
|
|
/* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
|
|
/* EVIL2: we gave as argument also texture space context bit... was cleared */
|
|
mode= Trans.mode;
|
|
|
|
calculatePropRatio(&Trans);
|
|
calculateCenter(&Trans);
|
|
|
|
switch (mode) {
|
|
case TFM_TRANSLATION:
|
|
initTranslation(&Trans);
|
|
break;
|
|
case TFM_ROTATION:
|
|
initRotation(&Trans);
|
|
break;
|
|
case TFM_RESIZE:
|
|
initResize(&Trans);
|
|
break;
|
|
case TFM_TRACKBALL:
|
|
initTrackball(&Trans);
|
|
break;
|
|
}
|
|
|
|
Trans.flag |= T_USES_MANIPULATOR;
|
|
}
|
|
|
|
void ManipulatorTransform()
|
|
{
|
|
int mouse_moved = 0;
|
|
short pmval[2] = {0, 0}, mval[2], val;
|
|
unsigned short event;
|
|
|
|
if (Trans.total == 0)
|
|
return;
|
|
|
|
Trans.redraw = 1; /* initial draw */
|
|
|
|
while (Trans.state == TRANS_RUNNING) {
|
|
|
|
getmouseco_areawin(mval);
|
|
|
|
if (mval[0] != pmval[0] || mval[1] != pmval[1]) {
|
|
Trans.redraw = 1;
|
|
}
|
|
if (Trans.redraw) {
|
|
pmval[0] = mval[0];
|
|
pmval[1] = mval[1];
|
|
|
|
//selectConstraint(&Trans); needed?
|
|
if (Trans.transform) {
|
|
Trans.transform(&Trans, mval);
|
|
}
|
|
Trans.redraw = 0;
|
|
}
|
|
|
|
/* essential for idling subloop */
|
|
if( qtest()==0) PIL_sleep_ms(2);
|
|
|
|
while( qtest() ) {
|
|
event= extern_qread(&val);
|
|
|
|
switch (event){
|
|
case MOUSEX:
|
|
case MOUSEY:
|
|
mouse_moved = 1;
|
|
break;
|
|
/* enforce redraw of transform when modifiers are used */
|
|
case LEFTCTRLKEY:
|
|
case RIGHTCTRLKEY:
|
|
if(val) Trans.redraw = 1;
|
|
break;
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
/* shift is modifier for higher resolution transform, works nice to store this mouse position */
|
|
if(val) {
|
|
getmouseco_areawin(Trans.shiftmval);
|
|
Trans.flag |= T_SHIFT_MOD;
|
|
Trans.redraw = 1;
|
|
}
|
|
else Trans.flag &= ~T_SHIFT_MOD;
|
|
break;
|
|
|
|
case ESCKEY:
|
|
case RIGHTMOUSE:
|
|
Trans.state = TRANS_CANCEL;
|
|
break;
|
|
case LEFTMOUSE:
|
|
if(mouse_moved==0 && val==0) break;
|
|
// else we pass on event to next, which cancels
|
|
case SPACEKEY:
|
|
case PADENTER:
|
|
case RETKEY:
|
|
Trans.state = TRANS_CONFIRM;
|
|
break;
|
|
}
|
|
if(val) {
|
|
switch(event) {
|
|
case WHEELDOWNMOUSE:
|
|
case PADPLUSKEY:
|
|
if(Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 1.1f;
|
|
calculatePropRatio(&Trans);
|
|
Trans.redraw= 1;
|
|
}
|
|
break;
|
|
case WHEELUPMOUSE:
|
|
case PADMINUS:
|
|
if(Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 0.90909090f;
|
|
calculatePropRatio(&Trans);
|
|
Trans.redraw= 1;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Trans.state == TRANS_CANCEL) {
|
|
restoreTransObjects(&Trans);
|
|
}
|
|
else {
|
|
BIF_undo_push(transform_to_undostr(&Trans));
|
|
}
|
|
|
|
/* free data, reset vars */
|
|
postTrans(&Trans);
|
|
|
|
/* aftertrans does insert ipos and action channels, and clears base flags */
|
|
special_aftertrans_update(&Trans);
|
|
|
|
/* send events out for redraws */
|
|
viewRedrawPost(&Trans);
|
|
}
|
|
|
|
/* ************************** TRANSFORMATIONS **************************** */
|
|
|
|
static void protectedTransBits(short protectflag, float *vec)
|
|
{
|
|
if(protectflag & OB_LOCK_LOCX)
|
|
vec[0]= 0.0f;
|
|
if(protectflag & OB_LOCK_LOCY)
|
|
vec[1]= 0.0f;
|
|
if(protectflag & OB_LOCK_LOCZ)
|
|
vec[2]= 0.0f;
|
|
}
|
|
|
|
static void protectedSizeBits(short protectflag, float *size)
|
|
{
|
|
if(protectflag & OB_LOCK_SCALEX)
|
|
size[0]= 1.0f;
|
|
if(protectflag & OB_LOCK_SCALEY)
|
|
size[1]= 1.0f;
|
|
if(protectflag & OB_LOCK_SCALEZ)
|
|
size[2]= 1.0f;
|
|
}
|
|
|
|
static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
|
|
{
|
|
if(protectflag & OB_LOCK_ROTX)
|
|
eul[0]= oldeul[0];
|
|
if(protectflag & OB_LOCK_ROTY)
|
|
eul[1]= oldeul[1];
|
|
if(protectflag & OB_LOCK_ROTZ)
|
|
eul[2]= oldeul[2];
|
|
}
|
|
|
|
static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
|
|
{
|
|
/* quaternions get limited with euler... */
|
|
/* this function only does the delta rotation */
|
|
|
|
if(protectflag) {
|
|
float eul[3], oldeul[3], quat1[4];
|
|
|
|
QUATCOPY(quat1, quat);
|
|
QuatToEul(quat, eul);
|
|
QuatToEul(oldquat, oldeul);
|
|
|
|
if(protectflag & OB_LOCK_ROTX)
|
|
eul[0]= oldeul[0];
|
|
if(protectflag & OB_LOCK_ROTY)
|
|
eul[1]= oldeul[1];
|
|
if(protectflag & OB_LOCK_ROTZ)
|
|
eul[2]= oldeul[2];
|
|
|
|
EulToQuat(eul, quat);
|
|
/* quaternions flip w sign to accumulate rotations correctly */
|
|
if( (quat1[0]<0.0f && quat[0]>0.0f) || (quat1[0]>0.0f && quat[0]<0.0f) ) {
|
|
QuatMulf(quat, -1.0f);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ************************** WARP *************************** */
|
|
|
|
/* warp is done fully in view space */
|
|
void initWarp(TransInfo *t)
|
|
{
|
|
float max[3], min[3];
|
|
int i;
|
|
|
|
calculateCenterCursor(t);
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->transform = Warp;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 5.0f;
|
|
t->snap[2] = 1.0f;
|
|
|
|
t->fac = (float)(t->center2d[0] - t->imval[0]);
|
|
|
|
/* we need min/max in view space */
|
|
for(i = 0; i < t->total; i++) {
|
|
float center[3];
|
|
VECCOPY(center, t->data[i].center);
|
|
Mat3MulVecfl(t->data[i].mtx, center);
|
|
Mat4MulVecfl(t->viewmat, center);
|
|
VecSubf(center, center, t->viewmat[3]);
|
|
if (i)
|
|
MinMax3(min, max, center);
|
|
else {
|
|
VECCOPY(max, center);
|
|
VECCOPY(min, center);
|
|
}
|
|
}
|
|
|
|
t->center[0]= (min[0]+max[0])/2.0f;
|
|
t->center[1]= (min[1]+max[1])/2.0f;
|
|
t->center[2]= (min[2]+max[2])/2.0f;
|
|
|
|
t->val= (max[0]-min[0])/2.0f; // t->val is free variable
|
|
}
|
|
|
|
|
|
int Warp(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float vec[3], circumfac, dist, phi0, co, si, *curs, cursor[3], gcursor[3];
|
|
int i;
|
|
char str[50];
|
|
|
|
curs= give_cursor();
|
|
/*
|
|
* gcursor is the one used for helpline.
|
|
* It has to be in the same space as the drawing loop
|
|
* (that means it needs to be in the object's space when in edit mode and
|
|
* in global space in object mode)
|
|
*
|
|
* cursor is used for calculations.
|
|
* It needs to be in view space, but we need to take object's offset
|
|
* into account if in Edit mode.
|
|
*/
|
|
VECCOPY(cursor, curs);
|
|
VECCOPY(gcursor, cursor);
|
|
if (t->flag & T_EDIT) {
|
|
VecSubf(cursor, cursor, G.obedit->obmat[3]);
|
|
VecSubf(gcursor, gcursor, G.obedit->obmat[3]);
|
|
Mat3MulVecfl(t->data->smtx, gcursor);
|
|
}
|
|
Mat4MulVecfl(t->viewmat, cursor);
|
|
VecSubf(cursor, cursor, t->viewmat[3]);
|
|
|
|
// amount of degrees for warp, 450 = allow to create 360 degree warp
|
|
circumfac= 450.0f*(mval[1] - t->imval[1]) / (float)(curarea->winy);
|
|
circumfac+= 90.0f;
|
|
|
|
snapGrid(t, &circumfac);
|
|
applyNumInput(&t->num, &circumfac);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Warp: %s", c);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "Warp: %.3f", circumfac);
|
|
}
|
|
|
|
circumfac*= (float)(-M_PI/360.0);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
float loc[3];
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
/* translate point to centre, rotate in such a way that outline==distance */
|
|
|
|
VECCOPY(vec, td->iloc);
|
|
Mat3MulVecfl(td->mtx, vec);
|
|
Mat4MulVecfl(t->viewmat, vec);
|
|
VecSubf(vec, vec, t->viewmat[3]);
|
|
|
|
dist= vec[0]-cursor[0];
|
|
|
|
phi0= (circumfac*dist/t->val); // t->val is X dimension projected boundbox
|
|
|
|
vec[1]= (vec[1]-cursor[1]);
|
|
|
|
co= (float)cos(phi0);
|
|
si= (float)sin(phi0);
|
|
loc[0]= -si*vec[1]+cursor[0];
|
|
loc[1]= co*vec[1]+cursor[1];
|
|
loc[2]= vec[2];
|
|
|
|
Mat4MulVecfl(t->viewinv, loc);
|
|
VecSubf(loc, loc, t->viewinv[3]);
|
|
Mat3MulVecfl(td->smtx, loc);
|
|
|
|
VecSubf(loc, loc, td->iloc);
|
|
VecMulf(loc, td->factor);
|
|
VecAddf(td->loc, td->iloc, loc);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline(t, gcursor);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** SHEAR *************************** */
|
|
|
|
void initShear(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = Shear;
|
|
}
|
|
|
|
int Shear(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float vec[3];
|
|
float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
|
|
float value;
|
|
int i;
|
|
char str[50];
|
|
|
|
Mat3CpyMat4(persmat, t->viewmat);
|
|
Mat3Inv(persinv, persmat);
|
|
|
|
value = 0.05f * InputHorizontalAbsolute(t, mval);
|
|
|
|
snapGrid(t, &value);
|
|
|
|
applyNumInput(&t->num, &value);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Shear: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "Shear: %.3f %s", value, t->proptext);
|
|
}
|
|
|
|
Mat3One(smat);
|
|
smat[1][0] = value;
|
|
Mat3MulMat3(tmat, smat, persmat);
|
|
Mat3MulMat3(totmat, persinv, tmat);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (G.obedit) {
|
|
float mat3[3][3];
|
|
Mat3MulMat3(mat3, totmat, td->mtx);
|
|
Mat3MulMat3(tmat, td->smtx, mat3);
|
|
}
|
|
else {
|
|
Mat3CpyMat3(tmat, totmat);
|
|
}
|
|
VecSubf(vec, td->center, t->center);
|
|
|
|
Mat3MulVecfl(tmat, vec);
|
|
|
|
VecAddf(vec, vec, t->center);
|
|
VecSubf(vec, vec, td->center);
|
|
|
|
VecMulf(vec, td->factor);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** RESIZE *************************** */
|
|
|
|
void initResize(TransInfo *t)
|
|
{
|
|
t->fac = (float)sqrt(
|
|
(
|
|
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
|
|
+
|
|
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
|
|
) );
|
|
|
|
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
|
|
|
|
t->idx_max = 2;
|
|
t->num.idx_max = 2;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = Resize;
|
|
}
|
|
|
|
static void headerResize(TransInfo *t, float vec[3], char *str) {
|
|
char tvec[60];
|
|
if (hasNumInput(&t->num)) {
|
|
outputNumInput(&(t->num), tvec);
|
|
}
|
|
else {
|
|
sprintf(&tvec[0], "%.4f", vec[0]);
|
|
sprintf(&tvec[20], "%.4f", vec[1]);
|
|
sprintf(&tvec[40], "%.4f", vec[2]);
|
|
}
|
|
|
|
if (t->con.mode & CON_APPLY) {
|
|
switch(t->num.idx_max) {
|
|
case 0:
|
|
sprintf(str, "Scale: %s%s %s", &tvec[0], t->con.text, t->proptext);
|
|
break;
|
|
case 1:
|
|
sprintf(str, "Scale: %s : %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
|
|
break;
|
|
case 2:
|
|
sprintf(str, "Scale: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
|
|
}
|
|
}
|
|
else {
|
|
if (t->flag & T_2D_EDIT)
|
|
sprintf(str, "Scale X: %s Y: %s%s %s", &tvec[0], &tvec[20], t->con.text, t->proptext);
|
|
else
|
|
sprintf(str, "Scale X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
|
|
}
|
|
}
|
|
|
|
#define SIGN(a) (a<-FLT_EPSILON?1:a>FLT_EPSILON?2:3)
|
|
#define VECSIGNFLIP(a, b) ((SIGN(a[0]) & SIGN(b[0]))==0 || (SIGN(a[1]) & SIGN(b[1]))==0 || (SIGN(a[2]) & SIGN(b[2]))==0)
|
|
|
|
/* smat is reference matrix, only scaled */
|
|
static void TransMat3ToSize( float mat[][3], float smat[][3], float *size)
|
|
{
|
|
float vec[3];
|
|
|
|
VecCopyf(vec, mat[0]);
|
|
size[0]= Normalise(vec);
|
|
VecCopyf(vec, mat[1]);
|
|
size[1]= Normalise(vec);
|
|
VecCopyf(vec, mat[2]);
|
|
size[2]= Normalise(vec);
|
|
|
|
/* first tried with dotproduct... but the sign flip is crucial */
|
|
if( VECSIGNFLIP(mat[0], smat[0]) ) size[0]= -size[0];
|
|
if( VECSIGNFLIP(mat[1], smat[1]) ) size[1]= -size[1];
|
|
if( VECSIGNFLIP(mat[2], smat[2]) ) size[2]= -size[2];
|
|
}
|
|
|
|
|
|
static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) {
|
|
float tmat[3][3], smat[3][3], center[3];
|
|
float vec[3];
|
|
|
|
if (t->flag & T_EDIT) {
|
|
Mat3MulMat3(smat, mat, td->mtx);
|
|
Mat3MulMat3(tmat, td->smtx, smat);
|
|
}
|
|
else {
|
|
Mat3CpyMat3(tmat, mat);
|
|
}
|
|
|
|
if (t->con.applySize) {
|
|
t->con.applySize(t, td, tmat);
|
|
}
|
|
|
|
/* local constraint shouldn't alter center */
|
|
if (t->around == V3D_LOCAL) {
|
|
if (t->flag & T_OBJECT) {
|
|
VECCOPY(center, td->center);
|
|
}
|
|
else if (t->flag & T_EDIT) {
|
|
|
|
if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
|
|
VECCOPY(center, td->center);
|
|
}
|
|
else {
|
|
VECCOPY(center, t->center);
|
|
}
|
|
}
|
|
else {
|
|
VECCOPY(center, t->center);
|
|
}
|
|
}
|
|
else {
|
|
VECCOPY(center, t->center);
|
|
}
|
|
|
|
if (td->ext) {
|
|
float fsize[3];
|
|
|
|
if (t->flag & (T_OBJECT|T_TEXTURE)) {
|
|
float obsizemat[3][3];
|
|
// Reorient the size mat to fit the oriented object.
|
|
Mat3MulMat3(obsizemat, tmat, td->axismtx);
|
|
//printmatrix3("obsizemat", obsizemat);
|
|
TransMat3ToSize(obsizemat, td->axismtx, fsize);
|
|
//printvecf("fsize", fsize);
|
|
}
|
|
else {
|
|
Mat3ToSize(tmat, fsize);
|
|
}
|
|
|
|
protectedSizeBits(td->protectflag, fsize);
|
|
|
|
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
|
|
/* handle ipokeys? */
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
/* calculate delta size (equal for size and dsize) */
|
|
|
|
vec[0]= (tdi->oldsize[0])*(fsize[0] -1.0f) * td->factor;
|
|
vec[1]= (tdi->oldsize[1])*(fsize[1] -1.0f) * td->factor;
|
|
vec[2]= (tdi->oldsize[2])*(fsize[2] -1.0f) * td->factor;
|
|
|
|
add_tdi_poin(tdi->sizex, tdi->oldsize, vec[0]);
|
|
add_tdi_poin(tdi->sizey, tdi->oldsize+1, vec[1]);
|
|
add_tdi_poin(tdi->sizez, tdi->oldsize+2, vec[2]);
|
|
|
|
}
|
|
else if((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)){
|
|
/* scale val and reset size */
|
|
*td->val = td->ival * fsize[0] * td->factor;
|
|
|
|
td->ext->size[0] = td->ext->isize[0];
|
|
td->ext->size[1] = td->ext->isize[1];
|
|
td->ext->size[2] = td->ext->isize[2];
|
|
}
|
|
else {
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
if (td->flag & TD_SINGLESIZE)
|
|
*td->val = td->ival;
|
|
|
|
td->ext->size[0] = td->ext->isize[0] * (fsize[0]) * td->factor;
|
|
td->ext->size[1] = td->ext->isize[1] * (fsize[1]) * td->factor;
|
|
td->ext->size[2] = td->ext->isize[2] * (fsize[2]) * td->factor;
|
|
}
|
|
}
|
|
}
|
|
/* For individual element center, Editmode need to use iloc */
|
|
if (t->flag & T_POINTS)
|
|
VecSubf(vec, td->iloc, center);
|
|
else
|
|
VecSubf(vec, td->center, center);
|
|
|
|
Mat3MulVecfl(tmat, vec);
|
|
|
|
VecAddf(vec, vec, center);
|
|
if (t->flag & T_POINTS)
|
|
VecSubf(vec, vec, td->iloc);
|
|
else
|
|
VecSubf(vec, vec, td->center);
|
|
|
|
VecMulf(vec, td->factor);
|
|
|
|
if (t->flag & T_OBJECT) {
|
|
Mat3MulVecfl(td->smtx, vec);
|
|
}
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
|
|
add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
|
|
add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
|
|
}
|
|
else VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
int Resize(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td;
|
|
float size[3], mat[3][3];
|
|
float ratio;
|
|
int i;
|
|
char str[200];
|
|
|
|
/* for manipulator, center handle, the scaling can't be done relative to center */
|
|
if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
|
|
ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
|
|
}
|
|
else {
|
|
ratio = InputScaleRatio(t, mval);
|
|
|
|
/* flip scale, but not for manipulator center handle */
|
|
if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
|
|
(t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
|
|
ratio *= -1.0f;
|
|
}
|
|
|
|
size[0] = size[1] = size[2] = ratio;
|
|
|
|
snapGrid(t, size);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
applyNumInput(&t->num, size);
|
|
constraintNumInput(t, size);
|
|
}
|
|
|
|
SizeToMat3(size, mat);
|
|
|
|
if (t->con.applySize) {
|
|
t->con.applySize(t, NULL, mat);
|
|
}
|
|
|
|
Mat3CpyMat3(t->mat, mat); // used in manipulator
|
|
|
|
headerResize(t, size, str);
|
|
|
|
for(i = 0, td=t->data; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
ElementResize(t, td, mat);
|
|
}
|
|
|
|
/* evil hack - redo resize if cliiping needeed */
|
|
if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
|
|
SizeToMat3(size, mat);
|
|
|
|
if (t->con.applySize)
|
|
t->con.applySize(t, NULL, mat);
|
|
|
|
for(i = 0, td=t->data; i < t->total; i++, td++)
|
|
ElementResize(t, td, mat);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** TOSPHERE *************************** */
|
|
|
|
void initToSphere(TransInfo *t)
|
|
{
|
|
TransData *td = t->data;
|
|
int i;
|
|
|
|
// Calculate average radius
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
t->val += VecLenf(t->center, td->iloc);
|
|
}
|
|
|
|
t->val /= (float)t->total;
|
|
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = ToSphere;
|
|
}
|
|
|
|
|
|
|
|
int ToSphere(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3];
|
|
float ratio, radius;
|
|
int i;
|
|
char str[50];
|
|
TransData *td = t->data;
|
|
|
|
ratio = InputHorizontalRatio(t, mval);
|
|
|
|
snapGrid(t, &ratio);
|
|
|
|
applyNumInput(&t->num, &ratio);
|
|
|
|
if (ratio < 0)
|
|
ratio = 0.0f;
|
|
else if (ratio > 1)
|
|
ratio = 1.0f;
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "To Sphere: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "To Sphere: %.4f %s", ratio, t->proptext);
|
|
}
|
|
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
float tratio;
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
VecSubf(vec, td->iloc, t->center);
|
|
|
|
radius = Normalise(vec);
|
|
|
|
tratio = ratio * td->factor;
|
|
|
|
VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
|
|
|
|
VecAddf(td->loc, t->center, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** ROTATION *************************** */
|
|
|
|
|
|
void initRotation(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = (float)((5.0/180)*M_PI);
|
|
t->snap[2] = t->snap[1] * 0.2f;
|
|
t->fac = 0;
|
|
t->transform = Rotation;
|
|
}
|
|
|
|
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3]) {
|
|
float vec[3], totmat[3][3], smat[3][3];
|
|
float eul[3], fmat[3][3], quat[4];
|
|
|
|
if (t->flag & T_POINTS) {
|
|
Mat3MulMat3(totmat, mat, td->mtx);
|
|
Mat3MulMat3(smat, td->smtx, totmat);
|
|
|
|
VecSubf(vec, td->iloc, t->center);
|
|
Mat3MulVecfl(smat, vec);
|
|
|
|
VecAddf(td->loc, vec, t->center);
|
|
|
|
if(td->flag & TD_USEQUAT) {
|
|
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
|
|
Mat3ToQuat(fmat, quat); // Actual transform
|
|
QuatMul(td->ext->quat, quat, td->ext->iquat);
|
|
}
|
|
}
|
|
else {
|
|
/* translation */
|
|
|
|
VecSubf(vec, td->center, t->center);
|
|
Mat3MulVecfl(mat, vec);
|
|
VecAddf(vec, vec, t->center);
|
|
/* vec now is the location where the object has to be */
|
|
VecSubf(vec, vec, td->center);
|
|
Mat3MulVecfl(td->smtx, vec);
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
add_tdi_poin(tdi->locx, tdi->oldloc, vec[0]);
|
|
add_tdi_poin(tdi->locy, tdi->oldloc+1, vec[1]);
|
|
add_tdi_poin(tdi->locz, tdi->oldloc+2, vec[2]);
|
|
}
|
|
else VecAddf(td->loc, td->iloc, vec);
|
|
|
|
/* rotation */
|
|
|
|
if(td->flag & TD_USEQUAT) {
|
|
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
|
|
Mat3ToQuat(fmat, quat); // Actual transform
|
|
|
|
QuatMul(td->ext->quat, quat, td->ext->iquat);
|
|
/* this function works on end result */
|
|
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
|
}
|
|
else if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
|
|
float obmat[3][3];
|
|
|
|
/* are there ipo keys? */
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float rot[3];
|
|
|
|
/* calculate the total rotatation in eulers */
|
|
VecAddf(eul, td->ext->irot, td->ext->drot);
|
|
EulToMat3(eul, obmat);
|
|
/* mat = transform, obmat = object rotation */
|
|
Mat3MulMat3(fmat, mat, obmat);
|
|
|
|
Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
|
|
|
|
/* correct back for delta rot */
|
|
if(tdi->flag & TOB_IPODROT) {
|
|
VecSubf(rot, eul, td->ext->irot);
|
|
}
|
|
else {
|
|
VecSubf(rot, eul, td->ext->drot);
|
|
}
|
|
|
|
VecMulf(rot, (float)(9.0/M_PI_2));
|
|
VecSubf(rot, rot, tdi->oldrot);
|
|
|
|
protectedRotateBits(td->protectflag, rot, tdi->oldrot);
|
|
|
|
add_tdi_poin(tdi->rotx, tdi->oldrot, rot[0]);
|
|
add_tdi_poin(tdi->roty, tdi->oldrot+1, rot[1]);
|
|
add_tdi_poin(tdi->rotz, tdi->oldrot+2, rot[2]);
|
|
}
|
|
else {
|
|
Mat3MulMat3(totmat, mat, td->mtx);
|
|
Mat3MulMat3(smat, td->smtx, totmat);
|
|
|
|
/* calculate the total rotatation in eulers */
|
|
VecAddf(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
|
|
EulToMat3(eul, obmat);
|
|
/* mat = transform, obmat = object rotation */
|
|
Mat3MulMat3(fmat, smat, obmat);
|
|
|
|
Mat3ToCompatibleEul(fmat, eul, td->ext->irot);
|
|
|
|
/* correct back for delta rot */
|
|
VecSubf(eul, eul, td->ext->drot);
|
|
|
|
/* and apply */
|
|
protectedRotateBits(td->protectflag, eul, td->ext->irot);
|
|
VECCOPY(td->ext->rot, eul);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void applyRotation(TransInfo *t, float angle, float axis[3])
|
|
{
|
|
TransData *td = t->data;
|
|
float mat[3][3], center[3];
|
|
int i;
|
|
|
|
/* saving original center */
|
|
if (t->around == V3D_LOCAL) {
|
|
VECCOPY(center, t->center);
|
|
}
|
|
|
|
VecRotToMat3(axis, angle, mat);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
/* local constraint shouldn't alter center */
|
|
if (t->around == V3D_LOCAL) {
|
|
if (t->flag & (T_OBJECT|T_POSE)) {
|
|
VECCOPY(t->center, td->center);
|
|
}
|
|
else {
|
|
if(G.vd->around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
|
|
VECCOPY(t->center, td->center);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (t->con.applyRot) {
|
|
t->con.applyRot(t, td, axis);
|
|
VecRotToMat3(axis, angle * td->factor, mat);
|
|
}
|
|
else if (t->flag & T_PROP_EDIT) {
|
|
VecRotToMat3(axis, angle * td->factor, mat);
|
|
}
|
|
|
|
ElementRotation(t, td, mat);
|
|
}
|
|
|
|
/* restoring original center */
|
|
if (t->around == V3D_LOCAL) {
|
|
VECCOPY(t->center, center);
|
|
}
|
|
}
|
|
|
|
int Rotation(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
char str[50];
|
|
|
|
float final;
|
|
|
|
int dx2 = t->center2d[0] - mval[0];
|
|
int dy2 = t->center2d[1] - mval[1];
|
|
double B = sqrt(dx2*dx2+dy2*dy2);
|
|
|
|
int dx1 = t->center2d[0] - t->imval[0];
|
|
int dy1 = t->center2d[1] - t->imval[1];
|
|
double A = sqrt(dx1*dx1+dy1*dy1);
|
|
|
|
int dx3 = mval[0] - t->imval[0];
|
|
int dy3 = mval[1] - t->imval[1];
|
|
/* use doubles here, to make sure a "1.0" (no rotation) doesnt become 9.999999e-01, which gives 0.02 for acos */
|
|
double deler= ((double)((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3) ))
|
|
/ (2.0 * (A*B?A*B:1.0));
|
|
/* (A*B?A*B:1.0f) this takes care of potential divide by zero errors */
|
|
|
|
float dphi;
|
|
|
|
float axis[3];
|
|
float mat[3][3];
|
|
|
|
VECCOPY(axis, t->viewinv[2]);
|
|
VecMulf(axis, -1.0f);
|
|
Normalise(axis);
|
|
|
|
dphi = saacos((float)deler);
|
|
if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
|
|
|
|
if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
|
|
else t->fac += dphi;
|
|
|
|
/*
|
|
clamping angle between -2 PI and 2 PI (not sure if useful so commented out - theeth)
|
|
if (t->fac >= 2 * M_PI)
|
|
t->fac -= 2 * M_PI;
|
|
else if (t->fac <= -2 * M_PI)
|
|
t->fac -= -2 * M_PI;
|
|
*/
|
|
|
|
final = t->fac;
|
|
|
|
snapGrid(t, &final);
|
|
|
|
t->imval[0] = mval[0];
|
|
t->imval[1] = mval[1];
|
|
|
|
if (t->con.applyRot) {
|
|
t->con.applyRot(t, NULL, axis);
|
|
}
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
applyNumInput(&t->num, &final);
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Rot: %s %s", &c[0], t->proptext);
|
|
|
|
final *= (float)(M_PI / 180.0);
|
|
}
|
|
else {
|
|
sprintf(str, "Rot: %.2f%s %s", 180.0*final/M_PI, t->con.text, t->proptext);
|
|
}
|
|
|
|
VecRotToMat3(axis, final * td->factor, mat);
|
|
|
|
t->val = final; // used in manipulator
|
|
Mat3CpyMat3(t->mat, mat); // used in manipulator
|
|
|
|
applyRotation(t, final, axis);
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* ************************** TRACKBALL *************************** */
|
|
|
|
void initTrackball(TransInfo *t)
|
|
{
|
|
t->idx_max = 1;
|
|
t->num.idx_max = 1;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = (float)((5.0/180)*M_PI);
|
|
t->snap[2] = t->snap[1] * 0.2f;
|
|
t->fac = 0;
|
|
t->transform = Trackball;
|
|
|
|
t->flag |= T_NO_CONSTRAINT; /* making sure the flag is always set */
|
|
}
|
|
|
|
static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float mat[3][3], smat[3][3], totmat[3][3];
|
|
int i;
|
|
|
|
VecRotToMat3(axis1, angles[0], smat);
|
|
VecRotToMat3(axis2, angles[1], totmat);
|
|
|
|
Mat3MulMat3(mat, smat, totmat);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (t->around == V3D_LOCAL) {
|
|
if (t->flag & T_OBJECT)
|
|
VECCOPY(t->center, td->center); // not supported in editmode yet
|
|
}
|
|
|
|
if (t->flag & T_PROP_EDIT) {
|
|
VecRotToMat3(axis1, td->factor * angles[0], smat);
|
|
VecRotToMat3(axis2, td->factor * angles[1], totmat);
|
|
|
|
Mat3MulMat3(mat, smat, totmat);
|
|
}
|
|
|
|
ElementRotation(t, td, mat);
|
|
}
|
|
}
|
|
|
|
int Trackball(TransInfo *t, short mval[2])
|
|
{
|
|
char str[80];
|
|
float axis1[3], axis2[3];
|
|
float mat[3][3], totmat[3][3], smat[3][3];
|
|
float phi[2];
|
|
|
|
VECCOPY(axis1, t->persinv[0]);
|
|
VECCOPY(axis2, t->persinv[1]);
|
|
Normalise(axis1);
|
|
Normalise(axis2);
|
|
|
|
/* factore has to become setting or so */
|
|
phi[0]= 0.01f*(float)( t->imval[1] - mval[1] );
|
|
phi[1]= 0.01f*(float)( mval[0] - t->imval[0] );
|
|
|
|
//if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
|
|
//else t->fac += dphi;
|
|
|
|
snapGrid(t, phi);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
char c[40];
|
|
|
|
applyNumInput(&t->num, phi);
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Trackball: %s %s %s", &c[0], &c[20], t->proptext);
|
|
|
|
phi[0] *= (float)(M_PI / 180.0);
|
|
phi[1] *= (float)(M_PI / 180.0);
|
|
}
|
|
else {
|
|
sprintf(str, "Trackball: %.2f %.2f %s", 180.0*phi[0]/M_PI, 180.0*phi[1]/M_PI, t->proptext);
|
|
}
|
|
|
|
VecRotToMat3(axis1, phi[0], smat);
|
|
VecRotToMat3(axis2, phi[1], totmat);
|
|
|
|
Mat3MulMat3(mat, smat, totmat);
|
|
|
|
Mat3CpyMat3(t->mat, mat); // used in manipulator
|
|
|
|
applyTrackball(t, axis1, axis2, phi);
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** TRANSLATION *************************** */
|
|
|
|
void initTranslation(TransInfo *t)
|
|
{
|
|
t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
|
|
t->num.idx_max = t->idx_max;
|
|
t->transform = Translation;
|
|
|
|
if(t->spacetype == SPACE_VIEW3D) {
|
|
/* initgrabz() defines a factor for perspective depth correction, used in window_to_3d() */
|
|
if(t->flag & (T_EDIT|T_POSE)) {
|
|
Object *ob= G.obedit?G.obedit:t->poseobj;
|
|
float vec[3];
|
|
|
|
VECCOPY(vec, t->center);
|
|
Mat4MulVecfl(ob->obmat, vec);
|
|
initgrabz(vec[0], vec[1], vec[2]);
|
|
}
|
|
else initgrabz(t->center[0], t->center[1], t->center[2]);
|
|
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = G.vd->gridview * 1.0f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
}
|
|
else if(t->spacetype == SPACE_IMAGE) {
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.125f;
|
|
t->snap[2] = 0.0625f;
|
|
}
|
|
else {
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = t->snap[2] = 1.0f;
|
|
}
|
|
}
|
|
|
|
static void headerTranslation(TransInfo *t, float vec[3], char *str) {
|
|
char tvec[60];
|
|
char distvec[20];
|
|
float dvec[3];
|
|
float dist;
|
|
|
|
convertVecToDisplayNum(vec, dvec);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
outputNumInput(&(t->num), tvec);
|
|
dist = VecLength(t->num.val);
|
|
}
|
|
else {
|
|
dist = VecLength(vec);
|
|
sprintf(&tvec[0], "%.4f", dvec[0]);
|
|
sprintf(&tvec[20], "%.4f", dvec[1]);
|
|
sprintf(&tvec[40], "%.4f", dvec[2]);
|
|
}
|
|
|
|
if( dist > 1e10 || dist < -1e10 ) /* prevent string buffer overflow */
|
|
sprintf(distvec, "%.4e", dist);
|
|
else
|
|
sprintf(distvec, "%.4f", dist);
|
|
|
|
if (t->con.mode & CON_APPLY) {
|
|
switch(t->num.idx_max) {
|
|
case 0:
|
|
sprintf(str, "D: %s (%s)%s %s", &tvec[0], distvec, t->con.text, t->proptext);
|
|
break;
|
|
case 1:
|
|
sprintf(str, "D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
|
|
break;
|
|
case 2:
|
|
sprintf(str, "D: %s D: %s D: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
|
|
}
|
|
}
|
|
else {
|
|
if(t->flag & T_2D_EDIT)
|
|
sprintf(str, "Dx: %s Dy: %s (%s)%s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext);
|
|
else
|
|
sprintf(str, "Dx: %s Dy: %s Dz: %s (%s)%s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext);
|
|
}
|
|
}
|
|
|
|
static void applyTranslation(TransInfo *t, float vec[3]) {
|
|
TransData *td = t->data;
|
|
float tvec[3];
|
|
int i;
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (t->con.applyVec) {
|
|
float pvec[3];
|
|
t->con.applyVec(t, td, vec, tvec, pvec);
|
|
}
|
|
else {
|
|
VECCOPY(tvec, vec);
|
|
}
|
|
|
|
Mat3MulVecfl(td->smtx, tvec);
|
|
VecMulf(tvec, td->factor);
|
|
|
|
protectedTransBits(td->protectflag, tvec);
|
|
|
|
/* transdata ipokey */
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
add_tdi_poin(tdi->locx, tdi->oldloc, tvec[0]);
|
|
add_tdi_poin(tdi->locy, tdi->oldloc+1, tvec[1]);
|
|
add_tdi_poin(tdi->locz, tdi->oldloc+2, tvec[2]);
|
|
}
|
|
else VecAddf(td->loc, td->iloc, tvec);
|
|
}
|
|
}
|
|
|
|
/* uses t->vec to store actual translation in */
|
|
int Translation(TransInfo *t, short mval[2])
|
|
{
|
|
float tvec[3];
|
|
char str[200];
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
float dvec[3];
|
|
/* calculate the main translation and the precise one separate */
|
|
convertViewVec(t, dvec, (short)(mval[0] - t->shiftmval[0]), (short)(mval[1] - t->shiftmval[1]));
|
|
VecMulf(dvec, 0.1f);
|
|
convertViewVec(t, t->vec, (short)(t->shiftmval[0] - t->imval[0]), (short)(t->shiftmval[1] - t->imval[1]));
|
|
VecAddf(t->vec, t->vec, dvec);
|
|
}
|
|
else convertViewVec(t, t->vec, (short)(mval[0] - t->imval[0]), (short)(mval[1] - t->imval[1]));
|
|
|
|
if (t->con.mode & CON_APPLY) {
|
|
float pvec[3] = {0.0f, 0.0f, 0.0f};
|
|
t->con.applyVec(t, NULL, t->vec, tvec, pvec);
|
|
VECCOPY(t->vec, tvec);
|
|
headerTranslation(t, pvec, str);
|
|
}
|
|
else {
|
|
snapGrid(t, t->vec);
|
|
applyNumInput(&t->num, t->vec);
|
|
headerTranslation(t, t->vec, str);
|
|
}
|
|
|
|
applyTranslation(t, t->vec);
|
|
|
|
/* evil hack - redo translation if cliiping needeed */
|
|
if (t->flag & T_CLIP_UV && clipUVTransform(t, t->vec, 0))
|
|
applyTranslation(t, t->vec);
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** SHRINK/FATTEN *************************** */
|
|
|
|
void initShrinkFatten(TransInfo *t)
|
|
{
|
|
if (G.obedit==NULL || G.obedit->type != OB_MESH) {
|
|
initTransModeFlags(t, TFM_RESIZE);
|
|
initResize(t);
|
|
return;
|
|
}
|
|
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 1.0f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = ShrinkFatten;
|
|
}
|
|
|
|
|
|
|
|
int ShrinkFatten(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3];
|
|
float distance;
|
|
int i;
|
|
char str[50];
|
|
TransData *td = t->data;
|
|
|
|
distance = -InputVerticalAbsolute(t, mval);
|
|
|
|
snapGrid(t, &distance);
|
|
|
|
applyNumInput(&t->num, &distance);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Shrink/Fatten: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "Shrink/Fatten: %.4f %s", distance, t->proptext);
|
|
}
|
|
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
VECCOPY(vec, td->axismtx[2]);
|
|
VecMulf(vec, distance);
|
|
VecMulf(vec, td->factor);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** TILT *************************** */
|
|
|
|
void initTilt(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = (float)((5.0/180)*M_PI);
|
|
t->snap[2] = t->snap[1] * 0.2f;
|
|
t->fac = 0;
|
|
t->transform = Tilt;
|
|
}
|
|
|
|
|
|
|
|
int Tilt(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
int i;
|
|
char str[50];
|
|
|
|
float final;
|
|
|
|
int dx2 = t->center2d[0] - mval[0];
|
|
int dy2 = t->center2d[1] - mval[1];
|
|
float B = (float)sqrt(dx2*dx2+dy2*dy2);
|
|
|
|
int dx1 = t->center2d[0] - t->imval[0];
|
|
int dy1 = t->center2d[1] - t->imval[1];
|
|
float A = (float)sqrt(dx1*dx1+dy1*dy1);
|
|
|
|
int dx3 = mval[0] - t->imval[0];
|
|
int dy3 = mval[1] - t->imval[1];
|
|
|
|
float deler= ((dx1*dx1+dy1*dy1)+(dx2*dx2+dy2*dy2)-(dx3*dx3+dy3*dy3))
|
|
/ (2 * A * B);
|
|
|
|
float dphi;
|
|
|
|
dphi = saacos(deler);
|
|
if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
|
|
|
|
if(G.qual & LR_SHIFTKEY) t->fac += dphi/30.0f;
|
|
else t->fac += dphi;
|
|
|
|
final = t->fac;
|
|
|
|
snapGrid(t, &final);
|
|
|
|
t->imval[0] = mval[0];
|
|
t->imval[1] = mval[1];
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
applyNumInput(&t->num, &final);
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Tilt: %s %s", &c[0], t->proptext);
|
|
|
|
final *= (float)(M_PI / 180.0);
|
|
}
|
|
else {
|
|
sprintf(str, "Tilt: %.2f %s", 180.0*final/M_PI, t->proptext);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->val) {
|
|
*td->val = td->ival + final * td->factor;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* ******************** Curve Shrink/Fatten *************** */
|
|
|
|
int CurveShrinkFatten(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float ratio;
|
|
int i;
|
|
char str[50];
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
|
|
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
|
|
|
|
}
|
|
else {
|
|
float dx= (float)(t->center2d[0] - mval[0]);
|
|
float dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
|
|
snapGrid(t, &ratio);
|
|
|
|
applyNumInput(&t->num, &ratio);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
sprintf(str, "Shrink/Fatten: %s", c);
|
|
}
|
|
else {
|
|
sprintf(str, "Shrink/Fatten: %3f", ratio);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if(td->val) {
|
|
//*td->val= ratio;
|
|
*td->val= td->ival*ratio;
|
|
if (*td->val <= 0.0f) *td->val = 0.0001f;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void initCurveShrinkFatten(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = CurveShrinkFatten;
|
|
t->fac = (float)sqrt( (
|
|
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
|
|
+
|
|
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
|
|
) );
|
|
}
|
|
|
|
/* ************************** PUSH/PULL *************************** */
|
|
|
|
void initPushPull(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 1.0f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = PushPull;
|
|
}
|
|
|
|
|
|
|
|
int PushPull(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3], axis[3];
|
|
float distance;
|
|
int i;
|
|
char str[50];
|
|
TransData *td = t->data;
|
|
|
|
distance = InputVerticalAbsolute(t, mval);
|
|
|
|
snapGrid(t, &distance);
|
|
|
|
applyNumInput(&t->num, &distance);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Push/Pull: %s%s %s", c, t->con.text, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "Push/Pull: %.4f%s %s", distance, t->con.text, t->proptext);
|
|
}
|
|
|
|
if (t->con.applyRot && t->con.mode & CON_APPLY) {
|
|
t->con.applyRot(t, NULL, axis);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
VecSubf(vec, t->center, td->center);
|
|
if (t->con.applyRot && t->con.mode & CON_APPLY) {
|
|
t->con.applyRot(t, td, axis);
|
|
if (isLockConstraint(t)) {
|
|
float dvec[3];
|
|
Projf(dvec, vec, axis);
|
|
VecSubf(vec, vec, dvec);
|
|
}
|
|
else {
|
|
Projf(vec, vec, axis);
|
|
}
|
|
}
|
|
Normalise(vec);
|
|
VecMulf(vec, distance);
|
|
VecMulf(vec, td->factor);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** CREASE *************************** */
|
|
|
|
void initCrease(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = Crease;
|
|
t->fac = (float)sqrt(
|
|
(
|
|
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
|
|
+
|
|
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
|
|
) );
|
|
|
|
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
|
|
}
|
|
|
|
int Crease(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float crease;
|
|
int i;
|
|
char str[50];
|
|
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
|
|
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
|
|
crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
crease+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -crease);
|
|
|
|
}
|
|
else {
|
|
float dx= (float)(t->center2d[0] - mval[0]);
|
|
float dy= (float)(t->center2d[1] - mval[1]);
|
|
crease = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
|
|
crease -= 1.0f;
|
|
if (crease > 1.0f) crease = 1.0f;
|
|
|
|
snapGrid(t, &crease);
|
|
|
|
applyNumInput(&t->num, &crease);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
if (crease >= 0.0f)
|
|
sprintf(str, "Crease: +%s %s", c, t->proptext);
|
|
else
|
|
sprintf(str, "Crease: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
if (crease >= 0.0f)
|
|
sprintf(str, "Crease: +%.3f %s", crease, t->proptext);
|
|
else
|
|
sprintf(str, "Crease: %.3f %s", crease, t->proptext);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->val) {
|
|
*td->val = td->ival + crease * td->factor;
|
|
if (*td->val < 0.0f) *td->val = 0.0f;
|
|
if (*td->val > 1.0f) *td->val = 1.0f;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** MIRROR *************************** */
|
|
|
|
void Mirror(short mode)
|
|
{
|
|
TransData *td;
|
|
float mati[3][3], matview[3][3], mat[3][3];
|
|
float size[3];
|
|
int i;
|
|
|
|
Trans.context = CTX_NO_PET;
|
|
|
|
initTrans(&Trans); // internal data, mouse, vectors
|
|
|
|
Mat3One(mati);
|
|
Mat3CpyMat4(matview, Trans.viewinv); // t->viewinv was set in initTrans
|
|
Mat3Ortho(matview);
|
|
|
|
initTransModeFlags(&Trans, TFM_MIRROR); // modal settings in struct Trans
|
|
|
|
createTransData(&Trans); // make TransData structs from selection
|
|
|
|
calculatePropRatio(&Trans);
|
|
calculateCenter(&Trans);
|
|
|
|
initResize(&Trans);
|
|
|
|
if (Trans.total == 0) {
|
|
postTrans(&Trans);
|
|
return;
|
|
}
|
|
|
|
size[0] = size[1] = size[2] = 1.0f;
|
|
td = Trans.data;
|
|
|
|
switch (mode) {
|
|
case 1:
|
|
size[0] = -1.0f;
|
|
setConstraint(&Trans, mati, (CON_AXIS0), "");
|
|
break;
|
|
case 2:
|
|
size[1] = -1.0f;
|
|
setConstraint(&Trans, mati, (CON_AXIS1), "");
|
|
break;
|
|
case 3:
|
|
size[2] = -1.0f;
|
|
setConstraint(&Trans, mati, (CON_AXIS2), "");
|
|
break;
|
|
case 4:
|
|
size[0] = -1.0f;
|
|
setLocalConstraint(&Trans, (CON_AXIS0), "");
|
|
break;
|
|
case 5:
|
|
size[1] = -1.0f;
|
|
setLocalConstraint(&Trans, (CON_AXIS1), "");
|
|
break;
|
|
case 6:
|
|
size[2] = -1.0f;
|
|
setLocalConstraint(&Trans, (CON_AXIS2), "");
|
|
break;
|
|
case 7:
|
|
size[0] = -1.0f;
|
|
setConstraint(&Trans, matview, (CON_AXIS0), "");
|
|
break;
|
|
case 8:
|
|
size[1] = -1.0f;
|
|
setConstraint(&Trans, matview, (CON_AXIS1), "");
|
|
break;
|
|
case 9:
|
|
size[2] = -1.0f;
|
|
setConstraint(&Trans, matview, (CON_AXIS2), "");
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
SizeToMat3(size, mat);
|
|
|
|
if (Trans.con.applySize) {
|
|
Trans.con.applySize(&Trans, NULL, mat);
|
|
}
|
|
|
|
for(i = 0 ; i < Trans.total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
ElementResize(&Trans, td, mat);
|
|
}
|
|
|
|
recalcData(&Trans);
|
|
|
|
BIF_undo_push("Mirror");
|
|
|
|
/* free data, reset vars */
|
|
postTrans(&Trans);
|
|
|
|
/* send events out for redraws */
|
|
viewRedrawPost(&Trans);
|
|
}
|
|
|
|
/* ******************** EditBone (B-bone) width scaling *************** */
|
|
|
|
static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
|
|
{
|
|
float tmat[3][3], smat[3][3], oldy;
|
|
float sizemat[3][3];
|
|
|
|
Mat3MulMat3(smat, mat, td->mtx);
|
|
Mat3MulMat3(tmat, td->smtx, smat);
|
|
|
|
if (t->con.applySize) {
|
|
t->con.applySize(t, td, tmat);
|
|
}
|
|
|
|
/* we've tucked the scale in loc */
|
|
oldy= td->iloc[1];
|
|
SizeToMat3(td->iloc, sizemat);
|
|
Mat3MulMat3(tmat, tmat, sizemat);
|
|
Mat3ToSize(tmat, td->loc);
|
|
td->loc[1]= oldy;
|
|
}
|
|
|
|
|
|
int BoneSize(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float size[3], mat[3][3];
|
|
float ratio;
|
|
int i;
|
|
char str[50];
|
|
|
|
/* for manipulator, center handle, the scaling can't be done relative to center */
|
|
if( (t->flag & T_USES_MANIPULATOR) && t->con.mode==0) {
|
|
ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1]))/100.0f;
|
|
}
|
|
else {
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
|
|
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
|
|
|
|
}
|
|
else {
|
|
float dx= (float)(t->center2d[0] - mval[0]);
|
|
float dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
|
|
/* flip scale, but not for manipulator center handle */
|
|
if ((t->center2d[0] - mval[0]) * (t->center2d[0] - t->imval[0]) +
|
|
(t->center2d[1] - mval[1]) * (t->center2d[1] - t->imval[1]) < 0)
|
|
ratio *= -1.0f;
|
|
}
|
|
|
|
size[0] = size[1] = size[2] = ratio;
|
|
|
|
snapGrid(t, size);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
applyNumInput(&t->num, size);
|
|
constraintNumInput(t, size);
|
|
}
|
|
|
|
SizeToMat3(size, mat);
|
|
|
|
if (t->con.applySize) {
|
|
t->con.applySize(t, NULL, mat);
|
|
}
|
|
|
|
Mat3CpyMat3(t->mat, mat); // used in manipulator
|
|
|
|
headerResize(t, size, str);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
ElementBoneSize(t, td, mat);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void initBoneSize(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = BoneSize;
|
|
t->fac = (float)sqrt( (
|
|
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
|
|
+
|
|
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
|
|
) );
|
|
|
|
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
|
|
}
|
|
|
|
/* ******************** EditBone envelope *************** */
|
|
|
|
int BoneEnvelope(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float ratio;
|
|
int i;
|
|
char str[50];
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
float dx= (float)(t->center2d[0] - t->shiftmval[0]);
|
|
float dy= (float)(t->center2d[1] - t->shiftmval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -ratio);
|
|
|
|
}
|
|
else {
|
|
float dx= (float)(t->center2d[0] - mval[0]);
|
|
float dy= (float)(t->center2d[1] - mval[1]);
|
|
ratio = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
|
|
snapGrid(t, &ratio);
|
|
|
|
applyNumInput(&t->num, &ratio);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
sprintf(str, "Envelope: %s", c);
|
|
}
|
|
else {
|
|
sprintf(str, "Envelope: %3f", ratio);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if(td->val) *td->val= td->ival*ratio;
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
headerprint(str);
|
|
|
|
force_draw(0);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void initBoneEnvelope(TransInfo *t)
|
|
{
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
t->transform = BoneEnvelope;
|
|
t->fac = (float)sqrt( (
|
|
((float)(t->center2d[1] - t->imval[1]))*((float)(t->center2d[1] - t->imval[1]))
|
|
+
|
|
((float)(t->center2d[0] - t->imval[0]))*((float)(t->center2d[0] - t->imval[0]))
|
|
) );
|
|
|
|
if(t->fac==0.0f) t->fac= 1.0f; // prevent Inf
|
|
}
|
|
|
|
/* ************************************ */
|
|
|
|
void BIF_TransformSetUndo(char *str)
|
|
{
|
|
Trans.undostr= str;
|
|
}
|
|
|
|
|