Note: there were some crashes that would occur if context was not reset everytime the modal callback was run. Probably there's something about the context info we need to be more careful about.
4843 lines
107 KiB
C
4843 lines
107 KiB
C
/**
|
|
* $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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <float.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_action_types.h" /* for some special action-editor settings */
|
|
#include "DNA_constraint_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_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_editparticle.h"
|
|
//#include "BIF_drawimage.h" /* uvco_to_areaco_noclip */
|
|
//#include "BIF_editaction.h"
|
|
|
|
#include "BKE_action.h" /* get_action_frame */
|
|
//#include "BKE_bad_level_calls.h"/* popmenu and error */
|
|
#include "BKE_bmesh.h"
|
|
#include "BKE_constraint.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_particle.h"
|
|
#include "BKE_pointcache.h"
|
|
#include "BKE_utildefines.h"
|
|
#include "BKE_context.h"
|
|
|
|
//#include "BSE_drawipo.h"
|
|
//#include "BSE_editnla_types.h" /* for NLAWIDTH */
|
|
//#include "BSE_editaction_types.h"
|
|
//#include "BSE_time.h"
|
|
//#include "BSE_view.h"
|
|
|
|
#include "ED_view3d.h"
|
|
#include "ED_screen.h"
|
|
#include "UI_view2d.h"
|
|
#include "WM_types.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"
|
|
|
|
/******************************** Helper functions ************************************/
|
|
|
|
/* GLOBAL Wrapper Fonctions */
|
|
|
|
//void BIF_drawSnap()
|
|
//{
|
|
// drawSnapping(&Trans);
|
|
//}
|
|
|
|
/* ************************** Dashed help line **************************** */
|
|
|
|
|
|
/* bad frontbuffer call... because it is used in transform after force_draw() */
|
|
static void helpline(TransInfo *t, float *vec)
|
|
{
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
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
|
|
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/* ************************** 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]) {
|
|
float x, pad;
|
|
|
|
pad = t->ar->winx / 10;
|
|
|
|
if (t->flag & T_SHIFT_MOD) {
|
|
/* deal with Shift key by adding motion / 10 to motion before shift press */
|
|
x = t->shiftmval[0] + (float)(mval[0] - t->shiftmval[0]) / 10.0f;
|
|
}
|
|
else {
|
|
x = mval[0];
|
|
}
|
|
return (x - pad) / (t->ar->winx - 2 * pad);
|
|
}
|
|
|
|
float InputHorizontalAbsolute(TransInfo *t, short mval[2]) {
|
|
float vec[3];
|
|
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]));
|
|
}
|
|
Projf(vec, t->vec, t->viewinv[0]);
|
|
return Inpf(t->viewinv[0], vec) * 2.0f;
|
|
}
|
|
|
|
float InputVerticalRatio(TransInfo *t, short mval[2]) {
|
|
float y, pad;
|
|
|
|
pad = t->ar->winy / 10;
|
|
|
|
if (t->flag & T_SHIFT_MOD) {
|
|
/* deal with Shift key by adding motion / 10 to motion before shift press */
|
|
y = t->shiftmval[1] + (float)(mval[1] - t->shiftmval[1]) / 10.0f;
|
|
}
|
|
else {
|
|
y = mval[0];
|
|
}
|
|
return (y - pad) / (t->ar->winy - 2 * pad);
|
|
}
|
|
|
|
float InputVerticalAbsolute(TransInfo *t, short mval[2]) {
|
|
float vec[3];
|
|
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]));
|
|
}
|
|
Projf(vec, t->vec, t->viewinv[1]);
|
|
return Inpf(t->viewinv[1], vec) * 2.0f;
|
|
}
|
|
|
|
float InputDeltaAngle(TransInfo *t, short mval[2])
|
|
{
|
|
double dx2 = mval[0] - t->center2d[0];
|
|
double dy2 = mval[1] - t->center2d[1];
|
|
double B = sqrt(dx2*dx2+dy2*dy2);
|
|
|
|
double dx1 = t->imval[0] - t->center2d[0];
|
|
double dy1 = t->imval[1] - t->center2d[1];
|
|
double A = sqrt(dx1*dx1+dy1*dy1);
|
|
|
|
double dx3 = mval[0] - t->imval[0];
|
|
double 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 = ((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;
|
|
|
|
dphi = saacos((float)deler);
|
|
if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
|
|
|
|
/* If the angle is zero, because of lack of precision close to the 1.0 value in acos
|
|
* approximate the angle with the oposite side of the normalized triangle
|
|
* This is a good approximation here since the smallest acos value seems to be around
|
|
* 0.02 degree and lower values don't even have a 0.01% error compared to the approximation
|
|
* */
|
|
if (dphi == 0)
|
|
{
|
|
double dx, dy;
|
|
|
|
dx2 /= A;
|
|
dy2 /= A;
|
|
|
|
dx1 /= B;
|
|
dy1 /= B;
|
|
|
|
dx = dx1 - dx2;
|
|
dy = dy1 - dy2;
|
|
|
|
dphi = sqrt(dx*dx + dy*dy);
|
|
if( (dx1*dy2-dx2*dy1)>0.0 ) dphi= -dphi;
|
|
}
|
|
|
|
if(t->flag & T_SHIFT_MOD) dphi = dphi/30.0f;
|
|
|
|
/* if no delta angle, don't update initial position */
|
|
if (dphi != 0)
|
|
{
|
|
t->imval[0] = mval[0];
|
|
t->imval[1] = mval[1];
|
|
}
|
|
|
|
return dphi;
|
|
}
|
|
|
|
/* ************************** SPACE DEPENDANT CODE **************************** */
|
|
|
|
void setTransformViewMatrices(TransInfo *t)
|
|
{
|
|
if(t->spacetype==SPACE_VIEW3D) {
|
|
View3D *v3d = t->view;
|
|
|
|
Mat4CpyMat4(t->viewmat, v3d->viewmat);
|
|
Mat4CpyMat4(t->viewinv, v3d->viewinv);
|
|
Mat4CpyMat4(t->persmat, v3d->persmat);
|
|
Mat4CpyMat4(t->persinv, v3d->persinv);
|
|
t->persp = v3d->persp;
|
|
}
|
|
else {
|
|
Mat4One(t->viewmat);
|
|
Mat4One(t->viewinv);
|
|
Mat4One(t->persmat);
|
|
Mat4One(t->persinv);
|
|
t->persp = V3D_ORTHO;
|
|
}
|
|
|
|
calculateCenter2D(t);
|
|
}
|
|
|
|
void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D) {
|
|
window_to_3d(t->ar, t->view, vec, dx, dy);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
View2D *v2d = t->view;
|
|
float divx, divy, aspx, aspy;
|
|
|
|
// TRANSFORM_FIX_ME
|
|
//transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
|
|
divx= v2d->mask.xmax-v2d->mask.xmin;
|
|
divy= v2d->mask.ymax-v2d->mask.ymin;
|
|
|
|
vec[0]= aspx*(v2d->cur.xmax-v2d->cur.xmin)*(dx)/divx;
|
|
vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
|
|
vec[2]= 0.0f;
|
|
}
|
|
else if(t->spacetype==SPACE_IPO) {
|
|
View2D *v2d = t->view;
|
|
float divx, divy;
|
|
|
|
divx= v2d->mask.xmax-v2d->mask.xmin;
|
|
divy= v2d->mask.ymax-v2d->mask.ymin;
|
|
|
|
vec[0]= (v2d->cur.xmax-v2d->cur.xmin)*(dx) / (divx);
|
|
vec[1]= (v2d->cur.ymax-v2d->cur.ymin)*(dy) / (divy);
|
|
vec[2]= 0.0f;
|
|
}
|
|
}
|
|
|
|
void projectIntView(TransInfo *t, float *vec, int *adr)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D) {
|
|
project_int_noclip(t->ar, t->view, vec, adr);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
float aspx, aspy, v[2];
|
|
|
|
// TRANSFORM_FIX_ME
|
|
//transform_aspect_ratio_tface_uv(&aspx, &aspy);
|
|
v[0]= vec[0]/aspx;
|
|
v[1]= vec[1]/aspy;
|
|
|
|
// TRANSFORM_FIX_ME
|
|
//uvco_to_areaco_noclip(v, adr);
|
|
}
|
|
else if(t->spacetype==SPACE_IPO) {
|
|
short out[2] = {0.0f, 0.0f};
|
|
|
|
// TRANSFORM_FIX_ME
|
|
//ipoco_to_areaco(G.v2d, vec, out);
|
|
adr[0]= out[0];
|
|
adr[1]= out[1];
|
|
}
|
|
}
|
|
|
|
void projectFloatView(TransInfo *t, float *vec, float *adr)
|
|
{
|
|
if (t->spacetype==SPACE_VIEW3D) {
|
|
project_float_noclip(t->ar, t->view, vec, adr);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
int a[2];
|
|
|
|
projectIntView(t, vec, a);
|
|
adr[0]= a[0];
|
|
adr[1]= a[1];
|
|
}
|
|
else if(t->spacetype==SPACE_IPO) {
|
|
int a[2];
|
|
|
|
projectIntView(t, vec, a);
|
|
adr[0]= a[0];
|
|
adr[1]= a[1];
|
|
}
|
|
}
|
|
|
|
void convertVecToDisplayNum(float *vec, float *num)
|
|
{
|
|
// TRANSFORM_FIX_ME
|
|
TransInfo *t = NULL; //BIF_GetTransInfo();
|
|
|
|
VECCOPY(num, vec);
|
|
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void convertDisplayNumToVec(float *num, float *vec)
|
|
{
|
|
// TRANSFORM_FIX_ME
|
|
TransInfo *t = NULL; //BIF_GetTransInfo();
|
|
|
|
VECCOPY(vec, num);
|
|
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void viewRedrawForce(TransInfo *t)
|
|
{
|
|
if (t->spacetype == SPACE_VIEW3D)
|
|
{
|
|
// TRANSFORM_FIX_ME
|
|
// need to redraw ALL 3d view
|
|
ED_area_tag_redraw(t->sa);
|
|
}
|
|
else if (t->spacetype == SPACE_ACTION) {
|
|
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
|
|
|
|
// TRANSFORM_FIX_ME
|
|
if (saction->lock) {
|
|
// whole window...
|
|
}
|
|
else
|
|
ED_area_tag_redraw(t->sa);
|
|
}
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
else if (t->spacetype==SPACE_IMAGE) {
|
|
if (G.sima->lock) force_draw_plus(SPACE_VIEW3D, 0);
|
|
else force_draw(0);
|
|
}
|
|
else if (t->spacetype == SPACE_ACTION) {
|
|
if (G.saction->lock) {
|
|
short context;
|
|
|
|
/* we ignore the pointer this function returns (not needed) */
|
|
get_action_context(&context);
|
|
|
|
if (context == ACTCONT_ACTION)
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
else if (context == ACTCONT_SHAPEKEY)
|
|
force_draw_all(0);
|
|
else
|
|
force_draw(0);
|
|
}
|
|
else {
|
|
force_draw(0);
|
|
}
|
|
}
|
|
else if (t->spacetype == SPACE_NLA) {
|
|
if (G.snla->lock)
|
|
force_draw_all(0);
|
|
else
|
|
force_draw(0);
|
|
}
|
|
else if (t->spacetype == SPACE_IPO) {
|
|
/* update realtime */
|
|
if (G.sipo->lock) {
|
|
if (G.sipo->blocktype==ID_MA || G.sipo->blocktype==ID_TE)
|
|
force_draw_plus(SPACE_BUTS, 0);
|
|
else if (G.sipo->blocktype==ID_CA)
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
else if (G.sipo->blocktype==ID_KE)
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
else if (G.sipo->blocktype==ID_PO)
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
else if (G.sipo->blocktype==ID_OB)
|
|
force_draw_plus(SPACE_VIEW3D, 0);
|
|
else if (G.sipo->blocktype==ID_SEQ)
|
|
force_draw_plus(SPACE_SEQ, 0);
|
|
else
|
|
force_draw(0);
|
|
}
|
|
else {
|
|
force_draw(0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void viewRedrawPost(TransInfo *t)
|
|
{
|
|
ED_area_headerprint(t->sa, NULL);
|
|
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
if(t->spacetype==SPACE_VIEW3D) {
|
|
allqueue(REDRAWBUTSOBJECT, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
else if(t->spacetype==SPACE_IMAGE) {
|
|
allqueue(REDRAWIMAGE, 0);
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
}
|
|
else if(ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
|
|
allqueue(REDRAWVIEW3D, 0);
|
|
allqueue(REDRAWACTION, 0);
|
|
allqueue(REDRAWNLA, 0);
|
|
allqueue(REDRAWIPO, 0);
|
|
allqueue(REDRAWTIME, 0);
|
|
allqueue(REDRAWBUTSOBJECT, 0);
|
|
}
|
|
|
|
scrarea_queue_headredraw(curarea);
|
|
#endif
|
|
}
|
|
|
|
/* ************************** TRANSFORMATIONS **************************** */
|
|
|
|
void BIF_selectOrientation() {
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
short val;
|
|
char *str_menu = BIF_menustringTransformOrientation("Orientation");
|
|
val= pupmenu(str_menu);
|
|
MEM_freeN(str_menu);
|
|
|
|
if(val >= 0) {
|
|
G.vd->twmode = val;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void view_editmove(unsigned short event)
|
|
{
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
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);
|
|
#endif
|
|
}
|
|
|
|
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_BEVEL:
|
|
return "Bevel";
|
|
case TFM_BWEIGHT:
|
|
return "Bevel Weight";
|
|
case TFM_CREASE:
|
|
return "Crease";
|
|
case TFM_BONESIZE:
|
|
return "Bone Width";
|
|
case TFM_BONE_ENVELOPE:
|
|
return "Bone Envelope";
|
|
case TFM_TIME_TRANSLATE:
|
|
return "Translate Anim. Data";
|
|
case TFM_TIME_SCALE:
|
|
return "Scale Anim. Data";
|
|
case TFM_TIME_SLIDE:
|
|
return "Time Slide";
|
|
case TFM_BAKE_TIME:
|
|
return "Key Time";
|
|
case TFM_MIRROR:
|
|
return "Mirror";
|
|
}
|
|
return "Transform";
|
|
}
|
|
|
|
/* ************************************************* */
|
|
|
|
void transformEvent(TransInfo *t, wmEvent *event)
|
|
{
|
|
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(t);
|
|
|
|
t->event = event;
|
|
|
|
if (event->type == MOUSEMOVE)
|
|
{
|
|
t->mval[0] = event->x - t->ar->winrct.xmin;
|
|
t->mval[1] = event->y - t->ar->winrct.ymin;
|
|
}
|
|
|
|
if (event->val) {
|
|
switch (event->type){
|
|
/* enforce redraw of transform when modifiers are used */
|
|
case LEFTCTRLKEY:
|
|
case RIGHTCTRLKEY:
|
|
t->redraw = 1;
|
|
break;
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
/* shift is modifier for higher resolution transform, works nice to store this mouse position */
|
|
t->shiftmval[0] = event->x - t->ar->winrct.xmin;
|
|
t->shiftmval[1] = event->y - t->ar->winrct.ymin;
|
|
t->flag |= T_SHIFT_MOD;
|
|
t->redraw = 1;
|
|
break;
|
|
|
|
case SPACEKEY:
|
|
if ((t->spacetype==SPACE_VIEW3D) && event->alt) {
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
short mval[2];
|
|
|
|
getmouseco_sc(mval);
|
|
BIF_selectOrientation();
|
|
calc_manipulator_stats(curarea);
|
|
Mat3CpyMat4(t->spacemtx, G.vd->twmat);
|
|
warp_pointer(mval[0], mval[1]);
|
|
#endif
|
|
}
|
|
else {
|
|
t->state = TRANS_CONFIRM;
|
|
}
|
|
break;
|
|
|
|
|
|
case MIDDLEMOUSE:
|
|
if ((t->flag & T_NO_CONSTRAINT)==0) {
|
|
/* exception for switching to dolly, or trackball, in camera view */
|
|
if (t->flag & T_CAMERA) {
|
|
if (t->mode==TFM_TRANSLATION)
|
|
setLocalConstraint(t, (CON_AXIS2), "along local Z");
|
|
else if (t->mode==TFM_ROTATION) {
|
|
restoreTransObjects(t);
|
|
initTrackball(t);
|
|
}
|
|
}
|
|
else {
|
|
t->flag |= T_MMB_PRESSED;
|
|
if (t->con.mode & CON_APPLY) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (event->shift) {
|
|
initSelectConstraint(t, t->spacemtx);
|
|
}
|
|
else {
|
|
/* bit hackish... but it prevents mmb select to print the orientation from menu */
|
|
strcpy(t->spacename, "global");
|
|
initSelectConstraint(t, mati);
|
|
}
|
|
postSelectConstraint(t);
|
|
}
|
|
}
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case ESCKEY:
|
|
case RIGHTMOUSE:
|
|
t->state = TRANS_CANCEL;
|
|
break;
|
|
case LEFTMOUSE:
|
|
case PADENTER:
|
|
case RETKEY:
|
|
t->state = TRANS_CONFIRM;
|
|
break;
|
|
case GKEY:
|
|
/* only switch when... */
|
|
if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
|
|
resetTransRestrictions(t);
|
|
restoreTransObjects(t);
|
|
initTranslation(t);
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case SKEY:
|
|
/* only switch when... */
|
|
if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
|
|
resetTransRestrictions(t);
|
|
restoreTransObjects(t);
|
|
initResize(t);
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case RKEY:
|
|
/* only switch when... */
|
|
if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
|
|
|
|
resetTransRestrictions(t);
|
|
|
|
if (t->mode == TFM_ROTATION) {
|
|
restoreTransObjects(t);
|
|
initTrackball(t);
|
|
}
|
|
else {
|
|
restoreTransObjects(t);
|
|
initRotation(t);
|
|
}
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case CKEY:
|
|
if (event->alt) {
|
|
t->flag ^= T_PROP_CONNECTED;
|
|
sort_trans_data_dist(t);
|
|
calculatePropRatio(t);
|
|
t->redraw= 1;
|
|
}
|
|
else {
|
|
stopConstraint(t);
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case XKEY:
|
|
if ((t->flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'X') {
|
|
if (t->flag & T_2D_EDIT) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (t->con.mode & CON_USER) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (event->keymodifier == 0)
|
|
setUserConstraint(t, (CON_AXIS0), "along %s X");
|
|
else if (event->keymodifier == KM_SHIFT)
|
|
setUserConstraint(t, (CON_AXIS1|CON_AXIS2), "locking %s X");
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (t->flag & T_2D_EDIT) {
|
|
setConstraint(t, mati, (CON_AXIS0), "along X axis");
|
|
}
|
|
else {
|
|
if (event->keymodifier == 0)
|
|
setConstraint(t, mati, (CON_AXIS0), "along global X");
|
|
else if (event->keymodifier == KM_SHIFT)
|
|
setConstraint(t, mati, (CON_AXIS1|CON_AXIS2), "locking global X");
|
|
}
|
|
}
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case YKEY:
|
|
if ((t->flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'Y') {
|
|
if (t->flag & T_2D_EDIT) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (t->con.mode & CON_USER) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (event->keymodifier == 0)
|
|
setUserConstraint(t, (CON_AXIS1), "along %s Y");
|
|
else if (event->keymodifier == KM_SHIFT)
|
|
setUserConstraint(t, (CON_AXIS0|CON_AXIS2), "locking %s Y");
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (t->flag & T_2D_EDIT) {
|
|
setConstraint(t, mati, (CON_AXIS1), "along Y axis");
|
|
}
|
|
else {
|
|
if (event->keymodifier == 0)
|
|
setConstraint(t, mati, (CON_AXIS1), "along global Y");
|
|
else if (event->keymodifier == KM_SHIFT)
|
|
setConstraint(t, mati, (CON_AXIS0|CON_AXIS2), "locking global Y");
|
|
}
|
|
}
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case ZKEY:
|
|
if ((t->flag & T_NO_CONSTRAINT)==0) {
|
|
if (cmode == 'Z') {
|
|
if (t->con.mode & CON_USER) {
|
|
stopConstraint(t);
|
|
}
|
|
else {
|
|
if (event->keymodifier == 0)
|
|
setUserConstraint(t, (CON_AXIS2), "along %s Z");
|
|
else if ((event->keymodifier == KM_SHIFT) && ((t->flag & T_2D_EDIT)==0))
|
|
setUserConstraint(t, (CON_AXIS0|CON_AXIS1), "locking %s Z");
|
|
}
|
|
}
|
|
else if ((t->flag & T_2D_EDIT)==0) {
|
|
if (event->keymodifier == 0)
|
|
setConstraint(t, mati, (CON_AXIS2), "along global Z");
|
|
else if (event->keymodifier == KM_SHIFT)
|
|
setConstraint(t, mati, (CON_AXIS0|CON_AXIS1), "locking global Z");
|
|
}
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case OKEY:
|
|
if (t->flag & T_PROP_EDIT && event->keymodifier == KM_SHIFT) {
|
|
G.scene->prop_mode = (G.scene->prop_mode+1)%6;
|
|
calculatePropRatio(t);
|
|
t->redraw= 1;
|
|
}
|
|
break;
|
|
case PADPLUSKEY:
|
|
if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
|
|
t->propsize*= 1.1f;
|
|
calculatePropRatio(t);
|
|
}
|
|
t->redraw= 1;
|
|
break;
|
|
case PAGEUPKEY:
|
|
case WHEELDOWNMOUSE:
|
|
if (t->flag & T_AUTOIK) {
|
|
transform_autoik_update(t, 1);
|
|
}
|
|
else if(t->flag & T_PROP_EDIT) {
|
|
t->propsize*= 1.1f;
|
|
calculatePropRatio(t);
|
|
}
|
|
else view_editmove(event->type);
|
|
t->redraw= 1;
|
|
break;
|
|
case PADMINUS:
|
|
if(event->keymodifier & KM_ALT && t->flag & T_PROP_EDIT) {
|
|
t->propsize*= 0.90909090f;
|
|
calculatePropRatio(t);
|
|
}
|
|
t->redraw= 1;
|
|
break;
|
|
case PAGEDOWNKEY:
|
|
case WHEELUPMOUSE:
|
|
if (t->flag & T_AUTOIK) {
|
|
transform_autoik_update(t, -1);
|
|
}
|
|
else if (t->flag & T_PROP_EDIT) {
|
|
t->propsize*= 0.90909090f;
|
|
calculatePropRatio(t);
|
|
}
|
|
else view_editmove(event->type);
|
|
t->redraw= 1;
|
|
break;
|
|
// case NDOFMOTION:
|
|
// viewmoveNDOF(1);
|
|
// break;
|
|
}
|
|
|
|
// Numerical input events
|
|
t->redraw |= handleNumInput(&(t->num), event);
|
|
|
|
// NDof input events
|
|
switch(handleNDofInput(&(t->ndof), event))
|
|
{
|
|
case NDOF_CONFIRM:
|
|
if ((t->options & CTX_NDOF) == 0)
|
|
{
|
|
/* Confirm on normal transform only */
|
|
t->state = TRANS_CONFIRM;
|
|
}
|
|
break;
|
|
case NDOF_CANCEL:
|
|
if (t->options & CTX_NDOF)
|
|
{
|
|
/* Cancel on pure NDOF transform */
|
|
t->state = TRANS_CANCEL;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, just redraw, NDof input was cancelled */
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case NDOF_NOMOVE:
|
|
if (t->options & CTX_NDOF)
|
|
{
|
|
/* Confirm on pure NDOF transform */
|
|
t->state = TRANS_CONFIRM;
|
|
}
|
|
break;
|
|
case NDOF_REFRESH:
|
|
t->redraw = 1;
|
|
break;
|
|
|
|
}
|
|
|
|
// Snapping events
|
|
t->redraw |= handleSnapping(t, event);
|
|
|
|
//arrows_move_cursor(event->type);
|
|
}
|
|
else {
|
|
switch (event->type){
|
|
/* no redraw on release modifier keys! this makes sure you can assign the 'grid' still
|
|
after releasing modifer key */
|
|
case MIDDLEMOUSE:
|
|
if ((t->flag & T_NO_CONSTRAINT)==0) {
|
|
t->flag &= ~T_MMB_PRESSED;
|
|
postSelectConstraint(t);
|
|
t->redraw = 1;
|
|
}
|
|
break;
|
|
case LEFTMOUSE:
|
|
case RIGHTMOUSE:
|
|
if (t->options & CTX_TWEAK)
|
|
t->state = TRANS_CONFIRM;
|
|
break;
|
|
case LEFTSHIFTKEY:
|
|
case RIGHTSHIFTKEY:
|
|
/* shift is modifier for higher resolution transform */
|
|
t->flag &= ~T_SHIFT_MOD;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Per transform event, if present
|
|
if (t->handleEvent)
|
|
t->redraw |= t->handleEvent(t, event);
|
|
}
|
|
|
|
int calculateTransformCenter(bContext *C, wmEvent *event, int centerMode, float *vec)
|
|
{
|
|
TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
|
|
int success = 1;
|
|
|
|
t->state = TRANS_RUNNING;
|
|
|
|
t->options = CTX_NONE;
|
|
|
|
t->mode = TFM_DUMMY;
|
|
|
|
initTransInfo(C, t, event); // internal data, mouse, vectors
|
|
|
|
createTransData(C, t); // make TransData structs from selection
|
|
|
|
t->around = centerMode; // override userdefined mode
|
|
|
|
if (t->total == 0) {
|
|
success = 0;
|
|
}
|
|
else {
|
|
success = 1;
|
|
|
|
calculateCenter(t);
|
|
|
|
// Copy center from constraint center. Transform center can be local
|
|
VECCOPY(vec, t->con.center);
|
|
}
|
|
|
|
postTrans(t);
|
|
|
|
/* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
|
|
special_aftertrans_update(t);
|
|
|
|
MEM_freeN(t);
|
|
|
|
return success;
|
|
}
|
|
|
|
void initTransform(bContext *C, TransInfo *t, int mode, int options, wmEvent *event)
|
|
{
|
|
/* added initialize, for external calls to set stuff in TransInfo, like undo string */
|
|
|
|
t->state = TRANS_RUNNING;
|
|
|
|
t->options = options;
|
|
|
|
t->mode = mode;
|
|
|
|
initTransInfo(C, t, event); // internal data, mouse, vectors
|
|
|
|
if(t->spacetype == SPACE_VIEW3D)
|
|
{
|
|
View3D *v3d = t->view;
|
|
//calc_manipulator_stats(curarea);
|
|
Mat3CpyMat4(t->spacemtx, v3d->twmat);
|
|
Mat3Ortho(t->spacemtx);
|
|
}
|
|
else
|
|
Mat3One(t->spacemtx);
|
|
|
|
createTransData(C, t); // make TransData structs from selection
|
|
|
|
initSnapping(t); // Initialize snapping data AFTER mode flags
|
|
|
|
if (t->total == 0) {
|
|
postTrans(t);
|
|
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 */
|
|
/* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
|
|
mode = t->mode;
|
|
|
|
calculatePropRatio(t);
|
|
calculateCenter(t);
|
|
|
|
switch (mode) {
|
|
case TFM_TRANSLATION:
|
|
initTranslation(t);
|
|
break;
|
|
case TFM_ROTATION:
|
|
initRotation(t);
|
|
break;
|
|
case TFM_RESIZE:
|
|
initResize(t);
|
|
break;
|
|
case TFM_TOSPHERE:
|
|
initToSphere(t);
|
|
break;
|
|
case TFM_SHEAR:
|
|
initShear(t);
|
|
break;
|
|
case TFM_WARP:
|
|
initWarp(t);
|
|
break;
|
|
case TFM_SHRINKFATTEN:
|
|
initShrinkFatten(t);
|
|
break;
|
|
case TFM_TILT:
|
|
initTilt(t);
|
|
break;
|
|
case TFM_CURVE_SHRINKFATTEN:
|
|
initCurveShrinkFatten(t);
|
|
break;
|
|
case TFM_TRACKBALL:
|
|
initTrackball(t);
|
|
break;
|
|
case TFM_PUSHPULL:
|
|
initPushPull(t);
|
|
break;
|
|
case TFM_CREASE:
|
|
initCrease(t);
|
|
break;
|
|
case TFM_BONESIZE:
|
|
{ /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
|
|
bArmature *arm= t->poseobj->data;
|
|
if(arm->drawtype==ARM_ENVELOPE)
|
|
initBoneEnvelope(t);
|
|
else
|
|
initBoneSize(t);
|
|
}
|
|
break;
|
|
case TFM_BONE_ENVELOPE:
|
|
initBoneEnvelope(t);
|
|
break;
|
|
case TFM_BONE_ROLL:
|
|
initBoneRoll(t);
|
|
break;
|
|
case TFM_TIME_TRANSLATE:
|
|
initTimeTranslate(t);
|
|
break;
|
|
case TFM_TIME_SLIDE:
|
|
initTimeSlide(t);
|
|
break;
|
|
case TFM_TIME_SCALE:
|
|
initTimeScale(t);
|
|
break;
|
|
case TFM_TIME_EXTEND:
|
|
/* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
|
|
initTimeTranslate(t);
|
|
break;
|
|
case TFM_BAKE_TIME:
|
|
initBakeTime(t);
|
|
break;
|
|
case TFM_MIRROR:
|
|
initMirror(t);
|
|
break;
|
|
case TFM_BEVEL:
|
|
initBevel(t);
|
|
break;
|
|
case TFM_BWEIGHT:
|
|
initBevelWeight(t);
|
|
break;
|
|
case TFM_ALIGN:
|
|
initAlign(t);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void transformApply(TransInfo *t)
|
|
{
|
|
if (1) // MOUSE MOVE
|
|
{
|
|
if (t->flag & T_MMB_PRESSED)
|
|
t->con.mode |= CON_SELECT;
|
|
t->redraw = 1;
|
|
}
|
|
if (t->redraw)
|
|
{
|
|
// RESET MOUSE MOVE
|
|
|
|
selectConstraint(t);
|
|
if (t->transform) {
|
|
t->transform(t, t->mval); // calls recalcData()
|
|
}
|
|
t->redraw = 0;
|
|
}
|
|
|
|
/* If auto confirm is on, break after one pass */
|
|
if (t->options & CTX_AUTOCONFIRM)
|
|
{
|
|
t->state = TRANS_CONFIRM;
|
|
}
|
|
|
|
if (BKE_ptcache_get_continue_physics())
|
|
{
|
|
// TRANSFORM_FIX_ME
|
|
//do_screenhandlers(G.curscreen);
|
|
t->redraw = 1;
|
|
}
|
|
}
|
|
|
|
int transformEnd(TransInfo *t)
|
|
{
|
|
if (t->state != TRANS_RUNNING)
|
|
{
|
|
/* handle restoring objects */
|
|
if(t->state == TRANS_CANCEL)
|
|
restoreTransObjects(t); // calls recalcData()
|
|
|
|
/* free data */
|
|
postTrans(t);
|
|
|
|
/* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
|
|
special_aftertrans_update(t);
|
|
|
|
/* send events out for redraws */
|
|
viewRedrawPost(t);
|
|
|
|
/* Undo as last, certainly after special_trans_update! */
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
if(t->state == TRANS_CANCEL) {
|
|
if(t->undostr) BIF_undo_push(t->undostr);
|
|
}
|
|
else {
|
|
if(t->undostr) BIF_undo_push(t->undostr);
|
|
else BIF_undo_push(transform_to_undostr(t));
|
|
}
|
|
t->undostr= NULL;
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
t->context= NULL;
|
|
t->event = NULL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ************************** Manipulator init and main **************************** */
|
|
|
|
void initManipulator(int mode)
|
|
{
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
Trans.state = TRANS_RUNNING;
|
|
|
|
Trans.options = CTX_NONE;
|
|
|
|
Trans.mode = mode;
|
|
|
|
/* 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
|
|
|
|
G.moving |= G_TRANSFORM_MANIP; // signal to draw manipuls while transform
|
|
createTransData(&Trans); // make TransData structs from selection
|
|
|
|
if (Trans.total == 0)
|
|
return;
|
|
|
|
initSnapping(&Trans); // Initialize snapping data AFTER mode flags
|
|
|
|
/* 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;
|
|
#endif
|
|
}
|
|
|
|
void ManipulatorTransform()
|
|
{
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
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;
|
|
// case NDOFMOTION:
|
|
// viewmoveNDOF(1);
|
|
// break;
|
|
}
|
|
if(val) {
|
|
switch(event) {
|
|
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_AUTOIK) {
|
|
transform_autoik_update(&Trans, 1);
|
|
}
|
|
else 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_AUTOIK) {
|
|
transform_autoik_update(&Trans, -1);
|
|
}
|
|
else if (Trans.flag & T_PROP_EDIT) {
|
|
Trans.propsize*= 0.90909090f;
|
|
calculatePropRatio(&Trans);
|
|
}
|
|
else view_editmove(event);
|
|
Trans.redraw= 1;
|
|
break;
|
|
}
|
|
|
|
// Numerical input events
|
|
Trans.redraw |= handleNumInput(&(Trans.num), event);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(Trans.state == TRANS_CANCEL) {
|
|
restoreTransObjects(&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);
|
|
|
|
if(Trans.state != TRANS_CANCEL) {
|
|
BIF_undo_push(transform_to_undostr(&Trans));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* ************************** TRANSFORM LOCKS **************************** */
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ******************* TRANSFORM LIMITS ********************** */
|
|
|
|
static void constraintTransLim(TransInfo *t, TransData *td)
|
|
{
|
|
if (td->con) {
|
|
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
|
|
bConstraintOb cob;
|
|
bConstraint *con;
|
|
|
|
/* Make a temporary bConstraintOb for using these limit constraints
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
* - current space should be local
|
|
*/
|
|
memset(&cob, 0, sizeof(bConstraintOb));
|
|
Mat4One(cob.matrix);
|
|
if (td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
cob.matrix[3][0]= tdi->locx[0];
|
|
cob.matrix[3][1]= tdi->locy[0];
|
|
cob.matrix[3][2]= tdi->locz[0];
|
|
}
|
|
else {
|
|
VECCOPY(cob.matrix[3], td->loc);
|
|
}
|
|
|
|
/* Evaluate valid constraints */
|
|
for (con= td->con; con; con= con->next) {
|
|
float tmat[4][4];
|
|
|
|
/* only consider constraint if enabled */
|
|
if (con->flag & CONSTRAINT_DISABLE) continue;
|
|
if (con->enforce == 0.0f) continue;
|
|
|
|
/* only use it if it's tagged for this purpose (and the right type) */
|
|
if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
|
|
bLocLimitConstraint *data= con->data;
|
|
|
|
if ((data->flag2 & LIMIT_TRANSFORM)==0)
|
|
continue;
|
|
|
|
/* do space conversions */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->mtx, tmat);
|
|
}
|
|
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
|
|
/* skip... incompatable spacetype */
|
|
continue;
|
|
}
|
|
|
|
/* do constraint */
|
|
cti->evaluate_constraint(con, &cob, NULL);
|
|
|
|
/* convert spaces again */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->smtx, tmat);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* copy results from cob->matrix */
|
|
if (td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
tdi->locx[0]= cob.matrix[3][0];
|
|
tdi->locy[0]= cob.matrix[3][1];
|
|
tdi->locz[0]= cob.matrix[3][2];
|
|
}
|
|
else {
|
|
VECCOPY(td->loc, cob.matrix[3]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void constraintRotLim(TransInfo *t, TransData *td)
|
|
{
|
|
if (td->con) {
|
|
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
|
|
bConstraintOb cob;
|
|
bConstraint *con;
|
|
|
|
/* Make a temporary bConstraintOb for using these limit constraints
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
* - current space should be local
|
|
*/
|
|
memset(&cob, 0, sizeof(bConstraintOb));
|
|
if (td->flag & TD_USEQUAT) {
|
|
/* quats */
|
|
if (td->ext)
|
|
QuatToMat4(td->ext->quat, cob.matrix);
|
|
else
|
|
return;
|
|
}
|
|
else if (td->tdi) {
|
|
/* ipo-keys eulers */
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float eul[3];
|
|
|
|
eul[0]= tdi->rotx[0];
|
|
eul[1]= tdi->roty[0];
|
|
eul[2]= tdi->rotz[0];
|
|
|
|
EulToMat4(eul, cob.matrix);
|
|
}
|
|
else {
|
|
/* eulers */
|
|
if (td->ext)
|
|
EulToMat4(td->ext->rot, cob.matrix);
|
|
else
|
|
return;
|
|
}
|
|
|
|
/* Evaluate valid constraints */
|
|
for (con= td->con; con; con= con->next) {
|
|
/* only consider constraint if enabled */
|
|
if (con->flag & CONSTRAINT_DISABLE) continue;
|
|
if (con->enforce == 0.0f) continue;
|
|
|
|
/* we're only interested in Limit-Rotation constraints */
|
|
if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
|
|
bRotLimitConstraint *data= con->data;
|
|
float tmat[4][4];
|
|
|
|
/* only use it if it's tagged for this purpose */
|
|
if ((data->flag2 & LIMIT_TRANSFORM)==0)
|
|
continue;
|
|
|
|
/* do space conversions */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->mtx, tmat);
|
|
}
|
|
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
|
|
/* skip... incompatable spacetype */
|
|
continue;
|
|
}
|
|
|
|
/* do constraint */
|
|
cti->evaluate_constraint(con, &cob, NULL);
|
|
|
|
/* convert spaces again */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->smtx, tmat);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* copy results from cob->matrix */
|
|
if (td->flag & TD_USEQUAT) {
|
|
/* quats */
|
|
Mat4ToQuat(cob.matrix, td->ext->quat);
|
|
}
|
|
else if (td->tdi) {
|
|
/* ipo-keys eulers */
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float eul[3];
|
|
|
|
Mat4ToEul(cob.matrix, eul);
|
|
|
|
tdi->rotx[0]= eul[0];
|
|
tdi->roty[0]= eul[1];
|
|
tdi->rotz[0]= eul[2];
|
|
}
|
|
else {
|
|
/* eulers */
|
|
Mat4ToEul(cob.matrix, td->ext->rot);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void constraintSizeLim(TransInfo *t, TransData *td)
|
|
{
|
|
if (td->con && td->ext) {
|
|
bConstraintTypeInfo *cti= get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
|
|
bConstraintOb cob;
|
|
bConstraint *con;
|
|
|
|
/* Make a temporary bConstraintOb for using these limit constraints
|
|
* - they only care that cob->matrix is correctly set ;-)
|
|
* - current space should be local
|
|
*/
|
|
memset(&cob, 0, sizeof(bConstraintOb));
|
|
if (td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float size[3];
|
|
|
|
size[0]= tdi->sizex[0];
|
|
size[1]= tdi->sizey[0];
|
|
size[2]= tdi->sizez[0];
|
|
SizeToMat4(size, cob.matrix);
|
|
}
|
|
else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
|
|
/* scale val and reset size */
|
|
return; // TODO: fix this case
|
|
}
|
|
else {
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
if (td->flag & TD_SINGLESIZE)
|
|
return;
|
|
|
|
SizeToMat4(td->ext->size, cob.matrix);
|
|
}
|
|
|
|
/* Evaluate valid constraints */
|
|
for (con= td->con; con; con= con->next) {
|
|
/* only consider constraint if enabled */
|
|
if (con->flag & CONSTRAINT_DISABLE) continue;
|
|
if (con->enforce == 0.0f) continue;
|
|
|
|
/* we're only interested in Limit-Scale constraints */
|
|
if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
|
|
bSizeLimitConstraint *data= con->data;
|
|
float tmat[4][4];
|
|
|
|
/* only use it if it's tagged for this purpose */
|
|
if ((data->flag2 & LIMIT_TRANSFORM)==0)
|
|
continue;
|
|
|
|
/* do space conversions */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->mtx, tmat);
|
|
}
|
|
else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
|
|
/* skip... incompatable spacetype */
|
|
continue;
|
|
}
|
|
|
|
/* do constraint */
|
|
cti->evaluate_constraint(con, &cob, NULL);
|
|
|
|
/* convert spaces again */
|
|
if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
|
|
/* just multiply by td->mtx (this should be ok) */
|
|
Mat4CpyMat4(tmat, cob.matrix);
|
|
Mat4MulMat34(cob.matrix, td->smtx, tmat);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* copy results from cob->matrix */
|
|
if (td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float size[3];
|
|
|
|
Mat4ToSize(cob.matrix, size);
|
|
|
|
tdi->sizex[0]= size[0];
|
|
tdi->sizey[0]= size[1];
|
|
tdi->sizez[0]= size[2];
|
|
}
|
|
else if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
|
|
/* scale val and reset size */
|
|
return; // TODO: fix this case
|
|
}
|
|
else {
|
|
/* Reset val if SINGLESIZE but using a constraint */
|
|
if (td->flag & TD_SINGLESIZE)
|
|
return;
|
|
|
|
Mat4ToSize(cob.matrix, td->ext->size);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ************************** WARP *************************** */
|
|
|
|
void initWarp(TransInfo *t)
|
|
{
|
|
float max[3], min[3];
|
|
int i;
|
|
|
|
t->mode = TFM_WARP;
|
|
t->transform = Warp;
|
|
t->handleEvent = handleEventWarp;
|
|
|
|
t->idx_max = 0;
|
|
t->num.idx_max = 0;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 5.0f;
|
|
t->snap[2] = 1.0f;
|
|
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
|
|
/* warp is done fully in view space */
|
|
calculateCenterCursor(t);
|
|
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;
|
|
|
|
if (max[0] == min[0]) max[0] += 0.1; /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
|
|
t->val= (max[0]-min[0])/2.0f; /* t->val is X dimension projected boundbox */
|
|
}
|
|
|
|
int handleEventWarp(TransInfo *t, wmEvent *event)
|
|
{
|
|
int status = 0;
|
|
|
|
if (event->type == MIDDLEMOUSE && event->val)
|
|
{
|
|
// Use customData pointer to signal warp direction
|
|
if (t->customData == 0)
|
|
t->customData = (void*)1;
|
|
else
|
|
t->customData = 0;
|
|
|
|
status = 1;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
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(t->scene, t->view);
|
|
/*
|
|
* 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 */
|
|
circumfac= 360.0f * InputHorizontalRatio(t, mval);
|
|
|
|
if (t->customData) /* non-null value indicates reversed input */
|
|
{
|
|
circumfac *= -1;
|
|
}
|
|
|
|
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;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
/* translate point to center, 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];
|
|
|
|
/* t->val is X dimension projected boundbox */
|
|
phi0= (circumfac*dist/t->val);
|
|
|
|
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);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline(t, gcursor);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** SHEAR *************************** */
|
|
|
|
void initShear(TransInfo *t)
|
|
{
|
|
t->mode = TFM_SHEAR;
|
|
t->transform = Shear;
|
|
t->handleEvent = handleEventShear;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
|
|
int handleEventShear(TransInfo *t, wmEvent *event)
|
|
{
|
|
int status = 0;
|
|
|
|
if (event->type == MIDDLEMOUSE && event->val)
|
|
{
|
|
// Use customData pointer to signal Shear direction
|
|
if (t->customData == 0)
|
|
t->customData = (void*)1;
|
|
else
|
|
t->customData = 0;
|
|
|
|
status = 1;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
// Custom data signals shear direction
|
|
if (t->customData == 0)
|
|
value = 0.05f * InputHorizontalAbsolute(t, mval);
|
|
else
|
|
value = 0.05f * InputVerticalAbsolute(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);
|
|
|
|
// Custom data signals shear direction
|
|
if (t->customData == 0)
|
|
smat[1][0] = value;
|
|
else
|
|
smat[0][1] = value;
|
|
|
|
Mat3MulMat3(tmat, smat, persmat);
|
|
Mat3MulMat3(totmat, persinv, tmat);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
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);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** RESIZE *************************** */
|
|
|
|
void initResize(TransInfo *t)
|
|
{
|
|
t->mode = TFM_RESIZE;
|
|
t->transform = Resize;
|
|
|
|
t->flag |= T_NULL_ONE;
|
|
t->num.flag |= NUM_NULL_ONE;
|
|
t->num.flag |= NUM_AFFECT_ALL;
|
|
if (!G.obedit) {
|
|
t->flag |= T_NO_ZERO;
|
|
t->num.flag |= NUM_NO_ZERO;
|
|
}
|
|
|
|
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->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
|
|
}
|
|
|
|
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]= Normalize(vec);
|
|
VecCopyf(vec, mat[1]);
|
|
size[1]= Normalize(vec);
|
|
VecCopyf(vec, mat[2]);
|
|
size[2]= Normalize(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(t->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|T_POSE)) {
|
|
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 resize 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;
|
|
}
|
|
}
|
|
|
|
constraintSizeLim(t, td);
|
|
}
|
|
|
|
/* 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|T_POSE)) {
|
|
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);
|
|
|
|
constraintTransLim(t, td);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
applySnapping(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;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
ElementResize(t, td, mat);
|
|
}
|
|
|
|
/* evil hack - redo resize if cliping needed */
|
|
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);
|
|
|
|
ED_area_headerprint(t->sa, 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;
|
|
|
|
t->mode = TFM_TOSPHERE;
|
|
t->transform = ToSphere;
|
|
|
|
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->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
|
|
// Calculate average radius
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
t->val += VecLenf(t->center, td->iloc);
|
|
}
|
|
|
|
t->val /= (float)t->total;
|
|
}
|
|
|
|
int ToSphere(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3];
|
|
float ratio, radius;
|
|
int i;
|
|
char str[64];
|
|
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;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
VecSubf(vec, td->iloc, t->center);
|
|
|
|
radius = Normalize(vec);
|
|
|
|
tratio = ratio * td->factor;
|
|
|
|
VecMulf(vec, radius * (1.0f - tratio) + t->val * tratio);
|
|
|
|
VecAddf(td->loc, t->center, vec);
|
|
}
|
|
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** ROTATION *************************** */
|
|
|
|
|
|
void initRotation(TransInfo *t)
|
|
{
|
|
t->mode = TFM_ROTATION;
|
|
t->transform = Rotation;
|
|
|
|
t->ndof.axis = 16;
|
|
/* Scale down and flip input for rotation */
|
|
t->ndof.factor[0] = -0.2f;
|
|
|
|
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;
|
|
|
|
if (t->flag & T_2D_EDIT)
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
|
|
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around) {
|
|
float vec[3], totmat[3][3], smat[3][3];
|
|
float eul[3], fmat[3][3], quat[4];
|
|
float *center = t->center;
|
|
|
|
/* local constraint shouldn't alter center */
|
|
if (around == V3D_LOCAL) {
|
|
if (t->flag & (T_OBJECT|T_POSE)) {
|
|
center = td->center;
|
|
}
|
|
else {
|
|
/* !TODO! Make this if not rely on G */
|
|
if(around==V3D_LOCAL && (G.scene->selectmode & SCE_SELECT_FACE)) {
|
|
center = td->center;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (t->flag & T_POINTS) {
|
|
Mat3MulMat3(totmat, mat, td->mtx);
|
|
Mat3MulMat3(smat, td->smtx, totmat);
|
|
|
|
VecSubf(vec, td->iloc, center);
|
|
Mat3MulVecfl(smat, vec);
|
|
|
|
VecAddf(td->loc, vec, center);
|
|
|
|
VecSubf(vec,td->loc,td->iloc);
|
|
protectedTransBits(td->protectflag, vec);
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
|
|
if(td->flag & TD_USEQUAT) {
|
|
Mat3MulSerie(fmat, td->mtx, mat, td->smtx, 0, 0, 0, 0, 0);
|
|
Mat3ToQuat(fmat, quat); // Actual transform
|
|
|
|
if(td->ext->quat){
|
|
QuatMul(td->ext->quat, quat, td->ext->iquat);
|
|
|
|
/* is there a reason not to have this here? -jahka */
|
|
protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* HACK WARNING
|
|
*
|
|
* This is some VERY ugly special case to deal with pose mode.
|
|
*
|
|
* The problem is that mtx and smtx include each bone orientation.
|
|
*
|
|
* That is needed to rotate each bone properly, HOWEVER, to calculate
|
|
* the translation component, we only need the actual armature object's
|
|
* matrix (and inverse). That is not all though. Once the proper translation
|
|
* has been computed, it has to be converted back into the bone's space.
|
|
*/
|
|
else if (t->flag & T_POSE) {
|
|
float pmtx[3][3], imtx[3][3];
|
|
|
|
// Extract and invert armature object matrix
|
|
Mat3CpyMat4(pmtx, t->poseobj->obmat);
|
|
Mat3Inv(imtx, pmtx);
|
|
|
|
if ((td->flag & TD_NO_LOC) == 0)
|
|
{
|
|
VecSubf(vec, td->center, center);
|
|
|
|
Mat3MulVecfl(pmtx, vec); // To Global space
|
|
Mat3MulVecfl(mat, vec); // Applying rotation
|
|
Mat3MulVecfl(imtx, vec); // To Local space
|
|
|
|
VecAddf(vec, vec, center);
|
|
/* vec now is the location where the object has to be */
|
|
|
|
VecSubf(vec, vec, td->center); // Translation needed from the initial location
|
|
|
|
Mat3MulVecfl(pmtx, vec); // To Global space
|
|
Mat3MulVecfl(td->smtx, vec);// To Pose space
|
|
|
|
protectedTransBits(td->protectflag, vec);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
|
|
constraintTransLim(t, td);
|
|
}
|
|
|
|
/* rotation */
|
|
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
|
|
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);
|
|
|
|
constraintRotLim(t, td);
|
|
}
|
|
}
|
|
else {
|
|
|
|
if ((td->flag & TD_NO_LOC) == 0)
|
|
{
|
|
/* translation */
|
|
VecSubf(vec, td->center, center);
|
|
Mat3MulVecfl(mat, vec);
|
|
VecAddf(vec, vec, 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);
|
|
}
|
|
|
|
|
|
constraintTransLim(t, td);
|
|
|
|
/* rotation */
|
|
if ((t->flag & T_V3D_ALIGN)==0) { // align mode doesn't rotate objects itself
|
|
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 {
|
|
float obmat[3][3];
|
|
|
|
/* are there ipo keys? */
|
|
if(td->tdi) {
|
|
TransDataIpokey *tdi= td->tdi;
|
|
float current_rot[3];
|
|
float rot[3];
|
|
|
|
/* current IPO value for compatible euler */
|
|
current_rot[0] = (tdi->rotx) ? tdi->rotx[0] : 0.0f;
|
|
current_rot[1] = (tdi->roty) ? tdi->roty[0] : 0.0f;
|
|
current_rot[2] = (tdi->rotz) ? tdi->rotz[0] : 0.0f;
|
|
VecMulf(current_rot, (float)(M_PI_2 / 9.0));
|
|
|
|
/* 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, current_rot);
|
|
|
|
/* 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->rot);
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
|
|
constraintRotLim(t, td);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void applyRotation(TransInfo *t, float angle, float axis[3])
|
|
{
|
|
TransData *td = t->data;
|
|
float mat[3][3];
|
|
int i;
|
|
|
|
VecRotToMat3(axis, angle, mat);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
if (t->con.applyRot) {
|
|
t->con.applyRot(t, td, axis, NULL);
|
|
VecRotToMat3(axis, angle * td->factor, mat);
|
|
}
|
|
else if (t->flag & T_PROP_EDIT) {
|
|
VecRotToMat3(axis, angle * td->factor, mat);
|
|
}
|
|
|
|
ElementRotation(t, td, mat, t->around);
|
|
}
|
|
}
|
|
|
|
int Rotation(TransInfo *t, short mval[2])
|
|
{
|
|
char str[64];
|
|
|
|
float final;
|
|
|
|
float axis[3];
|
|
float mat[3][3];
|
|
|
|
VECCOPY(axis, t->viewinv[2]);
|
|
VecMulf(axis, -1.0f);
|
|
Normalize(axis);
|
|
|
|
t->fac += InputDeltaAngle(t, mval);
|
|
|
|
final = t->fac;
|
|
|
|
applyNDofInput(&t->ndof, &final);
|
|
|
|
snapGrid(t, &final);
|
|
|
|
if (t->con.applyRot) {
|
|
t->con.applyRot(t, NULL, axis, &final);
|
|
}
|
|
|
|
applySnapping(t, &final);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
applyNumInput(&t->num, &final);
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Rot: %s %s %s", &c[0], t->con.text, t->proptext);
|
|
|
|
/* Clamp between -180 and 180 */
|
|
while (final >= 180.0)
|
|
final -= 360.0;
|
|
|
|
while (final <= -180.0)
|
|
final += 360.0;
|
|
|
|
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, mat);
|
|
|
|
t->val = final; // used in manipulator
|
|
Mat3CpyMat3(t->mat, mat); // used in manipulator
|
|
|
|
applyRotation(t, final, axis);
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* ************************** TRACKBALL *************************** */
|
|
|
|
void initTrackball(TransInfo *t)
|
|
{
|
|
t->mode = TFM_TRACKBALL;
|
|
t->transform = Trackball;
|
|
|
|
t->ndof.axis = 40;
|
|
/* Scale down input for rotation */
|
|
t->ndof.factor[0] = 0.2f;
|
|
t->ndof.factor[1] = 0.2f;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
|
|
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 (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
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, t->around);
|
|
}
|
|
}
|
|
|
|
int Trackball(TransInfo *t, short mval[2])
|
|
{
|
|
char str[128];
|
|
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]);
|
|
Normalize(axis1);
|
|
Normalize(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] );
|
|
|
|
applyNDofInput(&t->ndof, phi);
|
|
|
|
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);
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
if(phi[0] != 0.0) phi[0]/= 5.0f;
|
|
if(phi[1] != 0.0) phi[1]/= 5.0f;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** TRANSLATION *************************** */
|
|
|
|
void initTranslation(TransInfo *t)
|
|
{
|
|
t->mode = TFM_TRANSLATION;
|
|
t->transform = Translation;
|
|
|
|
t->idx_max = (t->flag & T_2D_EDIT)? 1: 2;
|
|
t->num.flag = 0;
|
|
t->num.idx_max = t->idx_max;
|
|
|
|
t->ndof.axis = 7;
|
|
|
|
if(t->spacetype == SPACE_VIEW3D) {
|
|
View3D *v3d = t->view;
|
|
|
|
/* 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(v3d, vec[0], vec[1], vec[2]);
|
|
}
|
|
else {
|
|
initgrabz(v3d, t->center[0], t->center[1], t->center[2]);
|
|
}
|
|
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = v3d->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];
|
|
char autoik[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->flag & T_AUTOIK) {
|
|
short chainlen= G.scene->toolsettings->autoik_chainlen;
|
|
|
|
if(chainlen)
|
|
sprintf(autoik, "AutoIK-Len: %d", chainlen);
|
|
else
|
|
strcpy(autoik, "");
|
|
}
|
|
else
|
|
strcpy(autoik, "");
|
|
|
|
if (t->con.mode & CON_APPLY) {
|
|
switch(t->num.idx_max) {
|
|
case 0:
|
|
sprintf(str, "D: %s (%s)%s %s %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
|
|
break;
|
|
case 1:
|
|
sprintf(str, "D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[20], distvec, t->con.text, t->proptext, &autoik[0]);
|
|
break;
|
|
case 2:
|
|
sprintf(str, "D: %s D: %s D: %s (%s)%s %s %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
|
|
}
|
|
}
|
|
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 %s", &tvec[0], &tvec[20], &tvec[40], distvec, t->con.text, t->proptext, &autoik[0]);
|
|
}
|
|
}
|
|
|
|
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 (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
/* handle snapping rotation before doing the translation */
|
|
if (usingSnappingNormal(t))
|
|
{
|
|
if (validSnappingNormal(t))
|
|
{
|
|
float *original_normal = td->axismtx[2];
|
|
float axis[3];
|
|
float quat[4];
|
|
float mat[3][3];
|
|
float angle;
|
|
|
|
Crossf(axis, original_normal, t->tsnap.snapNormal);
|
|
angle = saacos(Inpf(original_normal, t->tsnap.snapNormal));
|
|
|
|
AxisAngleToQuat(quat, axis, angle);
|
|
|
|
QuatToMat3(quat, mat);
|
|
|
|
ElementRotation(t, td, mat, V3D_LOCAL);
|
|
}
|
|
else
|
|
{
|
|
float mat[3][3];
|
|
|
|
Mat3One(mat);
|
|
|
|
ElementRotation(t, td, mat, V3D_LOCAL);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
constraintTransLim(t, td);
|
|
}
|
|
}
|
|
|
|
/* uses t->vec to store actual translation in */
|
|
int Translation(TransInfo *t, short mval[2])
|
|
{
|
|
float tvec[3];
|
|
char str[250];
|
|
|
|
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};
|
|
applySnapping(t, t->vec);
|
|
t->con.applyVec(t, NULL, t->vec, tvec, pvec);
|
|
VECCOPY(t->vec, tvec);
|
|
headerTranslation(t, pvec, str);
|
|
}
|
|
else {
|
|
applyNDofInput(&t->ndof, t->vec);
|
|
snapGrid(t, t->vec);
|
|
applyNumInput(&t->num, t->vec);
|
|
applySnapping(t, 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);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
drawSnapping(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** SHRINK/FATTEN *************************** */
|
|
|
|
void initShrinkFatten(TransInfo *t)
|
|
{
|
|
// If not in mesh edit mode, fallback to Resize
|
|
if (G.obedit==NULL || G.obedit->type != OB_MESH) {
|
|
initResize(t);
|
|
}
|
|
else {
|
|
t->mode = TFM_SHRINKFATTEN;
|
|
t->transform = ShrinkFatten;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int ShrinkFatten(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3];
|
|
float distance;
|
|
int i;
|
|
char str[64];
|
|
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;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
VECCOPY(vec, td->axismtx[2]);
|
|
VecMulf(vec, distance);
|
|
VecMulf(vec, td->factor);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** TILT *************************** */
|
|
|
|
void initTilt(TransInfo *t)
|
|
{
|
|
t->mode = TFM_TILT;
|
|
t->transform = Tilt;
|
|
|
|
t->ndof.axis = 16;
|
|
/* Scale down and flip input for rotation */
|
|
t->ndof.factor[0] = -0.2f;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
|
|
|
|
|
|
int Tilt(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
int i;
|
|
char str[50];
|
|
|
|
float final;
|
|
|
|
t->fac += InputDeltaAngle(t, mval);
|
|
|
|
final = t->fac;
|
|
|
|
applyNDofInput(&t->ndof, &final);
|
|
|
|
snapGrid(t, &final);
|
|
|
|
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->flag & TD_SKIP)
|
|
continue;
|
|
|
|
if (td->val) {
|
|
*td->val = td->ival + final * td->factor;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, 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->flag & TD_SKIP)
|
|
continue;
|
|
|
|
if(td->val) {
|
|
//*td->val= ratio;
|
|
*td->val= td->ival*ratio;
|
|
if (*td->val <= 0.0f) *td->val = 0.0001f;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void initCurveShrinkFatten(TransInfo *t)
|
|
{
|
|
t->mode = TFM_CURVE_SHRINKFATTEN;
|
|
t->transform = CurveShrinkFatten;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
|
|
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->mode = TFM_PUSHPULL;
|
|
t->transform = PushPull;
|
|
|
|
t->ndof.axis = 4;
|
|
/* Flip direction */
|
|
t->ndof.factor[0] = -1.0f;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
int PushPull(TransInfo *t, short mval[2])
|
|
{
|
|
float vec[3], axis[3];
|
|
float distance;
|
|
int i;
|
|
char str[128];
|
|
TransData *td = t->data;
|
|
|
|
distance = InputVerticalAbsolute(t, mval);
|
|
|
|
applyNDofInput(&t->ndof, &distance);
|
|
|
|
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, NULL);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
VecSubf(vec, t->center, td->center);
|
|
if (t->con.applyRot && t->con.mode & CON_APPLY) {
|
|
t->con.applyRot(t, td, axis, NULL);
|
|
if (isLockConstraint(t)) {
|
|
float dvec[3];
|
|
Projf(dvec, vec, axis);
|
|
VecSubf(vec, vec, dvec);
|
|
}
|
|
else {
|
|
Projf(vec, vec, axis);
|
|
}
|
|
}
|
|
Normalize(vec);
|
|
VecMulf(vec, distance);
|
|
VecMulf(vec, td->factor);
|
|
|
|
VecAddf(td->loc, td->iloc, vec);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** BEVEL **************************** */
|
|
|
|
void initBevel(TransInfo *t)
|
|
{
|
|
t->mode = TFM_BEVEL;
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
t->num.flag |= NUM_NO_NEGATIVE;
|
|
t->transform = Bevel;
|
|
t->handleEvent = handleEventBevel;
|
|
|
|
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;
|
|
|
|
/* DON'T KNOW WHY THIS IS NEEDED */
|
|
if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
|
|
/* save the initial mouse co */
|
|
G.editBMesh->imval[0] = t->imval[0];
|
|
G.editBMesh->imval[1] = t->imval[1];
|
|
}
|
|
else {
|
|
/* restore the mouse co from a previous call to initTransform() */
|
|
t->imval[0] = G.editBMesh->imval[0];
|
|
t->imval[1] = G.editBMesh->imval[1];
|
|
}
|
|
}
|
|
|
|
int handleEventBevel(TransInfo *t, wmEvent *event)
|
|
{
|
|
if (event->val) {
|
|
if(!G.editBMesh) return 0;
|
|
|
|
switch (event->type) {
|
|
case MIDDLEMOUSE:
|
|
G.editBMesh->options ^= BME_BEVEL_VERT;
|
|
t->state = TRANS_CANCEL;
|
|
return 1;
|
|
//case PADPLUSKEY:
|
|
// G.editBMesh->options ^= BME_BEVEL_RES;
|
|
// G.editBMesh->res += 1;
|
|
// if (G.editBMesh->res > 4) {
|
|
// G.editBMesh->res = 4;
|
|
// }
|
|
// t->state = TRANS_CANCEL;
|
|
// return 1;
|
|
//case PADMINUS:
|
|
// G.editBMesh->options ^= BME_BEVEL_RES;
|
|
// G.editBMesh->res -= 1;
|
|
// if (G.editBMesh->res < 0) {
|
|
// G.editBMesh->res = 0;
|
|
// }
|
|
// t->state = TRANS_CANCEL;
|
|
// return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Bevel(TransInfo *t, short mval[2])
|
|
{
|
|
float distance,d;
|
|
int i;
|
|
char str[128];
|
|
char *mode;
|
|
TransData *td = t->data;
|
|
|
|
mode = (G.editBMesh->options & BME_BEVEL_VERT) ? "verts only" : "normal";
|
|
distance = InputHorizontalAbsolute(t, mval)/4; /* 4 just seemed a nice value to me, nothing special */
|
|
|
|
distance = fabs(distance);
|
|
|
|
snapGrid(t, &distance);
|
|
|
|
applyNumInput(&t->num, &distance);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Bevel - Dist: %s, Mode: %s (MMB to toggle))", c, mode);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
sprintf(str, "Bevel - Dist: %.4f, Mode: %s (MMB to toggle))", distance, mode);
|
|
}
|
|
|
|
if (distance < 0) distance = -distance;
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
|
|
d = td->axismtx[1][0];
|
|
}
|
|
else {
|
|
d = distance;
|
|
}
|
|
VECADDFAC(td->loc,td->center,td->axismtx[0],(*td->val)*d);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** BEVEL WEIGHT *************************** */
|
|
|
|
void initBevelWeight(TransInfo *t)
|
|
{
|
|
t->mode = TFM_BWEIGHT;
|
|
t->transform = BevelWeight;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
|
|
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 BevelWeight(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float weight;
|
|
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]);
|
|
weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
|
|
dx= (float)(t->center2d[0] - mval[0]);
|
|
dy= (float)(t->center2d[1] - mval[1]);
|
|
weight+= 0.1f*(float)(sqrt( dx*dx + dy*dy)/t->fac -weight);
|
|
|
|
}
|
|
else {
|
|
float dx= (float)(t->center2d[0] - mval[0]);
|
|
float dy= (float)(t->center2d[1] - mval[1]);
|
|
weight = (float)sqrt( dx*dx + dy*dy)/t->fac;
|
|
}
|
|
|
|
weight -= 1.0f;
|
|
if (weight > 1.0f) weight = 1.0f;
|
|
|
|
snapGrid(t, &weight);
|
|
|
|
applyNumInput(&t->num, &weight);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
if (weight >= 0.0f)
|
|
sprintf(str, "Bevel Weight: +%s %s", c, t->proptext);
|
|
else
|
|
sprintf(str, "Bevel Weight: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
if (weight >= 0.0f)
|
|
sprintf(str, "Bevel Weight: +%.3f %s", weight, t->proptext);
|
|
else
|
|
sprintf(str, "Bevel Weight: %.3f %s", weight, t->proptext);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->val) {
|
|
*td->val = td->ival + weight * td->factor;
|
|
if (*td->val < 0.0f) *td->val = 0.0f;
|
|
if (*td->val > 1.0f) *td->val = 1.0f;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** CREASE *************************** */
|
|
|
|
void initCrease(TransInfo *t)
|
|
{
|
|
t->mode = TFM_CREASE;
|
|
t->transform = Crease;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
|
|
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->flag & TD_SKIP)
|
|
continue;
|
|
|
|
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);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ******************** EditBone (B-bone) width scaling *************** */
|
|
|
|
void initBoneSize(TransInfo *t)
|
|
{
|
|
t->mode = TFM_BONESIZE;
|
|
t->transform = BoneSize;
|
|
|
|
t->idx_max = 2;
|
|
t->num.idx_max = 2;
|
|
t->num.flag |= NUM_NULL_ONE;
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = 0.1f;
|
|
t->snap[2] = t->snap[1] * 0.1f;
|
|
|
|
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
|
|
}
|
|
|
|
static void headerBoneSize(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]);
|
|
}
|
|
|
|
/* hmm... perhaps the y-axis values don't need to be shown? */
|
|
if (t->con.mode & CON_APPLY) {
|
|
if (t->num.idx_max == 0)
|
|
sprintf(str, "ScaleB: %s%s %s", &tvec[0], t->con.text, t->proptext);
|
|
else
|
|
sprintf(str, "ScaleB: %s : %s : %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
|
|
}
|
|
else {
|
|
sprintf(str, "ScaleB X: %s Y: %s Z: %s%s %s", &tvec[0], &tvec[20], &tvec[40], t->con.text, t->proptext);
|
|
}
|
|
}
|
|
|
|
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[60];
|
|
|
|
/* 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
|
|
|
|
headerBoneSize(t, size, str);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
ElementBoneSize(t, td, mat);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* ******************** EditBone envelope *************** */
|
|
|
|
void initBoneEnvelope(TransInfo *t)
|
|
{
|
|
t->mode = TFM_BONE_ENVELOPE;
|
|
t->transform = BoneEnvelope;
|
|
|
|
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->flag |= T_NO_CONSTRAINT;
|
|
|
|
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 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->flag & TD_SKIP)
|
|
continue;
|
|
|
|
if (td->val) {
|
|
/* if the old/original value was 0.0f, then just use ratio */
|
|
if (td->ival)
|
|
*td->val= td->ival*ratio;
|
|
else
|
|
*td->val= ratio;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* ******************** EditBone roll *************** */
|
|
|
|
void initBoneRoll(TransInfo *t)
|
|
{
|
|
t->mode = TFM_BONE_ROLL;
|
|
t->transform = BoneRoll;
|
|
|
|
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.0f;
|
|
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
}
|
|
|
|
int BoneRoll(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
int i;
|
|
char str[50];
|
|
|
|
float final;
|
|
|
|
t->fac += InputDeltaAngle(t, mval);
|
|
|
|
final = t->fac;
|
|
|
|
snapGrid(t, &final);
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
applyNumInput(&t->num, &final);
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
sprintf(str, "Roll: %s", &c[0]);
|
|
|
|
final *= (float)(M_PI / 180.0);
|
|
}
|
|
else {
|
|
sprintf(str, "Roll: %.2f", 180.0*final/M_PI);
|
|
}
|
|
|
|
/* set roll values */
|
|
for (i = 0; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
*(td->val) = td->ival - final;
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
if(!(t->flag & T_USES_MANIPULATOR)) helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** BAKE TIME ******************* */
|
|
|
|
void initBakeTime(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 = BakeTime;
|
|
t->fac = 0.1f;
|
|
}
|
|
|
|
int BakeTime(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float time;
|
|
int i;
|
|
char str[50];
|
|
|
|
|
|
if(t->flag & T_SHIFT_MOD) {
|
|
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
|
|
time= (float)(t->center2d[0] - t->shiftmval[0])*t->fac;
|
|
time+= 0.1f*((float)(t->center2d[0]*t->fac - mval[0]) -time);
|
|
}
|
|
else {
|
|
time = (float)(t->center2d[0] - mval[0])*t->fac;
|
|
}
|
|
|
|
snapGrid(t, &time);
|
|
|
|
applyNumInput(&t->num, &time);
|
|
|
|
/* header print for NumInput */
|
|
if (hasNumInput(&t->num)) {
|
|
char c[20];
|
|
|
|
outputNumInput(&(t->num), c);
|
|
|
|
if (time >= 0.0f)
|
|
sprintf(str, "Time: +%s %s", c, t->proptext);
|
|
else
|
|
sprintf(str, "Time: %s %s", c, t->proptext);
|
|
}
|
|
else {
|
|
/* default header print */
|
|
if (time >= 0.0f)
|
|
sprintf(str, "Time: +%.3f %s", time, t->proptext);
|
|
else
|
|
sprintf(str, "Time: %.3f %s", time, t->proptext);
|
|
}
|
|
|
|
for(i = 0 ; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
if (td->val) {
|
|
*td->val = td->ival + time * td->factor;
|
|
if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
|
|
if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
|
|
}
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
helpline (t, t->center);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** MIRROR *************************** */
|
|
|
|
void initMirror(TransInfo *t)
|
|
{
|
|
t->flag |= T_NULL_ONE;
|
|
if (!G.obedit) {
|
|
t->flag |= T_NO_ZERO;
|
|
}
|
|
|
|
t->transform = Mirror;
|
|
}
|
|
|
|
int Mirror(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td;
|
|
float size[3], mat[3][3];
|
|
int i;
|
|
char str[200];
|
|
|
|
/*
|
|
* OPTIMISATION:
|
|
* This still recalcs transformation on mouse move
|
|
* while it should only recalc on constraint change
|
|
* */
|
|
|
|
/* if an axis has been selected */
|
|
if (t->con.mode & CON_APPLY) {
|
|
size[0] = size[1] = size[2] = -1;
|
|
|
|
SizeToMat3(size, mat);
|
|
|
|
if (t->con.applySize) {
|
|
t->con.applySize(t, NULL, mat);
|
|
}
|
|
|
|
sprintf(str, "Mirror%s", t->con.text);
|
|
|
|
for(i = 0, td=t->data; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
ElementResize(t, td, mat);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
}
|
|
else
|
|
{
|
|
size[0] = size[1] = size[2] = 1;
|
|
|
|
SizeToMat3(size, mat);
|
|
|
|
for(i = 0, td=t->data; i < t->total; i++, td++) {
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
ElementResize(t, td, mat);
|
|
}
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, "Select a mirror axis (X, Y, Z)");
|
|
|
|
viewRedrawForce(t);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** ALIGN *************************** */
|
|
|
|
void initAlign(TransInfo *t)
|
|
{
|
|
t->flag |= T_NO_CONSTRAINT;
|
|
|
|
t->transform = Align;
|
|
}
|
|
|
|
int Align(TransInfo *t, short mval[2])
|
|
{
|
|
TransData *td = t->data;
|
|
float center[3];
|
|
int i;
|
|
|
|
/* saving original center */
|
|
VECCOPY(center, t->center);
|
|
|
|
for(i = 0 ; i < t->total; i++, td++)
|
|
{
|
|
float mat[3][3], invmat[3][3];
|
|
|
|
if (td->flag & TD_NOACTION)
|
|
break;
|
|
|
|
if (td->flag & TD_SKIP)
|
|
continue;
|
|
|
|
/* around local centers */
|
|
if (t->flag & (T_OBJECT|T_POSE)) {
|
|
VECCOPY(t->center, td->center);
|
|
}
|
|
else {
|
|
if(G.scene->selectmode & SCE_SELECT_FACE) {
|
|
VECCOPY(t->center, td->center);
|
|
}
|
|
}
|
|
|
|
Mat3Inv(invmat, td->axismtx);
|
|
|
|
Mat3MulMat3(mat, t->spacemtx, invmat);
|
|
|
|
ElementRotation(t, td, mat, t->around);
|
|
}
|
|
|
|
/* restoring original center */
|
|
VECCOPY(t->center, center);
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, "Align");
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
|
|
|
|
/* ---------------- Special Helpers for Various Settings ------------- */
|
|
|
|
/* This function returns the snapping 'mode' for Animation Editors only
|
|
* We cannot use the standard snapping due to NLA-strip scaling complexities.
|
|
*/
|
|
// XXX these modifier checks should be keymappable
|
|
static short getAnimEdit_SnapMode(TransInfo *t)
|
|
{
|
|
short autosnap= SACTSNAP_OFF;
|
|
|
|
/* currently, some of these are only for the action editor */
|
|
if (t->spacetype == SPACE_ACTION) {
|
|
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
|
|
|
|
if (saction) {
|
|
switch (saction->autosnap) {
|
|
case SACTSNAP_OFF:
|
|
if (t->event->ctrl)
|
|
autosnap= SACTSNAP_STEP;
|
|
else if (t->event->shift)
|
|
autosnap= SACTSNAP_FRAME;
|
|
else if (t->event->alt)
|
|
autosnap= SACTSNAP_MARKER;
|
|
else
|
|
autosnap= SACTSNAP_OFF;
|
|
break;
|
|
case SACTSNAP_STEP:
|
|
autosnap= (t->event->ctrl)? SACTSNAP_OFF: SACTSNAP_STEP;
|
|
break;
|
|
case SACTSNAP_FRAME:
|
|
autosnap= (t->event->shift)? SACTSNAP_OFF: SACTSNAP_FRAME;
|
|
break;
|
|
case SACTSNAP_MARKER:
|
|
autosnap= (t->event->alt)? SACTSNAP_OFF: SACTSNAP_MARKER;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (t->spacetype == SPACE_NLA) {
|
|
SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
|
|
|
|
if (snla) {
|
|
switch (snla->autosnap) {
|
|
case SACTSNAP_OFF:
|
|
if (t->event->ctrl)
|
|
autosnap= SACTSNAP_STEP;
|
|
else if (t->event->shift)
|
|
autosnap= SACTSNAP_FRAME;
|
|
else if (t->event->alt)
|
|
autosnap= SACTSNAP_MARKER;
|
|
else
|
|
autosnap= SACTSNAP_OFF;
|
|
break;
|
|
case SACTSNAP_STEP:
|
|
autosnap= (t->event->ctrl)? SACTSNAP_OFF: SACTSNAP_STEP;
|
|
break;
|
|
case SACTSNAP_FRAME:
|
|
autosnap= (t->event->shift)? SACTSNAP_OFF: SACTSNAP_FRAME;
|
|
break;
|
|
case SACTSNAP_MARKER:
|
|
autosnap= (t->event->alt)? SACTSNAP_OFF: SACTSNAP_MARKER;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (t->event->ctrl)
|
|
autosnap= SACTSNAP_STEP;
|
|
else if (t->event->shift)
|
|
autosnap= SACTSNAP_FRAME;
|
|
else if (t->event->alt)
|
|
autosnap= SACTSNAP_MARKER;
|
|
else
|
|
autosnap= SACTSNAP_OFF;
|
|
}
|
|
|
|
return autosnap;
|
|
}
|
|
|
|
/* This function is used for testing if an Animation Editor is displaying
|
|
* its data in frames or seconds (and the data needing to be edited as such).
|
|
* Returns 1 if in seconds, 0 if in frames
|
|
*/
|
|
static short getAnimEdit_DrawTime(TransInfo *t)
|
|
{
|
|
short drawtime;
|
|
|
|
/* currently, some of these are only for the action editor */
|
|
if (t->spacetype == SPACE_ACTION) {
|
|
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
|
|
|
|
drawtime = (saction->flag & SACTION_DRAWTIME)? 1 : 0;
|
|
}
|
|
else if (t->spacetype == SPACE_NLA) {
|
|
SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
|
|
|
|
drawtime = (snla->flag & SNLA_DRAWTIME)? 1 : 0;
|
|
}
|
|
else {
|
|
drawtime = 0;
|
|
}
|
|
|
|
return drawtime;
|
|
}
|
|
|
|
|
|
/* This function is used by Animation Editor specific transform functions to do
|
|
* the Snap Keyframe to Nearest Frame/Marker
|
|
*/
|
|
static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
|
|
{
|
|
/* snap key to nearest frame? */
|
|
if (autosnap == SACTSNAP_FRAME) {
|
|
const Scene *scene= t->scene;
|
|
const short doTime= getAnimEdit_DrawTime(t);
|
|
const double secf= FPS;
|
|
double val;
|
|
|
|
/* convert frame to nla-action time (if needed) */
|
|
if (ob)
|
|
val= get_action_frame_inv(ob, *(td->val));
|
|
else
|
|
val= *(td->val);
|
|
|
|
/* do the snapping to nearest frame/second */
|
|
if (doTime)
|
|
val= (float)( floor((val/secf) + 0.5f) * secf );
|
|
else
|
|
val= (float)( floor(val+0.5f) );
|
|
|
|
/* convert frame out of nla-action time */
|
|
if (ob)
|
|
*(td->val)= get_action_frame(ob, val);
|
|
else
|
|
*(td->val)= val;
|
|
}
|
|
/* snap key to nearest marker? */
|
|
else if (autosnap == SACTSNAP_MARKER) {
|
|
float val;
|
|
|
|
/* convert frame to nla-action time (if needed) */
|
|
if (ob)
|
|
val= get_action_frame_inv(ob, *(td->val));
|
|
else
|
|
val= *(td->val);
|
|
|
|
/* snap to nearest marker */
|
|
// XXX missing function!
|
|
//val= (float)find_nearest_marker_time(val);
|
|
|
|
/* convert frame out of nla-action time */
|
|
if (ob)
|
|
*(td->val)= get_action_frame(ob, val);
|
|
else
|
|
*(td->val)= val;
|
|
}
|
|
}
|
|
|
|
/* ----------------- Translation ----------------------- */
|
|
|
|
void initTimeTranslate(TransInfo *t)
|
|
{
|
|
t->mode = TFM_TIME_TRANSLATE;
|
|
t->transform = TimeTranslate;
|
|
|
|
/* num-input has max of (n-1) */
|
|
t->idx_max = 0;
|
|
t->num.flag = 0;
|
|
t->num.idx_max = t->idx_max;
|
|
|
|
/* initialise snap like for everything else */
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = t->snap[2] = 1.0f;
|
|
}
|
|
|
|
static void headerTimeTranslate(TransInfo *t, char *str)
|
|
{
|
|
char tvec[60];
|
|
|
|
/* if numeric input is active, use results from that, otherwise apply snapping to result */
|
|
if (hasNumInput(&t->num)) {
|
|
outputNumInput(&(t->num), tvec);
|
|
}
|
|
else {
|
|
const Scene *scene = t->scene;
|
|
const short autosnap= getAnimEdit_SnapMode(t);
|
|
const short doTime = getAnimEdit_DrawTime(t);
|
|
const double secf= FPS;
|
|
float val= t->fac;
|
|
|
|
/* apply snapping + frame->seconds conversions */
|
|
if (autosnap == SACTSNAP_STEP) {
|
|
if (doTime)
|
|
val= floor(val/secf + 0.5f);
|
|
else
|
|
val= floor(val + 0.5f);
|
|
}
|
|
else {
|
|
if (doTime)
|
|
val= val / secf;
|
|
}
|
|
|
|
sprintf(&tvec[0], "%.4f", val);
|
|
}
|
|
|
|
sprintf(str, "DeltaX: %s", &tvec[0]);
|
|
}
|
|
|
|
static void applyTimeTranslate(TransInfo *t, float sval)
|
|
{
|
|
TransData *td = t->data;
|
|
Scene *scene = t->scene;
|
|
int i;
|
|
|
|
const short doTime= getAnimEdit_DrawTime(t);
|
|
const double secf= FPS;
|
|
|
|
const short autosnap= getAnimEdit_SnapMode(t);
|
|
|
|
float deltax, val;
|
|
|
|
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
|
|
for (i = 0 ; i < t->total; i++, td++) {
|
|
/* it is assumed that td->ob is a pointer to the object,
|
|
* whose active action is where this keyframe comes from
|
|
*/
|
|
Object *ob= td->ob;
|
|
|
|
/* check if any need to apply nla-scaling */
|
|
if (ob) {
|
|
deltax = t->fac;
|
|
|
|
if (autosnap == SACTSNAP_STEP) {
|
|
if (doTime)
|
|
deltax= (float)( floor((deltax/secf) + 0.5f) * secf );
|
|
else
|
|
deltax= (float)( floor(deltax + 0.5f) );
|
|
}
|
|
|
|
val = get_action_frame_inv(ob, td->ival);
|
|
val += deltax;
|
|
*(td->val) = get_action_frame(ob, val);
|
|
}
|
|
else {
|
|
deltax = val = t->fac;
|
|
|
|
if (autosnap == SACTSNAP_STEP) {
|
|
if (doTime)
|
|
val= (float)( floor((deltax/secf) + 0.5f) * secf );
|
|
else
|
|
val= (float)( floor(val + 0.5f) );
|
|
}
|
|
|
|
*(td->val) = td->ival + val;
|
|
}
|
|
|
|
/* apply nearest snapping */
|
|
doAnimEdit_SnapFrame(t, td, ob, autosnap);
|
|
}
|
|
}
|
|
|
|
int TimeTranslate(TransInfo *t, short mval[2])
|
|
{
|
|
View2D *v2d = (View2D *)t->view;
|
|
float cval[2], sval[2];
|
|
char str[200];
|
|
|
|
/* calculate translation amount from mouse movement - in 'time-grid space' */
|
|
UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
|
|
UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
|
|
|
|
/* we only need to calculate effect for time (applyTimeTranslate only needs that) */
|
|
t->fac= cval[0] - sval[0];
|
|
|
|
/* handle numeric-input stuff */
|
|
t->vec[0] = t->fac;
|
|
applyNumInput(&t->num, &t->vec[0]);
|
|
t->fac = t->vec[0];
|
|
headerTimeTranslate(t, str);
|
|
|
|
applyTimeTranslate(t, sval[0]);
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ----------------- Time Slide ----------------------- */
|
|
|
|
void initTimeSlide(TransInfo *t)
|
|
{
|
|
/* this tool is only really available in the Action Editor... */
|
|
if (t->spacetype == SPACE_ACTION) {
|
|
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
|
|
|
|
/* set flag for drawing stuff */
|
|
saction->flag |= SACTION_MOVING;
|
|
}
|
|
|
|
t->mode = TFM_TIME_SLIDE;
|
|
t->transform = TimeSlide;
|
|
t->flag |= T_FREE_CUSTOMDATA;
|
|
|
|
/* num-input has max of (n-1) */
|
|
t->idx_max = 0;
|
|
t->num.flag = 0;
|
|
t->num.idx_max = t->idx_max;
|
|
|
|
/* initialise snap like for everything else */
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = t->snap[2] = 1.0f;
|
|
}
|
|
|
|
static void headerTimeSlide(TransInfo *t, float sval, char *str)
|
|
{
|
|
char tvec[60];
|
|
|
|
if (hasNumInput(&t->num)) {
|
|
outputNumInput(&(t->num), tvec);
|
|
}
|
|
else {
|
|
float minx= *((float *)(t->customData));
|
|
float maxx= *((float *)(t->customData) + 1);
|
|
float cval= t->fac;
|
|
float val;
|
|
|
|
val= 2.0f*(cval-sval) / (maxx-minx);
|
|
CLAMP(val, -1.0f, 1.0f);
|
|
|
|
sprintf(&tvec[0], "%.4f", val);
|
|
}
|
|
|
|
sprintf(str, "TimeSlide: %s", &tvec[0]);
|
|
}
|
|
|
|
static void applyTimeSlide(TransInfo *t, float sval)
|
|
{
|
|
TransData *td = t->data;
|
|
int i;
|
|
|
|
float minx= *((float *)(t->customData));
|
|
float maxx= *((float *)(t->customData) + 1);
|
|
|
|
/* set value for drawing black line */
|
|
if (t->spacetype == SPACE_ACTION) {
|
|
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
|
|
float cvalf = t->fac;
|
|
|
|
saction->timeslide= cvalf;
|
|
}
|
|
|
|
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
|
|
for (i = 0 ; i < t->total; i++, td++) {
|
|
/* it is assumed that td->ob is a pointer to the object,
|
|
* whose active action is where this keyframe comes from
|
|
*/
|
|
Object *ob= td->ob;
|
|
float cval = t->fac;
|
|
|
|
/* apply scaling to necessary values */
|
|
if (ob)
|
|
cval= get_action_frame(ob, cval);
|
|
|
|
/* only apply to data if in range */
|
|
if ((sval > minx) && (sval < maxx)) {
|
|
float cvalc= CLAMPIS(cval, minx, maxx);
|
|
float timefac;
|
|
|
|
/* left half? */
|
|
if (td->ival < sval) {
|
|
timefac= (sval - td->ival) / (sval - minx);
|
|
*(td->val)= cvalc - timefac * (cvalc - minx);
|
|
}
|
|
else {
|
|
timefac= (td->ival - sval) / (maxx - sval);
|
|
*(td->val)= cvalc + timefac * (maxx - cvalc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int TimeSlide(TransInfo *t, short mval[2])
|
|
{
|
|
View2D *v2d = (View2D *)t->view;
|
|
float cval[2], sval[2];
|
|
float minx= *((float *)(t->customData));
|
|
float maxx= *((float *)(t->customData) + 1);
|
|
char str[200];
|
|
|
|
/* calculate mouse co-ordinates */
|
|
UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
|
|
UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
|
|
|
|
/* t->fac stores cval[0], which is the current mouse-pointer location (in frames) */
|
|
t->fac= cval[0];
|
|
|
|
/* handle numeric-input stuff */
|
|
t->vec[0] = 2.0f*(cval[0]-sval[0]) / (maxx-minx);
|
|
applyNumInput(&t->num, &t->vec[0]);
|
|
t->fac = (maxx-minx) * t->vec[0] / 2.0 + sval[0];
|
|
|
|
headerTimeSlide(t, sval[0], str);
|
|
applyTimeSlide(t, sval[0]);
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ----------------- Scaling ----------------------- */
|
|
|
|
void initTimeScale(TransInfo *t)
|
|
{
|
|
t->mode = TFM_TIME_SCALE;
|
|
t->transform = TimeScale;
|
|
|
|
t->flag |= T_NULL_ONE;
|
|
t->num.flag |= NUM_NULL_ONE;
|
|
|
|
/* num-input has max of (n-1) */
|
|
t->idx_max = 0;
|
|
t->num.flag = 0;
|
|
t->num.idx_max = t->idx_max;
|
|
|
|
/* initialise snap like for everything else */
|
|
t->snap[0] = 0.0f;
|
|
t->snap[1] = t->snap[2] = 1.0f;
|
|
}
|
|
|
|
static void headerTimeScale(TransInfo *t, char *str) {
|
|
char tvec[60];
|
|
|
|
if (hasNumInput(&t->num))
|
|
outputNumInput(&(t->num), tvec);
|
|
else
|
|
sprintf(&tvec[0], "%.4f", t->fac);
|
|
|
|
sprintf(str, "ScaleX: %s", &tvec[0]);
|
|
}
|
|
|
|
static void applyTimeScale(TransInfo *t) {
|
|
Scene *scene = t->scene;
|
|
TransData *td = t->data;
|
|
int i;
|
|
|
|
const short autosnap= getAnimEdit_SnapMode(t);
|
|
const short doTime= getAnimEdit_DrawTime(t);
|
|
const double secf= FPS;
|
|
|
|
|
|
for (i = 0 ; i < t->total; i++, td++) {
|
|
/* it is assumed that td->ob is a pointer to the object,
|
|
* whose active action is where this keyframe comes from
|
|
*/
|
|
Object *ob= td->ob;
|
|
float startx= CFRA;
|
|
float fac= t->fac;
|
|
|
|
if (autosnap == SACTSNAP_STEP) {
|
|
if (doTime)
|
|
fac= (float)( floor(fac/secf + 0.5f) * secf );
|
|
else
|
|
fac= (float)( floor(fac + 0.5f) );
|
|
}
|
|
|
|
/* check if any need to apply nla-scaling */
|
|
if (ob)
|
|
startx= get_action_frame(ob, startx);
|
|
|
|
/* now, calculate the new value */
|
|
*(td->val) = td->ival - startx;
|
|
*(td->val) *= fac;
|
|
*(td->val) += startx;
|
|
|
|
/* apply nearest snapping */
|
|
doAnimEdit_SnapFrame(t, td, ob, autosnap);
|
|
}
|
|
}
|
|
|
|
int TimeScale(TransInfo *t, short mval[2])
|
|
{
|
|
float cval, sval;
|
|
float deltax, startx;
|
|
float width= 0.0f;
|
|
char str[200];
|
|
|
|
sval= t->imval[0];
|
|
cval= mval[0];
|
|
|
|
// XXX ewww... we need a better factor!
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
switch (t->spacetype) {
|
|
case SPACE_ACTION:
|
|
width= ACTWIDTH;
|
|
break;
|
|
case SPACE_NLA:
|
|
width= NLAWIDTH;
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
/* calculate scaling factor */
|
|
startx= sval-(width/2+(t->ar->winx)/2);
|
|
deltax= cval-(width/2+(t->ar->winx)/2);
|
|
t->fac = deltax / startx;
|
|
|
|
/* handle numeric-input stuff */
|
|
t->vec[0] = t->fac;
|
|
applyNumInput(&t->num, &t->vec[0]);
|
|
t->fac = t->vec[0];
|
|
headerTimeScale(t, str);
|
|
|
|
applyTimeScale(t);
|
|
|
|
recalcData(t);
|
|
|
|
ED_area_headerprint(t->sa, str);
|
|
|
|
viewRedrawForce(t);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* ************************************ */
|
|
|
|
void BIF_TransformSetUndo(char *str)
|
|
{
|
|
// TRANSFORM_FIX_ME
|
|
//Trans.undostr= str;
|
|
}
|
|
|
|
|
|
void NDofTransform()
|
|
{
|
|
#if 0 // TRANSFORM_FIX_ME
|
|
float fval[7];
|
|
float maxval = 50.0f; // also serves as threshold
|
|
int axis = -1;
|
|
int mode = 0;
|
|
int i;
|
|
|
|
getndof(fval);
|
|
|
|
for(i = 0; i < 6; i++)
|
|
{
|
|
float val = fabs(fval[i]);
|
|
if (val > maxval)
|
|
{
|
|
axis = i;
|
|
maxval = val;
|
|
}
|
|
}
|
|
|
|
switch(axis)
|
|
{
|
|
case -1:
|
|
/* No proper axis found */
|
|
break;
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
mode = TFM_TRANSLATION;
|
|
break;
|
|
case 4:
|
|
mode = TFM_ROTATION;
|
|
break;
|
|
case 3:
|
|
case 5:
|
|
mode = TFM_TRACKBALL;
|
|
break;
|
|
default:
|
|
printf("ndof: what we are doing here ?");
|
|
}
|
|
|
|
if (mode != 0)
|
|
{
|
|
initTransform(mode, CTX_NDOF);
|
|
Transform();
|
|
}
|
|
#endif
|
|
}
|