Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/transform/manipulator_widget.c')
-rw-r--r--source/blender/editors/transform/manipulator_widget.c2082
1 files changed, 2082 insertions, 0 deletions
diff --git a/source/blender/editors/transform/manipulator_widget.c b/source/blender/editors/transform/manipulator_widget.c
new file mode 100644
index 00000000000..eff9fda4378
--- /dev/null
+++ b/source/blender/editors/transform/manipulator_widget.c
@@ -0,0 +1,2082 @@
+/*
+ * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/transform/transform_manipulator.c
+ * \ingroup edtransform
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_armature_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_lattice_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+
+#include "RNA_access.h"
+
+#include "BKE_action.h"
+#include "BKE_context.h"
+#include "BKE_curve.h"
+#include "BKE_global.h"
+#include "BKE_particle.h"
+#include "BKE_pointcache.h"
+#include "BKE_editmesh.h"
+#include "BKE_lattice.h"
+
+#include "BIF_gl.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_armature.h"
+#include "ED_curve.h"
+#include "ED_particle.h"
+#include "ED_view3d.h"
+#include "ED_screen.h"
+
+#include "UI_resources.h"
+#include "UI_interface.h"
+
+/* local module include */
+#include "transform.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "GPU_select.h"
+
+/* drawing flags */
+
+#define MAN_TRANS_X (1 << 0)
+#define MAN_TRANS_Y (1 << 1)
+#define MAN_TRANS_Z (1 << 2)
+#define MAN_TRANS_C (MAN_TRANS_X | MAN_TRANS_Y | MAN_TRANS_Z)
+
+#define MAN_ROT_X (1 << 3)
+#define MAN_ROT_Y (1 << 4)
+#define MAN_ROT_Z (1 << 5)
+#define MAN_ROT_V (1 << 6)
+#define MAN_ROT_T (1 << 7)
+#define MAN_ROT_C (MAN_ROT_X | MAN_ROT_Y | MAN_ROT_Z | MAN_ROT_V | MAN_ROT_T)
+
+#define MAN_SCALE_X (1 << 8)
+#define MAN_SCALE_Y (1 << 9)
+#define MAN_SCALE_Z (1 << 10)
+#define MAN_SCALE_C (MAN_SCALE_X | MAN_SCALE_Y | MAN_SCALE_Z)
+
+/* return codes for select */
+enum {
+ MAN_SEL_TRANS_X = 0,
+ MAN_SEL_TRANS_Y,
+ MAN_SEL_TRANS_Z,
+
+ MAN_SEL_ROT_X,
+ MAN_SEL_ROT_Y,
+ MAN_SEL_ROT_Z,
+ MAN_SEL_ROT_V,
+ MAN_SEL_ROT_T,
+
+ MAN_SEL_SCALE_X,
+ MAN_SEL_SCALE_Y,
+ MAN_SEL_SCALE_Z,
+
+ /* those two stay at the end so the rest can be inferred with bitshifting */
+ MAN_SEL_SCALE_C,
+ MAN_SEL_TRANS_C,
+
+ MAN_SEL_MAX
+};
+
+/* color codes */
+
+#define MAN_RGB 0
+#define MAN_GHOST 1
+#define MAN_MOVECOL 2
+
+/* threshold for testing view aligned manipulator axis */
+#define TW_AXIS_DOT_MIN 0.02f
+#define TW_AXIS_DOT_MAX 0.1f
+
+/* transform widget center calc helper for below */
+static void calc_tw_center(Scene *scene, const float co[3])
+{
+ float *twcent = scene->twcent;
+ float *min = scene->twmin;
+ float *max = scene->twmax;
+
+ minmax_v3v3_v3(min, max, co);
+ add_v3_v3(twcent, co);
+}
+
+static void protectflag_to_drawflags(short protectflag, short *drawflags)
+{
+ if (protectflag & OB_LOCK_LOCX)
+ *drawflags &= ~MAN_TRANS_X;
+ if (protectflag & OB_LOCK_LOCY)
+ *drawflags &= ~MAN_TRANS_Y;
+ if (protectflag & OB_LOCK_LOCZ)
+ *drawflags &= ~MAN_TRANS_Z;
+
+ if (protectflag & OB_LOCK_ROTX)
+ *drawflags &= ~MAN_ROT_X;
+ if (protectflag & OB_LOCK_ROTY)
+ *drawflags &= ~MAN_ROT_Y;
+ if (protectflag & OB_LOCK_ROTZ)
+ *drawflags &= ~MAN_ROT_Z;
+
+ if (protectflag & OB_LOCK_SCALEX)
+ *drawflags &= ~MAN_SCALE_X;
+ if (protectflag & OB_LOCK_SCALEY)
+ *drawflags &= ~MAN_SCALE_Y;
+ if (protectflag & OB_LOCK_SCALEZ)
+ *drawflags &= ~MAN_SCALE_Z;
+}
+
+/* for pose mode */
+static void stats_pose(Scene *scene, RegionView3D *rv3d, bPoseChannel *pchan)
+{
+ Bone *bone = pchan->bone;
+
+ if (bone) {
+ calc_tw_center(scene, pchan->pose_head);
+ protectflag_to_drawflags(pchan->protectflag, &rv3d->twdrawflag);
+ }
+}
+
+/* for editmode*/
+static void stats_editbone(RegionView3D *rv3d, EditBone *ebo)
+{
+ if (ebo->flag & BONE_EDITMODE_LOCKED)
+ protectflag_to_drawflags(OB_LOCK_LOC | OB_LOCK_ROT | OB_LOCK_SCALE, &rv3d->twdrawflag);
+}
+
+/* could move into BLI_math however this is only useful for display/editing purposes */
+static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], const float angle)
+{
+ /* X/Y are arbitrary axies, most importantly Z is the axis of rotation */
+
+ float cross_vec[3];
+ float quat[4];
+
+ /* this is an un-scientific method to get a vector to cross with
+ * XYZ intentionally YZX */
+ cross_vec[0] = axis[1];
+ cross_vec[1] = axis[2];
+ cross_vec[2] = axis[0];
+
+ /* X-axis */
+ cross_v3_v3v3(gmat[0], cross_vec, axis);
+ normalize_v3(gmat[0]);
+ axis_angle_to_quat(quat, axis, angle);
+ mul_qt_v3(quat, gmat[0]);
+
+ /* Y-axis */
+ axis_angle_to_quat(quat, axis, M_PI / 2.0);
+ copy_v3_v3(gmat[1], gmat[0]);
+ mul_qt_v3(quat, gmat[1]);
+
+ /* Z-axis */
+ copy_v3_v3(gmat[2], axis);
+
+ normalize_m3(gmat);
+}
+
+
+static int test_rotmode_euler(short rotmode)
+{
+ return (ELEM(rotmode, ROT_MODE_AXISANGLE, ROT_MODE_QUAT)) ? 0 : 1;
+}
+
+bool gimbal_axis(Object *ob, float gmat[3][3])
+{
+ if (ob) {
+ if (ob->mode & OB_MODE_POSE) {
+ bPoseChannel *pchan = BKE_pose_channel_active(ob);
+
+ if (pchan) {
+ float mat[3][3], tmat[3][3], obmat[3][3];
+ if (test_rotmode_euler(pchan->rotmode)) {
+ eulO_to_gimbal_axis(mat, pchan->eul, pchan->rotmode);
+ }
+ else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(mat, pchan->rotAxis, pchan->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+
+ /* apply bone transformation */
+ mul_m3_m3m3(tmat, pchan->bone->bone_mat, mat);
+
+ if (pchan->parent) {
+ float parent_mat[3][3];
+
+ copy_m3_m4(parent_mat, pchan->parent->pose_mat);
+ mul_m3_m3m3(mat, parent_mat, tmat);
+
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, mat);
+ }
+ else {
+ /* needed if object transformation isn't identity */
+ copy_m3_m4(obmat, ob->obmat);
+ mul_m3_m3m3(gmat, obmat, tmat);
+ }
+
+ normalize_m3(gmat);
+ return 1;
+ }
+ }
+ else {
+ if (test_rotmode_euler(ob->rotmode)) {
+ eulO_to_gimbal_axis(gmat, ob->rot, ob->rotmode);
+ }
+ else if (ob->rotmode == ROT_MODE_AXISANGLE) {
+ axis_angle_to_gimbal_axis(gmat, ob->rotAxis, ob->rotAngle);
+ }
+ else { /* quat */
+ return 0;
+ }
+
+ if (ob->parent) {
+ float parent_mat[3][3];
+ copy_m3_m4(parent_mat, ob->parent->obmat);
+ normalize_m3(parent_mat);
+ mul_m3_m3m3(gmat, parent_mat, gmat);
+ }
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+/* centroid, boundbox, of selection */
+/* returns total items selected */
+static int calc_manipulator_stats(const bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ Base *base;
+ Object *ob = OBACT;
+ int a, totsel = 0;
+
+ /* transform widget matrix */
+ unit_m4(rv3d->twmat);
+
+ rv3d->twdrawflag = 0xFFFF;
+
+ /* transform widget centroid/center */
+ INIT_MINMAX(scene->twmin, scene->twmax);
+ zero_v3(scene->twcent);
+
+ if (obedit) {
+ ob = obedit;
+ if ((ob->lay & v3d->lay) == 0) return 0;
+
+ if (obedit->type == OB_MESH) {
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMEditSelection ese;
+ float vec[3] = {0, 0, 0};
+
+ /* USE LAST SELECTE WITH ACTIVE */
+ if ((v3d->around == V3D_ACTIVE) && BM_select_history_active_get(em->bm, &ese)) {
+ BM_editselection_center(&ese, vec);
+ calc_tw_center(scene, vec);
+ totsel = 1;
+ }
+ else {
+ BMesh *bm = em->bm;
+ BMVert *eve;
+
+ BMIter iter;
+
+ /* do vertices/edges/faces for center depending on selection
+ * mode. note we can't use just vertex selection flag because
+ * it is not flush down on changes */
+ if (ts->selectmode & SCE_SELECT_VERTEX) {
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ }
+ }
+ }
+ }
+ else if (ts->selectmode & SCE_SELECT_EDGE) {
+ BMIter itersub;
+ BMEdge *eed;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* check the vertex has a selected edge, only add it once */
+ BM_ITER_ELEM (eed, &itersub, eve, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ break;
+ }
+ }
+ }
+ }
+ }
+ else {
+ BMIter itersub;
+ BMFace *efa;
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
+ /* check the vertex has a selected face, only add it once */
+ BM_ITER_ELEM (efa, &itersub, eve, BM_FACES_OF_VERT) {
+ if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
+ totsel++;
+ calc_tw_center(scene, eve->co);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ } /* end editmesh */
+ else if (obedit->type == OB_ARMATURE) {
+ bArmature *arm = obedit->data;
+ EditBone *ebo;
+
+ if ((v3d->around == V3D_ACTIVE) && (ebo = arm->act_edbone)) {
+ /* doesn't check selection or visibility intentionally */
+ if (ebo->flag & BONE_TIPSEL) {
+ calc_tw_center(scene, ebo->tail);
+ totsel++;
+ }
+ if ((ebo->flag & BONE_ROOTSEL) ||
+ ((ebo->flag & BONE_TIPSEL) == false)) /* ensure we get at least one point */
+ {
+ calc_tw_center(scene, ebo->head);
+ totsel++;
+ }
+ stats_editbone(rv3d, ebo);
+ }
+ else {
+ for (ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ if (EBONE_VISIBLE(arm, ebo)) {
+ if (ebo->flag & BONE_TIPSEL) {
+ calc_tw_center(scene, ebo->tail);
+ totsel++;
+ }
+ if (ebo->flag & BONE_ROOTSEL) {
+ calc_tw_center(scene, ebo->head);
+ totsel++;
+ }
+ if (ebo->flag & BONE_SELECTED) {
+ stats_editbone(rv3d, ebo);
+ }
+ }
+ }
+ }
+ }
+ else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
+ Curve *cu = obedit->data;
+ float center[3];
+
+ if (v3d->around == V3D_ACTIVE && ED_curve_active_center(cu, center)) {
+ calc_tw_center(scene, center);
+ totsel++;
+ }
+ else {
+ Nurb *nu;
+ BezTriple *bezt;
+ BPoint *bp;
+ ListBase *nurbs = BKE_curve_editNurbs_get(cu);
+
+ nu = nurbs->first;
+ while (nu) {
+ if (nu->type == CU_BEZIER) {
+ bezt = nu->bezt;
+ a = nu->pntsu;
+ while (a--) {
+ /* exceptions
+ * if handles are hidden then only check the center points.
+ * If the center knot is selected then only use this as the center point.
+ */
+ if (cu->drawflag & CU_HIDE_HANDLES) {
+ if (bezt->f2 & SELECT) {
+ calc_tw_center(scene, bezt->vec[1]);
+ totsel++;
+ }
+ }
+ else if (bezt->f2 & SELECT) {
+ calc_tw_center(scene, bezt->vec[1]);
+ totsel++;
+ }
+ else {
+ if (bezt->f1 & SELECT) {
+ calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 0]);
+ totsel++;
+ }
+ if (bezt->f3 & SELECT) {
+ calc_tw_center(scene, bezt->vec[(v3d->around == V3D_LOCAL) ? 1 : 2]);
+ totsel++;
+ }
+ }
+ bezt++;
+ }
+ }
+ else {
+ bp = nu->bp;
+ a = nu->pntsu * nu->pntsv;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ calc_tw_center(scene, bp->vec);
+ totsel++;
+ }
+ bp++;
+ }
+ }
+ nu = nu->next;
+ }
+ }
+ }
+ else if (obedit->type == OB_MBALL) {
+ MetaBall *mb = (MetaBall *)obedit->data;
+ MetaElem *ml;
+
+ if ((v3d->around == V3D_ACTIVE) && (ml = mb->lastelem)) {
+ calc_tw_center(scene, &ml->x);
+ totsel++;
+ }
+ else {
+ for (ml = mb->editelems->first; ml; ml = ml->next) {
+ if (ml->flag & SELECT) {
+ calc_tw_center(scene, &ml->x);
+ totsel++;
+ }
+ }
+ }
+ }
+ else if (obedit->type == OB_LATTICE) {
+ Lattice *lt = ((Lattice *)obedit->data)->editlatt->latt;
+ BPoint *bp;
+
+ if ((v3d->around == V3D_ACTIVE) && (bp = BKE_lattice_active_point_get(lt))) {
+ calc_tw_center(scene, bp->vec);
+ totsel++;
+ }
+ else {
+ bp = lt->def;
+ a = lt->pntsu * lt->pntsv * lt->pntsw;
+ while (a--) {
+ if (bp->f1 & SELECT) {
+ calc_tw_center(scene, bp->vec);
+ totsel++;
+ }
+ bp++;
+ }
+ }
+ }
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(obedit->obmat, scene->twcent);
+ mul_m4_v3(obedit->obmat, scene->twmin);
+ mul_m4_v3(obedit->obmat, scene->twmax);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_POSE)) {
+ bPoseChannel *pchan;
+ int mode = TFM_ROTATION; // mislead counting bones... bah. We don't know the manipulator mode, could be mixed
+ bool ok = false;
+
+ if ((ob->lay & v3d->lay) == 0) return 0;
+
+ if ((v3d->around == V3D_ACTIVE) && (pchan = BKE_pose_channel_active(ob))) {
+ /* doesn't check selection or visibility intentionally */
+ Bone *bone = pchan->bone;
+ if (bone) {
+ stats_pose(scene, rv3d, pchan);
+ totsel = 1;
+ ok = true;
+ }
+ }
+ else {
+ totsel = count_set_pose_transflags(&mode, 0, ob);
+
+ if (totsel) {
+ /* use channels to get stats */
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ Bone *bone = pchan->bone;
+ if (bone && (bone->flag & BONE_TRANSFORM)) {
+ stats_pose(scene, rv3d, pchan);
+ }
+ }
+ ok = true;
+ }
+ }
+
+ if (ok) {
+ mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ mul_m4_v3(ob->obmat, scene->twcent);
+ mul_m4_v3(ob->obmat, scene->twmin);
+ mul_m4_v3(ob->obmat, scene->twmax);
+ }
+ }
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ /* pass */
+ }
+ else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ PTCacheEditPoint *point;
+ PTCacheEditKey *ek;
+ int k;
+
+ if (edit) {
+ point = edit->points;
+ for (a = 0; a < edit->totpoint; a++, point++) {
+ if (point->flag & PEP_HIDE) continue;
+
+ for (k = 0, ek = point->keys; k < point->totkey; k++, ek++) {
+ if (ek->flag & PEK_SELECT) {
+ calc_tw_center(scene, ek->flag & PEK_USE_WCO ? ek->world_co : ek->co);
+ totsel++;
+ }
+ }
+ }
+
+ /* selection center */
+ if (totsel)
+ mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ }
+ }
+ else {
+
+ /* we need the one selected object, if its not active */
+ ob = OBACT;
+ if (ob && !(ob->flag & SELECT)) ob = NULL;
+
+ for (base = scene->base.first; base; base = base->next) {
+ if (TESTBASELIB(v3d, base)) {
+ if (ob == NULL)
+ ob = base->object;
+ calc_tw_center(scene, base->object->obmat[3]);
+ protectflag_to_drawflags(base->object->protectflag, &rv3d->twdrawflag);
+ totsel++;
+ }
+ }
+
+ /* selection center */
+ if (totsel) {
+ mul_v3_fl(scene->twcent, 1.0f / (float)totsel); // centroid!
+ }
+ }
+
+ /* global, local or normal orientation? */
+ if (ob && totsel) {
+
+ switch (v3d->twmode) {
+
+ case V3D_MANIP_GLOBAL:
+ {
+ break; /* nothing to do */
+ }
+ case V3D_MANIP_GIMBAL:
+ {
+ float mat[3][3];
+ if (gimbal_axis(ob, mat)) {
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ /* if not gimbal, fall through to normal */
+ /* fall-through */
+ }
+ case V3D_MANIP_NORMAL:
+ {
+ if (obedit || ob->mode & OB_MODE_POSE) {
+ float mat[3][3];
+ ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ /* no break we define 'normal' as 'local' in Object mode */
+ /* fall-through */
+ }
+ case V3D_MANIP_LOCAL:
+ {
+ if (ob->mode & OB_MODE_POSE) {
+ /* each bone moves on its own local axis, but to avoid confusion,
+ * use the active pones axis for display [#33575], this works as expected on a single bone
+ * and users who select many bones will understand whats going on and what local means
+ * when they start transforming */
+ float mat[3][3];
+ ED_getTransformOrientationMatrix(C, mat, (v3d->around == V3D_ACTIVE));
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ copy_m4_m4(rv3d->twmat, ob->obmat);
+ normalize_m4(rv3d->twmat);
+ break;
+ }
+ case V3D_MANIP_VIEW:
+ {
+ float mat[3][3];
+ copy_m3_m4(mat, rv3d->viewinv);
+ normalize_m3(mat);
+ copy_m4_m3(rv3d->twmat, mat);
+ break;
+ }
+ default: /* V3D_MANIP_CUSTOM */
+ {
+ float mat[3][3];
+ if (applyTransformOrientation(C, mat, NULL)) {
+ copy_m4_m3(rv3d->twmat, mat);
+ }
+ break;
+ }
+ }
+
+ }
+
+ return totsel;
+}
+
+/* don't draw axis perpendicular to the view */
+static void test_manipulator_axis(const bContext *C)
+{
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ float view_vec[3], axis_vec[3];
+ float idot;
+ int i;
+
+ const int twdrawflag_axis[3] = {
+ (MAN_TRANS_X | MAN_SCALE_X),
+ (MAN_TRANS_Y | MAN_SCALE_Y),
+ (MAN_TRANS_Z | MAN_SCALE_Z)};
+
+ ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], view_vec);
+
+ for (i = 0; i < 3; i++) {
+ normalize_v3_v3(axis_vec, rv3d->twmat[i]);
+ rv3d->tw_idot[i] = idot = 1.0f - fabsf(dot_v3v3(view_vec, axis_vec));
+ if (idot < TW_AXIS_DOT_MIN) {
+ rv3d->twdrawflag &= ~twdrawflag_axis[i];
+ }
+ }
+}
+
+
+/* ******************** DRAWING STUFFIES *********** */
+
+static float screen_aligned(RegionView3D *rv3d, float mat[4][4])
+{
+ glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
+
+ /* sets view screen aligned */
+ glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
+
+ return len_v3(mat[0]); /* draw scale */
+}
+
+
+/* radring = radius of doughnut rings
+ * radhole = radius hole
+ * start = starting segment (based on nrings)
+ * end = end segment
+ * nsides = amount of points in ring
+ * nrigns = amount of rings
+ */
+static void partial_doughnut(float radring, float radhole, int start, int end, int nsides, int nrings)
+{
+ float theta, phi, theta1;
+ float cos_theta, sin_theta;
+ float cos_theta1, sin_theta1;
+ float ring_delta, side_delta;
+ int i, j, do_caps = true;
+
+ if (start == 0 && end == nrings) do_caps = false;
+
+ ring_delta = 2.0f * (float)M_PI / (float)nrings;
+ side_delta = 2.0f * (float)M_PI / (float)nsides;
+
+ theta = (float)M_PI + 0.5f * ring_delta;
+ cos_theta = cosf(theta);
+ sin_theta = sinf(theta);
+
+ for (i = nrings - 1; i >= 0; i--) {
+ theta1 = theta + ring_delta;
+ cos_theta1 = cosf(theta1);
+ sin_theta1 = sinf(theta1);
+
+ if (do_caps && i == start) { // cap
+ glBegin(GL_POLYGON);
+ phi = 0.0;
+ for (j = nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi += side_delta;
+ cos_phi = cosf(phi);
+ sin_phi = sinf(phi);
+ dist = radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+ if (i >= start && i <= end) {
+ glBegin(GL_QUAD_STRIP);
+ phi = 0.0;
+ for (j = nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi += side_delta;
+ cos_phi = cosf(phi);
+ sin_phi = sinf(phi);
+ dist = radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta1 * dist, -sin_theta1 * dist, radring * sin_phi);
+ glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+
+ if (do_caps && i == end) { // cap
+ glBegin(GL_POLYGON);
+ phi = 0.0;
+ for (j = nsides; j >= 0; j--) {
+ float cos_phi, sin_phi, dist;
+
+ phi -= side_delta;
+ cos_phi = cosf(phi);
+ sin_phi = sinf(phi);
+ dist = radhole + radring * cos_phi;
+
+ glVertex3f(cos_theta * dist, -sin_theta * dist, radring * sin_phi);
+ }
+ glEnd();
+ }
+
+
+ theta = theta1;
+ cos_theta = cos_theta1;
+ sin_theta = sin_theta1;
+ }
+}
+
+static char axisBlendAngle(float idot)
+{
+ if (idot > TW_AXIS_DOT_MAX) {
+ return 255;
+ }
+ else if (idot < TW_AXIS_DOT_MIN) {
+ return 0;
+ }
+ else {
+ return (char)(255.0f * (idot - TW_AXIS_DOT_MIN) / (TW_AXIS_DOT_MAX - TW_AXIS_DOT_MIN));
+ }
+}
+
+/* three colors can be set:
+ * gray for ghosting
+ * moving: in transform theme color
+ * else the red/green/blue
+ */
+static void manipulator_setcolor(View3D *v3d, char axis, int colcode, unsigned char alpha, bool highlight)
+{
+ unsigned char col[4] = {0};
+ int offset = (highlight) ? 80 : 0;
+ col[3] = alpha;
+
+ if (colcode == MAN_GHOST) {
+ col[3] = 70;
+ }
+ else if (colcode == MAN_MOVECOL) {
+ UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+ }
+ else {
+ switch (axis) {
+ case 'C':
+ UI_GetThemeColor3ubv(TH_TRANSFORM, col);
+ if (v3d->twmode == V3D_MANIP_LOCAL) {
+ col[0] = col[0] > 200 ? 255 : col[0] + 55;
+ col[1] = col[1] > 200 ? 255 : col[1] + 55;
+ col[2] = col[2] > 200 ? 255 : col[2] + 55;
+ }
+ else if (v3d->twmode == V3D_MANIP_NORMAL) {
+ col[0] = col[0] < 55 ? 0 : col[0] - 55;
+ col[1] = col[1] < 55 ? 0 : col[1] - 55;
+ col[2] = col[2] < 55 ? 0 : col[2] - 55;
+ }
+ break;
+ case 'X':
+ UI_GetThemeColorShade3ubv(TH_AXIS_X, offset, col);
+ break;
+ case 'Y':
+ UI_GetThemeColorShade3ubv(TH_AXIS_Y, offset, col);
+ break;
+ case 'Z':
+ UI_GetThemeColorShade3ubv(TH_AXIS_Z, offset, col);
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+
+ glColor4ubv(col);
+}
+
+static void manipulator_axis_order(RegionView3D *rv3d, int r_axis_order[3])
+{
+ float axis_values[3];
+ float vec[3];
+
+ ED_view3d_global_to_vector(rv3d, rv3d->twmat[3], vec);
+
+ axis_values[0] = -dot_v3v3(rv3d->twmat[0], vec);
+ axis_values[1] = -dot_v3v3(rv3d->twmat[1], vec);
+ axis_values[2] = -dot_v3v3(rv3d->twmat[2], vec);
+
+ axis_sort_v3(axis_values, r_axis_order);
+}
+
+/* viewmatrix should have been set OK, also no shademode! */
+static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz, int axis,
+ const int selectionbase, int highlight)
+{
+ switch (axis) {
+ case 0:
+ /* axes */
+ if (flagx) {
+ if (selectionbase != -1) {
+ if (flagx & MAN_SCALE_X) GPU_select_load_id(selectionbase);
+ else if (flagx & MAN_TRANS_X) GPU_select_load_id(selectionbase);
+ }
+ else {
+ manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]), (highlight & (MAN_TRANS_X | MAN_SCALE_X)) != 0);
+ }
+ glBegin(GL_LINES);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 1:
+ if (flagy) {
+ if (selectionbase != -1) {
+ if (flagy & MAN_SCALE_Y) GPU_select_load_id(selectionbase);
+ else if (flagy & MAN_TRANS_Y) GPU_select_load_id(selectionbase);
+ }
+ else {
+ manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]), (highlight & (MAN_TRANS_Y | MAN_SCALE_Y)) != 0);
+ }
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ }
+ break;
+ case 2:
+ if (flagz) {
+ if (selectionbase != -1) {
+ if (flagz & MAN_SCALE_Z) GPU_select_load_id(selectionbase);
+ else if (flagz & MAN_TRANS_Z) GPU_select_load_id(selectionbase);
+ }
+ else {
+ manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]), (highlight & (MAN_TRANS_Z | MAN_SCALE_Z)) != 0);
+ }
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ glEnd();
+ }
+ break;
+ }
+}
+static void draw_manipulator_axes(View3D *v3d, RegionView3D *rv3d, int colcode,
+ int flagx, int flagy, int flagz,
+ const int axis_order[3], const int selectionbase, int highlight)
+{
+ int i;
+ for (i = 0; i < 3; i++) {
+ draw_manipulator_axes_single(v3d, rv3d, colcode, flagx, flagy, flagz, axis_order[i], selectionbase, highlight);
+ }
+}
+
+static void preOrthoFront(const bool ortho, float twmat[4][4], int axis)
+{
+ if (ortho == false) {
+ float omat[4][4];
+ copy_m4_m4(omat, twmat);
+ orthogonalize_m4(omat, axis);
+ glPushMatrix();
+ glMultMatrixf(omat);
+ glFrontFace(is_negative_m4(omat) ? GL_CW : GL_CCW);
+ }
+}
+
+static void postOrtho(const bool ortho)
+{
+ if (ortho == false) {
+ glPopMatrix();
+ }
+}
+
+static void draw_manipulator_rotate(
+ View3D *v3d, RegionView3D *rv3d, const int drawflags, int highlight, const int combo,
+ const bool is_moving, const int selectionbase)
+{
+ double plane[4];
+ float matt[4][4];
+ float size, unitmat[4][4];
+ float cywid = 0.33f * 0.01f * (float)U.tw_handlesize;
+ float cusize = cywid * 0.65f;
+ int arcs = (G.debug_value != 2);
+ const int colcode = (is_moving) ? MAN_MOVECOL : MAN_RGB;
+ bool ortho;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if ((drawflags & MAN_ROT_C) == 0) return;
+
+ /* Init stuff */
+ glDisable(GL_DEPTH_TEST);
+ unit_m4(unitmat);
+
+ /* prepare for screen aligned draw */
+ size = len_v3(rv3d->twmat[0]);
+ glPushMatrix();
+ glTranslatef(rv3d->twmat[3][0], rv3d->twmat[3][1], rv3d->twmat[3][2]);
+
+ if (arcs) {
+ /* clipplane makes nice handles, calc here because of multmatrix but with translate! */
+ copy_v3db_v3fl(plane, rv3d->viewinv[2]);
+ plane[3] = -0.02f * size; // clip just a bit more
+ glClipPlane(GL_CLIP_PLANE0, plane);
+ }
+ /* sets view screen aligned */
+ glRotatef(-360.0f * saacos(rv3d->viewquat[0]) / (float)M_PI, rv3d->viewquat[1], rv3d->viewquat[2], rv3d->viewquat[3]);
+
+ /* Screen aligned help circle */
+ if (arcs) {
+ if (selectionbase == -1) {
+ UI_ThemeColorShade(TH_BACK, -30);
+ drawcircball(GL_LINE_LOOP, unitmat[3], size, unitmat);
+ }
+ }
+
+ /* Screen aligned trackball rot circle */
+ if (drawflags & MAN_ROT_T) {
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else UI_ThemeColor(TH_TRANSFORM);
+
+ drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
+ }
+
+ /* Screen aligned view rot circle */
+ if (drawflags & MAN_ROT_V) {
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else UI_ThemeColor(TH_TRANSFORM);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
+
+ if (is_moving) {
+ float vec[3];
+ vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
+ vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
+ vec[2] = 0.0f;
+ normalize_v3(vec);
+ mul_v3_fl(vec, 1.2f * size);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.0f);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+ glPopMatrix();
+
+
+ ortho = is_orthogonal_m4(rv3d->twmat);
+
+ /* apply the transform delta */
+ if (is_moving) {
+ copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
+ // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
+ if (ortho) {
+ glMultMatrixf(matt);
+ glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
+ }
+ }
+ else {
+ if (ortho) {
+ glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
+ glMultMatrixf(rv3d->twmat);
+ }
+ }
+
+ /* axes */
+ if (arcs == 0) {
+ if (selectionbase == -1) {
+ if ((combo & V3D_MANIP_SCALE) == 0) {
+ /* axis */
+ if ((drawflags & MAN_ROT_X) || (is_moving && (drawflags & MAN_ROT_Z))) {
+ preOrthoFront(ortho, rv3d->twmat, 2);
+ manipulator_setcolor(v3d, 'X', colcode, 255, (highlight & MAN_ROT_X) != 0);
+ glBegin(GL_LINES);
+ glVertex3f(0.2f, 0.0f, 0.0f);
+ glVertex3f(1.0f, 0.0f, 0.0f);
+ glEnd();
+ postOrtho(ortho);
+ }
+ if ((drawflags & MAN_ROT_Y) || (is_moving && (drawflags & MAN_ROT_X))) {
+ preOrthoFront(ortho, rv3d->twmat, 0);
+ manipulator_setcolor(v3d, 'Y', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.2f, 0.0f);
+ glVertex3f(0.0f, 1.0f, 0.0f);
+ glEnd();
+ postOrtho(ortho);
+ }
+ if ((drawflags & MAN_ROT_Z) || (is_moving && (drawflags & MAN_ROT_Y))) {
+ preOrthoFront(ortho, rv3d->twmat, 1);
+ manipulator_setcolor(v3d, 'Z', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+ glBegin(GL_LINES);
+ glVertex3f(0.0f, 0.0f, 0.2f);
+ glVertex3f(0.0f, 0.0f, 1.0f);
+ glEnd();
+ postOrtho(ortho);
+ }
+ }
+ }
+ }
+
+ if (arcs == 0 && is_moving) {
+
+ /* Z circle */
+ if (drawflags & MAN_ROT_Z) {
+ preOrthoFront(ortho, matt, 2);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Z', colcode, 255, (highlight & MAN_ROT_Z) != 0);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ postOrtho(ortho);
+ }
+ /* X circle */
+ if (drawflags & MAN_ROT_X) {
+ preOrthoFront(ortho, matt, 0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'X', colcode, 255, (highlight & MAN_ROT_X) != 0);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ postOrtho(ortho);
+ }
+ /* Y circle */
+ if (drawflags & MAN_ROT_Y) {
+ preOrthoFront(ortho, matt, 1);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Y', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ postOrtho(ortho);
+ }
+
+ if (arcs) glDisable(GL_CLIP_PLANE0);
+ }
+ // donut arcs
+ if (arcs) {
+ glEnable(GL_CLIP_PLANE0);
+
+ /* Z circle */
+ if (drawflags & MAN_ROT_Z) {
+ preOrthoFront(ortho, rv3d->twmat, 2);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Z', colcode, 255, (highlight & MAN_ROT_Z) != 0);
+ partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
+ postOrtho(ortho);
+ }
+ /* X circle */
+ if (drawflags & MAN_ROT_X) {
+ preOrthoFront(ortho, rv3d->twmat, 0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'X', colcode, 255, (highlight & MAN_ROT_X) != 0);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ postOrtho(ortho);
+ }
+ /* Y circle */
+ if (drawflags & MAN_ROT_Y) {
+ preOrthoFront(ortho, rv3d->twmat, 1);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Y', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ postOrtho(ortho);
+ }
+
+ glDisable(GL_CLIP_PLANE0);
+ }
+
+ if (arcs == 0) {
+
+ /* Z handle on X axis */
+ if (drawflags & MAN_ROT_Z) {
+ preOrthoFront(ortho, rv3d->twmat, 2);
+ glPushMatrix();
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Z', colcode, 255, (highlight & MAN_ROT_Z) != 0);
+
+ partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ postOrtho(ortho);
+ }
+
+ /* Y handle on X axis */
+ if (drawflags & MAN_ROT_Y) {
+ preOrthoFront(ortho, rv3d->twmat, 1);
+ glPushMatrix();
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Y', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glRotatef(90.0, 0.0, 0.0, 1.0);
+ partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ postOrtho(ortho);
+ }
+
+ /* X handle on Z axis */
+ if (drawflags & MAN_ROT_X) {
+ preOrthoFront(ortho, rv3d->twmat, 0);
+ glPushMatrix();
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'X', colcode, 255, (highlight & MAN_ROT_X) != 0);
+
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glRotatef(90.0, 0.0, 0.0, 1.0);
+ partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
+
+ glPopMatrix();
+ postOrtho(ortho);
+ }
+
+ }
+
+ /* restore */
+ glLoadMatrixf(rv3d->viewmat);
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+static void drawsolidcube(float size)
+{
+ const float cube[8][3] = {
+ {-1.0, -1.0, -1.0},
+ {-1.0, -1.0, 1.0},
+ {-1.0, 1.0, 1.0},
+ {-1.0, 1.0, -1.0},
+ { 1.0, -1.0, -1.0},
+ { 1.0, -1.0, 1.0},
+ { 1.0, 1.0, 1.0},
+ { 1.0, 1.0, -1.0},
+ };
+ float n[3] = {0.0f};
+
+ glPushMatrix();
+ glScalef(size, size, size);
+
+ glBegin(GL_QUADS);
+ n[0] = -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[1]); glVertex3fv(cube[2]); glVertex3fv(cube[3]);
+ n[0] = 0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[1] = -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[0]); glVertex3fv(cube[4]); glVertex3fv(cube[5]); glVertex3fv(cube[1]);
+ n[1] = 0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[0] = 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[4]); glVertex3fv(cube[7]); glVertex3fv(cube[6]); glVertex3fv(cube[5]);
+ n[0] = 0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[1] = 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[3]); glVertex3fv(cube[2]); glVertex3fv(cube[6]);
+ n[1] = 0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[2] = 1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[1]); glVertex3fv(cube[5]); glVertex3fv(cube[6]); glVertex3fv(cube[2]);
+ n[2] = 0;
+ glEnd();
+
+ glBegin(GL_QUADS);
+ n[2] = -1.0;
+ glNormal3fv(n);
+ glVertex3fv(cube[7]); glVertex3fv(cube[4]); glVertex3fv(cube[0]); glVertex3fv(cube[3]);
+ glEnd();
+
+ glPopMatrix();
+}
+
+
+static void draw_manipulator_scale(
+ View3D *v3d, RegionView3D *rv3d, const int drawflags, int highlight, const int combo, const int colcode,
+ const bool is_moving, const int selectionbase)
+{
+ float cywid = 0.25f * 0.01f * (float)U.tw_handlesize;
+ float cusize = cywid * 0.75f, dz;
+ int axis_order[3] = {2, 0, 1};
+ int i;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if ((drawflags & MAN_SCALE_C) == 0) return;
+
+ manipulator_axis_order(rv3d, axis_order);
+
+ glDisable(GL_DEPTH_TEST);
+
+ /* not in combo mode */
+ if ((combo & (V3D_MANIP_TRANSLATE | V3D_MANIP_ROTATE)) == 0) {
+ float size, unitmat[4][4];
+ int shift = 0; // XXX
+
+ /* center circle, do not add to selection when shift is pressed (planar constraint) */
+ if (selectionbase != -1 && shift == 0) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'C', colcode, 255, (highlight & MAN_SCALE_C) != 0);
+
+ glPushMatrix();
+ size = screen_aligned(rv3d, rv3d->twmat);
+ unit_m4(unitmat);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
+ glPopMatrix();
+
+ dz = 1.0;
+ }
+ else {
+ dz = 1.0f - 4.0f * cusize;
+ }
+
+ if (is_moving) {
+ float matt[4][4];
+
+ copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
+ // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
+ glMultMatrixf(matt);
+ glFrontFace(is_negative_m4(matt) ? GL_CW : GL_CCW);
+ }
+ else {
+ glMultMatrixf(rv3d->twmat);
+ glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
+ }
+
+ /* axis */
+
+ /* in combo mode, this is always drawn as first type */
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_SCALE_X, drawflags & MAN_SCALE_Y, drawflags & MAN_SCALE_Z,
+ axis_order, selectionbase, highlight);
+
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cube */
+ if (drawflags & MAN_SCALE_X) {
+ glTranslatef(dz, 0.0, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]), (highlight & MAN_SCALE_X) != 0);
+ drawsolidcube(cusize);
+ glTranslatef(-dz, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cube */
+ if (drawflags & MAN_SCALE_Y) {
+ glTranslatef(0.0, dz, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]), (highlight & MAN_SCALE_Y) != 0);
+ drawsolidcube(cusize);
+ glTranslatef(0.0, -dz, 0.0);
+ }
+ break;
+ case 2: /* Z cube */
+ if (drawflags & MAN_SCALE_Z) {
+ glTranslatef(0.0, 0.0, dz);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]), (highlight & MAN_SCALE_Z) != 0);
+ drawsolidcube(cusize);
+ glTranslatef(0.0, 0.0, -dz);
+ }
+ break;
+ }
+ }
+
+ /* if shiftkey, center point as last, for selectbuffer order */
+ if (selectionbase != -1) {
+ int shift = 0; // XXX
+
+ if (shift) {
+ glTranslatef(0.0, -dz, 0.0);
+ GPU_select_load_id(selectionbase);
+ glBegin(GL_POINTS);
+ glVertex3f(0.0, 0.0, 0.0);
+ glEnd();
+ }
+ }
+
+ /* restore */
+ glLoadMatrixf(rv3d->viewmat);
+
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+ glFrontFace(GL_CCW);
+}
+
+
+static void draw_cone(GLUquadricObj *qobj, float len, float width)
+{
+ glTranslatef(0.0, 0.0, -0.5f * len);
+ gluCylinder(qobj, width, 0.0, len, 8, 1);
+ gluQuadricOrientation(qobj, GLU_INSIDE);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ gluQuadricOrientation(qobj, GLU_OUTSIDE);
+ glTranslatef(0.0, 0.0, 0.5f * len);
+}
+
+static void draw_cylinder(GLUquadricObj *qobj, float len, float width)
+{
+
+ width *= 0.8f; // just for beauty
+
+ glTranslatef(0.0, 0.0, -0.5f * len);
+ gluCylinder(qobj, width, width, len, 8, 1);
+ gluQuadricOrientation(qobj, GLU_INSIDE);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ gluQuadricOrientation(qobj, GLU_OUTSIDE);
+ glTranslatef(0.0, 0.0, len);
+ gluDisk(qobj, 0.0, width, 8, 1);
+ glTranslatef(0.0, 0.0, -0.5f * len);
+}
+
+
+static void draw_manipulator_translate(
+ View3D *v3d, RegionView3D *rv3d, int drawflags, int highlightflags, int combo, int colcode,
+ const bool UNUSED(is_moving), const int selectionbase)
+{
+ GLUquadricObj *qobj;
+ float cylen = 0.01f * (float)U.tw_handlesize;
+ float cywid = 0.25f * cylen, dz, size;
+ float unitmat[4][4];
+ int shift = 0; // XXX
+ int axis_order[3] = {0, 1, 2};
+ int i;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if ((drawflags & MAN_TRANS_C) == 0) return;
+
+ manipulator_axis_order(rv3d, axis_order);
+
+ // XXX if (moving) glTranslatef(t->vec[0], t->vec[1], t->vec[2]);
+ glDisable(GL_DEPTH_TEST);
+
+ /* center circle, do not add to selection when shift is pressed (planar constraint) */
+ if (selectionbase != -1 && shift == 0) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'C', colcode, 255, (highlightflags & MAN_TRANS_C) != 0);
+
+ glPushMatrix();
+ size = screen_aligned(rv3d, rv3d->twmat);
+ unit_m4(unitmat);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
+ glPopMatrix();
+
+ glPushMatrix();
+ /* and now apply matrix, we move to local matrix drawing */
+ glMultMatrixf(rv3d->twmat);
+
+#if 0
+ // translate drawn as last, only axis when no combo with scale, or for ghosting
+ if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_TRANS_X, 0, drawflags & MAN_TRANS_Z,
+ axis_order, selectionbase, highlightflags);
+ }
+
+ /* offset in combo mode, for rotate a bit more */
+ if (combo & (V3D_MANIP_ROTATE)) dz = 1.0f + 2.0f * cylen;
+ else if (combo & (V3D_MANIP_SCALE)) dz = 1.0f + 0.5f * cylen;
+ else dz = 1.0f;
+
+ qobj = gluNewQuadric();
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* Z Cone */
+ if (drawflags & MAN_TRANS_Z) {
+ glPushMatrix();
+ glTranslatef(0.0, 0.0, dz);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]), (highlightflags & MAN_TRANS_Z) != 0);
+ draw_cone(qobj, cylen, cywid);
+ glPopMatrix();
+ }
+ break;
+ case 1: /* X Cone */
+ if (drawflags & MAN_TRANS_X) {
+ glPushMatrix();
+ glTranslatef(dz, 0.0, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]), (highlightflags & MAN_TRANS_X) != 0);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ draw_cone(qobj, cylen, cywid);
+ glPopMatrix();
+ }
+ break;
+ case 2: /* Y Cone */
+ if (drawflags & MAN_TRANS_Y) {
+ glPushMatrix();
+ glTranslatef(0.0, dz, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]), (highlightflags & MAN_TRANS_Y) != 0);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ draw_cone(qobj, cylen, cywid);
+ glPopMatrix();
+ }
+ break;
+ }
+ }
+
+ gluDeleteQuadric(qobj);
+#endif
+
+ glPopMatrix();
+
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+static void draw_manipulator_rotate_cyl(
+ View3D *v3d, RegionView3D *rv3d, int drawflags, int highlight, const int combo, const int colcode,
+ const bool is_moving, const int selectionbase)
+{
+ GLUquadricObj *qobj;
+ float size;
+ float cylen = 0.01f * (float)U.tw_handlesize;
+ float cywid = 0.25f * cylen;
+ int axis_order[3] = {2, 0, 1};
+ int i;
+
+ /* when called while moving in mixed mode, do not draw when... */
+ if ((drawflags & MAN_ROT_C) == 0) return;
+
+ manipulator_axis_order(rv3d, axis_order);
+
+ /* prepare for screen aligned draw */
+ glPushMatrix();
+ size = screen_aligned(rv3d, rv3d->twmat);
+
+ glDisable(GL_DEPTH_TEST);
+
+ qobj = gluNewQuadric();
+
+ /* Screen aligned view rot circle */
+ if (drawflags & MAN_ROT_V) {
+ float unitmat[4][4];
+
+ unit_m4(unitmat);
+
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ UI_ThemeColor(TH_TRANSFORM);
+ drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
+
+ if (is_moving) {
+ float vec[3];
+ vec[0] = 0; // XXX (float)(t->imval[0] - t->center2d[0]);
+ vec[1] = 0; // XXX (float)(t->imval[1] - t->center2d[1]);
+ vec[2] = 0.0f;
+ normalize_v3(vec);
+ mul_v3_fl(vec, 1.2f * size);
+ glBegin(GL_LINES);
+ glVertex3f(0.0, 0.0, 0.0);
+ glVertex3fv(vec);
+ glEnd();
+ }
+ }
+ glPopMatrix();
+
+ /* apply the transform delta */
+ if (is_moving) {
+ float matt[4][4];
+ copy_m4_m4(matt, rv3d->twmat); // to copy the parts outside of [3][3]
+ // XXX if (t->flag & T_USES_MANIPULATOR) {
+ // XXX mul_m4_m3m4(matt, t->mat, rv3d->twmat);
+ // XXX }
+ glMultMatrixf(matt);
+ }
+ else {
+ glMultMatrixf(rv3d->twmat);
+ }
+
+ glFrontFace(is_negative_m4(rv3d->twmat) ? GL_CW : GL_CCW);
+
+ /* axis */
+ if (selectionbase != -1) {
+
+ // only draw axis when combo didn't draw scale axes
+ if ((combo & V3D_MANIP_SCALE) == 0) {
+ draw_manipulator_axes(v3d, rv3d, colcode,
+ drawflags & MAN_ROT_X, drawflags & MAN_ROT_Y, drawflags & MAN_ROT_Z,
+ axis_order, selectionbase, highlight);
+ }
+
+ /* only has to be set when not in picking */
+ gluQuadricDrawStyle(qobj, GLU_FILL);
+ }
+
+ for (i = 0; i < 3; i++) {
+ switch (axis_order[i]) {
+ case 0: /* X cylinder */
+ if (drawflags & MAN_ROT_X) {
+ glTranslatef(1.0, 0.0, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ glRotatef(90.0, 0.0, 1.0, 0.0);
+ manipulator_setcolor(v3d, 'X', colcode, 255, (highlight & MAN_ROT_X) != 0);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(-90.0, 0.0, 1.0, 0.0);
+ glTranslatef(-1.0, 0.0, 0.0);
+ }
+ break;
+ case 1: /* Y cylinder */
+ if (drawflags & MAN_ROT_Y) {
+ glTranslatef(0.0, 1.0, 0.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ glRotatef(-90.0, 1.0, 0.0, 0.0);
+ manipulator_setcolor(v3d, 'Y', colcode, 255, (highlight & MAN_ROT_Y) != 0);
+ draw_cylinder(qobj, cylen, cywid);
+ glRotatef(90.0, 1.0, 0.0, 0.0);
+ glTranslatef(0.0, -1.0, 0.0);
+ }
+ break;
+ case 2: /* Z cylinder */
+ if (drawflags & MAN_ROT_Z) {
+ glTranslatef(0.0, 0.0, 1.0);
+ if (selectionbase != -1) GPU_select_load_id(selectionbase);
+ manipulator_setcolor(v3d, 'Z', colcode, 255, (highlight & MAN_ROT_Z) != 0);
+ draw_cylinder(qobj, cylen, cywid);
+ glTranslatef(0.0, 0.0, -1.0);
+ }
+ break;
+ }
+ }
+
+ /* restore */
+
+ gluDeleteQuadric(qobj);
+ glLoadMatrixf(rv3d->viewmat);
+
+ if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
+
+}
+
+
+/* ********************************************* */
+
+/* main call, does calc centers & orientation too */
+static int drawflags = 0xFFFF; // only for the calls below, belongs in scene...?
+
+static int manipulator_flags_from_active(int active)
+{
+ int val;
+
+ if (active != -1) {
+ if (active == MAN_SEL_TRANS_C) {
+ val = MAN_TRANS_C;
+ }
+ else if (active == MAN_SEL_SCALE_C) {
+ val = MAN_SCALE_C;
+ }
+ else {
+ val = 1 << active;
+ }
+ }
+ else
+ val = 0;
+
+ return val;
+}
+
+void WIDGET_manipulator_draw(wmWidget *UNUSED(widget), const bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+
+ if (v3d->twflag & V3D_DRAW_MANIPULATOR) {
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+
+ if (G.debug_value == 3) {
+ if (G.moving & (G_TRANSFORM_OBJ | G_TRANSFORM_EDIT))
+ draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, 0, v3d->twtype, MAN_MOVECOL, true, -1);
+ else
+ draw_manipulator_rotate_cyl(v3d, rv3d, drawflags, 0, v3d->twtype, MAN_RGB, false, -1);
+ }
+ else {
+ draw_manipulator_rotate(v3d, rv3d, drawflags, 0, v3d->twtype, false, -1);
+ }
+ }
+ if (v3d->twtype & V3D_MANIP_SCALE) {
+ draw_manipulator_scale(v3d, rv3d, drawflags, 0, v3d->twtype, MAN_RGB, false, -1);
+ }
+ if (v3d->twtype & V3D_MANIP_TRANSLATE) {
+ draw_manipulator_translate(v3d, rv3d, drawflags, 0, v3d->twtype, MAN_RGB, false, -1);
+ }
+
+ glDisable(GL_BLEND);
+ }
+}
+
+void WIDGETGROUP_manipulator_update(struct wmWidgetGroup *wgroup, const struct bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ ManipulatorGroup *manipulator = WM_widgetgroup_customdata(wgroup);
+
+ int totsel;
+
+ v3d->twflag &= ~V3D_DRAW_MANIPULATOR;
+
+ totsel = calc_manipulator_stats(C);
+ if (totsel == 0) {
+ WM_widget_set_draw(manipulator->translate_x, false);
+ WM_widget_set_draw(manipulator->translate_y, false);
+ WM_widget_set_draw(manipulator->translate_z, false);
+
+ WM_widget_set_draw(manipulator->rotate_x, false);
+ WM_widget_set_draw(manipulator->rotate_y, false);
+ WM_widget_set_draw(manipulator->rotate_z, false);
+ return;
+ }
+ v3d->twflag |= V3D_DRAW_MANIPULATOR;
+
+ /* now we can define center */
+ switch (v3d->around) {
+ case V3D_CENTER:
+ case V3D_ACTIVE:
+ {
+ Object *ob;
+ if (((v3d->around == V3D_ACTIVE) && (scene->obedit == NULL)) &&
+ ((ob = OBACT) && !(ob->mode & OB_MODE_POSE)))
+ {
+ copy_v3_v3(rv3d->twmat[3], ob->obmat[3]);
+ }
+ else {
+ mid_v3_v3v3(rv3d->twmat[3], scene->twmin, scene->twmax);
+ }
+ break;
+ }
+ case V3D_LOCAL:
+ case V3D_CENTROID:
+ copy_v3_v3(rv3d->twmat[3], scene->twcent);
+ break;
+ case V3D_CURSOR:
+ copy_v3_v3(rv3d->twmat[3], ED_view3d_cursor3d_get(scene, v3d));
+ break;
+ }
+
+ mul_mat3_m4_fl(rv3d->twmat, ED_view3d_pixel_size(rv3d, rv3d->twmat[3]) * U.tw_size);
+
+ /* when looking through a selected camera, the manipulator can be at the
+ * exact same position as the view, skip so we don't break selection */
+ if (fabsf(mat4_to_scale(rv3d->twmat)) < 1e-7f) {
+ WM_widget_set_draw(manipulator->translate_x, false);
+ WM_widget_set_draw(manipulator->translate_y, false);
+ WM_widget_set_draw(manipulator->translate_z, false);
+
+ WM_widget_set_draw(manipulator->rotate_x, false);
+ WM_widget_set_draw(manipulator->rotate_y, false);
+ WM_widget_set_draw(manipulator->rotate_z, false);
+
+ return;
+ }
+
+ test_manipulator_axis(C);
+ drawflags = rv3d->twdrawflag; /* set in calc_manipulator_stats */
+
+ WM_widget_operator(manipulator->translate_x, WIDGET_manipulator_handler_trans, "TRANSFORM_OT_translate", NULL);
+ WM_widget_operator(manipulator->translate_y, WIDGET_manipulator_handler_trans, "TRANSFORM_OT_translate", NULL);
+ WM_widget_operator(manipulator->translate_z, WIDGET_manipulator_handler_trans, "TRANSFORM_OT_translate", NULL);
+ WM_widget_operator(manipulator->rotate_x, WIDGET_manipulator_handler_rot, "TRANSFORM_OT_rotate", NULL);
+ WM_widget_operator(manipulator->rotate_y, WIDGET_manipulator_handler_rot, "TRANSFORM_OT_rotate", NULL);
+ WM_widget_operator(manipulator->rotate_z, WIDGET_manipulator_handler_rot, "TRANSFORM_OT_rotate", NULL);
+
+ if (v3d->twtype & V3D_MANIP_TRANSLATE) {
+ /* should be added according to the order of axis */
+ WM_widget_set_origin(manipulator->translate_x, rv3d->twmat[3]);
+ WIDGET_arrow_set_direction(manipulator->translate_x, rv3d->twmat[0]);
+
+ WM_widget_set_origin(manipulator->translate_y, rv3d->twmat[3]);
+ WIDGET_arrow_set_direction(manipulator->translate_y, rv3d->twmat[1]);
+
+ WM_widget_set_origin(manipulator->translate_z, rv3d->twmat[3]);
+ WIDGET_arrow_set_direction(manipulator->translate_z, rv3d->twmat[2]);
+
+ WM_widget_set_draw(manipulator->translate_x, true);
+ WM_widget_set_draw(manipulator->translate_y, true);
+ WM_widget_set_draw(manipulator->translate_z, true);
+ }
+ else {
+ WM_widget_set_draw(manipulator->translate_x, false);
+ WM_widget_set_draw(manipulator->translate_y, false);
+ WM_widget_set_draw(manipulator->translate_z, false);
+ }
+
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+ /* should be added according to the order of axis */
+
+ WM_widget_set_origin(manipulator->rotate_x, rv3d->twmat[3]);
+ WIDGET_dial_set_direction(manipulator->rotate_x, rv3d->twmat[0]);
+
+ WM_widget_set_origin(manipulator->rotate_y, rv3d->twmat[3]);
+ WIDGET_dial_set_direction(manipulator->rotate_y, rv3d->twmat[1]);
+
+ WM_widget_set_origin(manipulator->rotate_z, rv3d->twmat[3]);
+ WIDGET_dial_set_direction(manipulator->rotate_z, rv3d->twmat[2]);
+
+ WM_widget_set_draw(manipulator->rotate_x, true);
+ WM_widget_set_draw(manipulator->rotate_y, true);
+ WM_widget_set_draw(manipulator->rotate_z, true);
+ }
+ else {
+ WM_widget_set_draw(manipulator->rotate_x, false);
+ WM_widget_set_draw(manipulator->rotate_y, false);
+ WM_widget_set_draw(manipulator->rotate_z, false);
+ }
+}
+
+
+bool WIDGETGROUP_manipulator_poll(wmWidgetGroup *UNUSED(wgroup), const struct bContext *C)
+{
+ /* it's a given we only use this in 3D view */
+ ScrArea *sa = CTX_wm_area(C);
+ View3D *v3d = sa->spacedata.first;
+
+ return ((v3d->twflag & V3D_USE_MANIPULATOR) != 0);
+}
+
+void WIDGET_manipulator_render_3d_intersect(const bContext *C, wmWidget *UNUSED(widget), int selectionbase)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ View3D *v3d = sa->spacedata.first;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = ar->regiondata;
+
+ /* do the drawing */
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+ //if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, 0, v3d->twtype, MAN_RGB, false, selectionbase);
+ //else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, 0, v3d->twtype, false, selectionbase);
+ }
+ if (v3d->twtype & V3D_MANIP_SCALE)
+ draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, 0, v3d->twtype, MAN_RGB, false, selectionbase);
+ //if (v3d->twtype & V3D_MANIP_TRANSLATE)
+ // draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, 0, v3d->twtype, MAN_RGB, false, selectionbase);
+}
+
+/* return 0; nothing happened */
+int WIDGET_manipulator_handler(bContext *C, const struct wmEvent *event, wmWidget *UNUSED(widget), wmOperator *op)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ View3D *v3d = sa->spacedata.first;
+ int constraint_axis[3] = {0, 0, 0};
+ int val;
+ int shift = event->shift;
+
+ struct IDProperty *properties = NULL; /* operator properties, assigned to ptr->data and can be written to a file */
+ struct PointerRNA *ptr = NULL; /* rna pointer to access properties */
+
+ val = manipulator_flags_from_active(0);
+
+ if (!((v3d->twflag & V3D_USE_MANIPULATOR) && (v3d->twflag & V3D_DRAW_MANIPULATOR)) ||
+ !(event->keymodifier == 0 || event->keymodifier == KM_SHIFT) ||
+ !((event->val == KM_PRESS) && (event->type == LEFTMOUSE)))
+ {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ if (val) {
+ if (val & MAN_TRANS_C) {
+ switch (val) {
+ case MAN_TRANS_C:
+ break;
+ case MAN_TRANS_X:
+ if (shift) {
+ constraint_axis[1] = 1;
+ constraint_axis[2] = 1;
+ }
+ else
+ constraint_axis[0] = 1;
+ break;
+ case MAN_TRANS_Y:
+ if (shift) {
+ constraint_axis[0] = 1;
+ constraint_axis[2] = 1;
+ }
+ else
+ constraint_axis[1] = 1;
+ break;
+ case MAN_TRANS_Z:
+ if (shift) {
+ constraint_axis[0] = 1;
+ constraint_axis[1] = 1;
+ }
+ else
+ constraint_axis[2] = 1;
+ break;
+ }
+ WM_operator_properties_alloc(&ptr, &properties, "TRANSFORM_OT_translate");
+ /* Force orientation */
+ RNA_boolean_set(ptr, "release_confirm", true);
+ RNA_enum_set(ptr, "constraint_orientation", v3d->twmode);
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
+ WM_operator_name_call(C, "TRANSFORM_OT_translate", WM_OP_INVOKE_DEFAULT, ptr);
+ }
+ else if (val & MAN_SCALE_C) {
+ switch (val) {
+ case MAN_SCALE_X:
+ if (shift) {
+ constraint_axis[1] = 1;
+ constraint_axis[2] = 1;
+ }
+ else
+ constraint_axis[0] = 1;
+ break;
+ case MAN_SCALE_Y:
+ if (shift) {
+ constraint_axis[0] = 1;
+ constraint_axis[2] = 1;
+ }
+ else
+ constraint_axis[1] = 1;
+ break;
+ case MAN_SCALE_Z:
+ if (shift) {
+ constraint_axis[0] = 1;
+ constraint_axis[1] = 1;
+ }
+ else
+ constraint_axis[2] = 1;
+ break;
+ }
+ WM_operator_properties_alloc(&ptr, &properties, "TRANSFORM_OT_resize");
+ /* Force orientation */
+ RNA_boolean_set(ptr, "release_confirm", true);
+ RNA_enum_set(ptr, "constraint_orientation", v3d->twmode);
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
+ WM_operator_name_call(C, "TRANSFORM_OT_resize", WM_OP_INVOKE_DEFAULT, ptr);
+ }
+ else if (val == MAN_ROT_T) { /* trackball need special case, init is different */
+ /* Do not pass op->ptr!!! trackball has no "constraint" properties!
+ * See [#34621], it's a miracle it did not cause more problems!!! */
+ /* However, we need to copy the "release_confirm" property, but only if defined, see T41112. */
+ PointerRNA props_ptr;
+ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true);
+ WM_operator_properties_create_ptr(&props_ptr, ot);
+ RNA_boolean_set(&props_ptr, "release_confirm", true);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr);
+ WM_operator_properties_free(&props_ptr);
+ }
+ else if (val & MAN_ROT_C) {
+ switch (val) {
+ case MAN_ROT_X:
+ constraint_axis[0] = 1;
+ break;
+ case MAN_ROT_Y:
+ constraint_axis[1] = 1;
+ break;
+ case MAN_ROT_Z:
+ constraint_axis[2] = 1;
+ break;
+ }
+ WM_operator_properties_alloc(&ptr, &properties, "TRANSFORM_OT_rotate");
+ /* Force orientation */
+ RNA_boolean_set(ptr, "release_confirm", true);
+ RNA_enum_set(ptr, "constraint_orientation", v3d->twmode);
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
+ WM_operator_name_call(C, "TRANSFORM_OT_rotate", WM_OP_INVOKE_DEFAULT, ptr);
+ }
+ }
+
+ if (ptr) {
+ WM_operator_properties_free(ptr);
+ MEM_freeN(ptr);
+ }
+
+ return (val) ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
+}
+
+/* return 0; nothing happened */
+int WIDGET_manipulator_handler_trans(bContext *C, const struct wmEvent *event, wmWidget *widget, struct PointerRNA *ptr)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ View3D *v3d = sa->spacedata.first;
+ int constraint_axis[3] = {0, 0, 0};
+ int shift = event->shift;
+ int direction = GET_INT_FROM_POINTER(WM_widget_customdata(widget));
+
+ if (!((v3d->twflag & V3D_USE_MANIPULATOR) && (v3d->twflag & V3D_DRAW_MANIPULATOR)) ||
+ !(event->keymodifier == 0 || event->keymodifier == KM_SHIFT))
+ {
+ ;//return OPERATOR_PASS_THROUGH;
+ }
+
+ if (shift) {
+ int d = 0;
+ for (; d < 3; d++) {
+ if (d != direction)
+ constraint_axis[d] = 1;
+ }
+ }
+ else
+ constraint_axis[direction] = 1;
+
+ /* Force orientation */
+ RNA_boolean_set(ptr, "release_confirm", true);
+ RNA_enum_set(ptr, "constraint_orientation", v3d->twmode);
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
+ RNA_boolean_set(ptr, "use_widget_input", true);
+
+ return OPERATOR_FINISHED;
+}
+
+/* return 0; nothing happened */
+int WIDGET_manipulator_handler_rot(bContext *C, const struct wmEvent *UNUSED(event), wmWidget *widget, struct PointerRNA *ptr)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ View3D *v3d = sa->spacedata.first;
+ int constraint_axis[3] = {0, 0, 0};
+ int direction = GET_INT_FROM_POINTER(WM_widget_customdata(widget));
+
+ if (!(v3d->twflag & V3D_USE_MANIPULATOR) && (v3d->twflag & V3D_DRAW_MANIPULATOR))
+ {
+ ;//return OPERATOR_PASS_THROUGH;
+ }
+
+ constraint_axis[direction] = 1;
+
+ /* Force orientation */
+ RNA_boolean_set(ptr, "release_confirm", true);
+ RNA_enum_set(ptr, "constraint_orientation", v3d->twmode);
+ RNA_boolean_set_array(ptr, "constraint_axis", constraint_axis);
+ RNA_boolean_set(ptr, "use_widget_input", true);
+
+ return OPERATOR_FINISHED;
+}
+
+void WIDGETGROUP_manipulator_free(struct wmWidgetGroup *wgroup)
+{
+ ManipulatorGroup *manipulator = WM_widgetgroup_customdata(wgroup);
+
+ MEM_freeN(manipulator);
+}
+
+void WIDGETGROUP_manipulator_create(struct wmWidgetGroup *wgroup)
+{
+ float color_green[4] = {0.0f, 1.0f, 0.0f, 1.0f};
+ float color_red[4] = {1.0f, 0.0f, 0.0f, 1.0f};
+ float color_blue[4] = {0.0f, 0.0f, 1.0f, 1.0f};
+
+ wmWidget *widget = NULL;
+
+ ManipulatorGroup *manipulator = MEM_callocN(sizeof(ManipulatorGroup), "manipulator_data");
+
+ widget = WM_widget_new(WIDGET_manipulator_draw,
+ WIDGET_manipulator_render_3d_intersect,
+ NULL,
+ WIDGET_manipulator_handler,
+ NULL, false);
+
+ WM_widget_register(wgroup, widget);
+
+ manipulator->translate_x = WIDGET_arrow_new(0, NULL);
+ WIDGET_arrow_set_color(manipulator->translate_x, color_red);
+ WM_widget_register(wgroup, manipulator->translate_x);
+
+ manipulator->translate_y = WIDGET_arrow_new(0, SET_INT_IN_POINTER(1));
+ WIDGET_arrow_set_color(manipulator->translate_y, color_green);
+ WM_widget_register(wgroup, manipulator->translate_y);
+
+ manipulator->translate_z = WIDGET_arrow_new(0, SET_INT_IN_POINTER(2));
+ WIDGET_arrow_set_color(manipulator->translate_z, color_blue);
+ WM_widget_register(wgroup, manipulator->translate_z);
+
+ manipulator->rotate_x = WIDGET_dial_new(UI_DIAL_STYLE_RING_CLIPPED, NULL);
+ WIDGET_dial_set_color(manipulator->rotate_x, color_red);
+ WM_widget_register(wgroup, manipulator->rotate_x);
+
+ manipulator->rotate_y = WIDGET_dial_new(UI_DIAL_STYLE_RING_CLIPPED, SET_INT_IN_POINTER(1));
+ WIDGET_dial_set_color(manipulator->rotate_y, color_green);
+ WM_widget_register(wgroup, manipulator->rotate_y);
+
+ manipulator->rotate_z = WIDGET_dial_new(UI_DIAL_STYLE_RING_CLIPPED, SET_INT_IN_POINTER(2));
+ WIDGET_dial_set_color(manipulator->rotate_z, color_blue);
+ WM_widget_register(wgroup, manipulator->rotate_z);
+
+ WM_widgetgroup_customdata_set(wgroup, manipulator);
+}
+