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:
authorYimingWu <xp8110@outlook.com>2020-05-16 18:08:40 +0300
committerYimingWu <xp8110@outlook.com>2020-05-16 18:08:40 +0300
commitcd54abd2c1316136753f7bbe227bd762a5f9e7d9 (patch)
tree69f2a4a1a5013acc78213bb4f3fe888912380ea4 /source/blender/editors/transform
parentf7770cb97bb9d19d0806f67da9377129fd4d09b0 (diff)
parenteaf7d36d66e551c3262d69f472b4028aeccb7e97 (diff)
Merge remote-tracking branch 'origin/master' into temp-lanpr-review
Diffstat (limited to 'source/blender/editors/transform')
-rw-r--r--source/blender/editors/transform/CMakeLists.txt33
-rw-r--r--source/blender/editors/transform/transform.c7460
-rw-r--r--source/blender/editors/transform/transform.h221
-rw-r--r--source/blender/editors/transform/transform_constraints.c52
-rw-r--r--source/blender/editors/transform/transform_constraints.h48
-rw-r--r--source/blender/editors/transform/transform_convert.c599
-rw-r--r--source/blender/editors/transform/transform_convert.h41
-rw-r--r--source/blender/editors/transform/transform_convert_action.c16
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c275
-rw-r--r--source/blender/editors/transform/transform_convert_cursor.c2
-rw-r--r--source/blender/editors/transform/transform_convert_curve.c10
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c20
-rw-r--r--source/blender/editors/transform/transform_convert_graph.c18
-rw-r--r--source/blender/editors/transform/transform_convert_lattice.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mask.c6
-rw-r--r--source/blender/editors/transform/transform_convert_mball.c1
-rw-r--r--source/blender/editors/transform/transform_convert_mesh.c155
-rw-r--r--source/blender/editors/transform/transform_convert_nla.c12
-rw-r--r--source/blender/editors/transform/transform_convert_node.c4
-rw-r--r--source/blender/editors/transform/transform_convert_object.c166
-rw-r--r--source/blender/editors/transform/transform_convert_paintcurve.c1
-rw-r--r--source/blender/editors/transform/transform_convert_particle.c3
-rw-r--r--source/blender/editors/transform/transform_convert_sculpt.c5
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer.c98
-rw-r--r--source/blender/editors/transform/transform_convert_tracking.c6
-rw-r--r--source/blender/editors/transform/transform_draw_cursors.c10
-rw-r--r--source/blender/editors/transform/transform_generics.c431
-rw-r--r--source/blender/editors/transform/transform_gizmo_2d.c102
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c144
-rw-r--r--source/blender/editors/transform/transform_gizmo_extrude_3d.c14
-rw-r--r--source/blender/editors/transform/transform_input.c108
-rw-r--r--source/blender/editors/transform/transform_mode.c1264
-rw-r--r--source/blender/editors/transform/transform_mode.h160
-rw-r--r--source/blender/editors/transform/transform_mode_align.c96
-rw-r--r--source/blender/editors/transform/transform_mode_baketime.c140
-rw-r--r--source/blender/editors/transform/transform_mode_bbone_resize.c184
-rw-r--r--source/blender/editors/transform/transform_mode_bend.c308
-rw-r--r--source/blender/editors/transform/transform_mode_boneenvelope.c121
-rw-r--r--source/blender/editors/transform/transform_mode_boneroll.c115
-rw-r--r--source/blender/editors/transform/transform_mode_curveshrinkfatten.c124
-rw-r--r--source/blender/editors/transform/transform_mode_edge_bevelweight.c130
-rw-r--r--source/blender/editors/transform/transform_mode_edge_crease.c134
-rw-r--r--source/blender/editors/transform/transform_mode_edge_rotate_normal.c156
-rw-r--r--source/blender/editors/transform/transform_mode_edge_seq_slide.c147
-rw-r--r--source/blender/editors/transform/transform_mode_edge_slide.c1498
-rw-r--r--source/blender/editors/transform/transform_mode_gpopacity.c120
-rw-r--r--source/blender/editors/transform/transform_mode_gpshrinkfatten.c122
-rw-r--r--source/blender/editors/transform/transform_mode_maskshrinkfatten.c154
-rw-r--r--source/blender/editors/transform/transform_mode_mirror.c129
-rw-r--r--source/blender/editors/transform/transform_mode_push_pull.c137
-rw-r--r--source/blender/editors/transform/transform_mode_resize.c170
-rw-r--r--source/blender/editors/transform/transform_mode_rotate.c198
-rw-r--r--source/blender/editors/transform/transform_mode_shear.c248
-rw-r--r--source/blender/editors/transform/transform_mode_shrink_fatten.c146
-rw-r--r--source/blender/editors/transform/transform_mode_skin_resize.c141
-rw-r--r--source/blender/editors/transform/transform_mode_tilt.c119
-rw-r--r--source/blender/editors/transform/transform_mode_timescale.c158
-rw-r--r--source/blender/editors/transform/transform_mode_timeslide.c236
-rw-r--r--source/blender/editors/transform/transform_mode_timetranslate.c167
-rw-r--r--source/blender/editors/transform/transform_mode_tosphere.c139
-rw-r--r--source/blender/editors/transform/transform_mode_trackball.c170
-rw-r--r--source/blender/editors/transform/transform_mode_translate.c412
-rw-r--r--source/blender/editors/transform/transform_mode_vert_slide.c666
-rw-r--r--source/blender/editors/transform/transform_ops.c71
-rw-r--r--source/blender/editors/transform/transform_orientations.c80
-rw-r--r--source/blender/editors/transform/transform_snap.c111
-rw-r--r--source/blender/editors/transform/transform_snap.h8
-rw-r--r--source/blender/editors/transform/transform_snap_object.c635
68 files changed, 10399 insertions, 8777 deletions
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 6f39a8c3b9c..afa7b02a1f6 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -65,14 +65,47 @@ set(SRC
transform_gizmo_3d.c
transform_gizmo_extrude_3d.c
transform_input.c
+ transform_mode.c
+ transform_mode_align.c
+ transform_mode_baketime.c
+ transform_mode_bbone_resize.c
+ transform_mode_bend.c
+ transform_mode_boneenvelope.c
+ transform_mode_boneroll.c
+ transform_mode_curveshrinkfatten.c
+ transform_mode_edge_bevelweight.c
+ transform_mode_edge_crease.c
+ transform_mode_edge_rotate_normal.c
+ transform_mode_edge_seq_slide.c
+ transform_mode_edge_slide.c
+ transform_mode_gpopacity.c
+ transform_mode_gpshrinkfatten.c
+ transform_mode_maskshrinkfatten.c
+ transform_mode_mirror.c
+ transform_mode_push_pull.c
+ transform_mode_resize.c
+ transform_mode_rotate.c
+ transform_mode_shear.c
+ transform_mode_shrink_fatten.c
+ transform_mode_skin_resize.c
+ transform_mode_tilt.c
+ transform_mode_timescale.c
+ transform_mode_timeslide.c
+ transform_mode_timetranslate.c
+ transform_mode_tosphere.c
+ transform_mode_trackball.c
+ transform_mode_translate.c
+ transform_mode_vert_slide.c
transform_ops.c
transform_orientations.c
transform_snap.c
transform_snap_object.c
transform.h
+ transform_constraints.h
transform_convert.h
transform_draw_cursors.h
+ transform_mode.h
transform_snap.h
)
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index ec39b457082..8e3ad55bae1 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -22,220 +22,70 @@
*/
#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <float.h>
#include "MEM_guardedalloc.h"
-#include "DNA_anim_types.h"
-#include "DNA_armature_types.h"
-#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
#include "DNA_mesh_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_scene_types.h" /* PET modes */
-#include "DNA_workspace_types.h"
-#include "DNA_gpencil_types.h"
-#include "BLI_alloca.h"
-#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BLI_ghash.h"
-#include "BLI_utildefines_stack.h"
-#include "BLI_memarena.h"
-#include "BKE_nla.h"
-#include "BKE_editmesh.h"
-#include "BKE_editmesh_bvh.h"
#include "BKE_context.h"
-#include "BKE_constraint.h"
-#include "BKE_particle.h"
-#include "BKE_unit.h"
-#include "BKE_scene.h"
+#include "BKE_editmesh.h"
#include "BKE_mask.h"
-#include "BKE_mesh.h"
-#include "BKE_report.h"
-#include "BKE_workspace.h"
-
-#include "DEG_depsgraph.h"
+#include "BKE_scene.h"
-#include "GPU_immediate.h"
-#include "GPU_matrix.h"
#include "GPU_state.h"
+#include "ED_clip.h"
+#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_keyframing.h"
-#include "ED_screen.h"
-#include "ED_space_api.h"
-#include "ED_view3d.h"
-#include "ED_mesh.h"
-#include "ED_clip.h"
#include "ED_node.h"
-#include "ED_gpencil.h"
+#include "ED_screen.h"
#include "ED_sculpt.h"
+#include "ED_space_api.h"
-#include "WM_types.h"
#include "WM_api.h"
+#include "WM_types.h"
-#include "UI_view2d.h"
-#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "RNA_access.h"
-#include "RNA_define.h"
#include "BLF_api.h"
#include "BLT_translation.h"
#include "transform.h"
+#include "transform_constraints.h"
#include "transform_convert.h"
#include "transform_draw_cursors.h"
+#include "transform_mode.h"
#include "transform_snap.h"
/* Disabling, since when you type you know what you are doing,
* and being able to set it to zero is handy. */
// #define USE_NUM_NO_ZERO
-static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
-static void doEdgeSlide(TransInfo *t, float perc);
-static void doVertSlide(TransInfo *t, float perc);
-
-static void drawEdgeSlide(TransInfo *t);
-static void drawVertSlide(TransInfo *t);
-static void postInputRotation(TransInfo *t, float values[3]);
+static void drawTransformApply(const struct bContext *C, ARegion *region, void *arg);
-static void ElementRotation(
- TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
static void initSnapSpatial(TransInfo *t, float r_snap[3]);
-static void storeCustomLNorValue(TransDataContainer *t, BMesh *bm);
-
-/* Transform Callbacks */
-static void initBend(TransInfo *t);
-static eRedrawFlag handleEventBend(TransInfo *t, const struct wmEvent *event);
-static void Bend(TransInfo *t, const int mval[2]);
-
-static void initShear(TransInfo *t);
-static eRedrawFlag handleEventShear(TransInfo *t, const struct wmEvent *event);
-static void applyShear(TransInfo *t, const int mval[2]);
-
-static void initResize(TransInfo *t);
-static void applyResize(TransInfo *t, const int mval[2]);
-
-static void initSkinResize(TransInfo *t);
-static void applySkinResize(TransInfo *t, const int mval[2]);
-
-static void initTranslation(TransInfo *t);
-static void applyTranslation(TransInfo *t, const int mval[2]);
-
-static void initToSphere(TransInfo *t);
-static void applyToSphere(TransInfo *t, const int mval[2]);
-
-static void initRotation(TransInfo *t);
-static void applyRotation(TransInfo *t, const int mval[2]);
-
-static void initNormalRotation(TransInfo *t);
-static void applyNormalRotation(TransInfo *t, const int mval[2]);
-
-static void initShrinkFatten(TransInfo *t);
-static void applyShrinkFatten(TransInfo *t, const int mval[2]);
-
-static void initTilt(TransInfo *t);
-static void applyTilt(TransInfo *t, const int mval[2]);
-
-static void initCurveShrinkFatten(TransInfo *t);
-static void applyCurveShrinkFatten(TransInfo *t, const int mval[2]);
-
-static void initMaskShrinkFatten(TransInfo *t);
-static void applyMaskShrinkFatten(TransInfo *t, const int mval[2]);
-
-static void initGPShrinkFatten(TransInfo *t);
-static void applyGPShrinkFatten(TransInfo *t, const int mval[2]);
-
-static void initTrackball(TransInfo *t);
-static void applyTrackball(TransInfo *t, const int mval[2]);
-
-static void initPushPull(TransInfo *t);
-static void applyPushPull(TransInfo *t, const int mval[2]);
-
-static void initBevelWeight(TransInfo *t);
-static void applyBevelWeight(TransInfo *t, const int mval[2]);
-
-static void initCrease(TransInfo *t);
-static void applyCrease(TransInfo *t, const int mval[2]);
-
-static void initBoneSize(TransInfo *t);
-static void applyBoneSize(TransInfo *t, const int mval[2]);
-
-static void initBoneEnvelope(TransInfo *t);
-static void applyBoneEnvelope(TransInfo *t, const int mval[2]);
-
-static void initBoneRoll(TransInfo *t);
-static void applyBoneRoll(TransInfo *t, const int mval[2]);
-
-static void initEdgeSlide_ex(
- TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
-static void initEdgeSlide(TransInfo *t);
-static eRedrawFlag handleEventEdgeSlide(TransInfo *t, const struct wmEvent *event);
-static void applyEdgeSlide(TransInfo *t, const int mval[2]);
-
-static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
-static void initVertSlide(TransInfo *t);
-static eRedrawFlag handleEventVertSlide(TransInfo *t, const struct wmEvent *event);
-static void applyVertSlide(TransInfo *t, const int mval[2]);
-
-static void initTimeTranslate(TransInfo *t);
-static void applyTimeTranslate(TransInfo *t, const int mval[2]);
-
-static void initTimeSlide(TransInfo *t);
-static void applyTimeSlide(TransInfo *t, const int mval[2]);
-
-static void initTimeScale(TransInfo *t);
-static void applyTimeScale(TransInfo *t, const int mval[2]);
-
-static void initBakeTime(TransInfo *t);
-static void applyBakeTime(TransInfo *t, const int mval[2]);
-
-static void initMirror(TransInfo *t);
-static void applyMirror(TransInfo *t, const int mval[2]);
-
-static void initAlign(TransInfo *t);
-static void applyAlign(TransInfo *t, const int mval[2]);
-
-static void initSeqSlide(TransInfo *t);
-static void applySeqSlide(TransInfo *t, const int mval[2]);
-
-static void initGPOpacity(TransInfo *t);
-static void applyGPOpacity(TransInfo *t, const int mval[2]);
-/* end transform callbacks */
-
-static bool transdata_check_local_center(TransInfo *t, short around)
-{
- return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
- ((t->flag & (T_OBJECT | T_POSE)) ||
- /* implicit: (t->flag & T_EDIT) */
- (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) ||
- (t->spacetype == SPACE_GRAPH) ||
- (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
-}
-
bool transdata_check_local_islands(TransInfo *t, short around)
{
- return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH))));
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) && ((ELEM(t->obedit_type, OB_MESH, OB_GPENCIL))));
}
/* ************************** SPACE DEPENDENT CODE **************************** */
void setTransformViewMatrices(TransInfo *t)
{
- if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = t->ar->regiondata;
+ if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = t->region->regiondata;
copy_m4_m4(t->viewmat, rv3d->viewmat);
copy_m4_m4(t->viewinv, rv3d->viewinv);
@@ -260,7 +110,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
copy_v3_fl(r_aspect, 1.0f);
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
ED_space_image_get_aspect(sima, &r_aspect[0], &r_aspect[1]);
@@ -273,7 +123,7 @@ void setTransformViewAspect(TransInfo *t, float r_aspect[3])
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = t->sa->spacedata.first;
+ SpaceClip *sclip = t->area->spacedata.first;
if (t->options & CTX_MOVIECLIP) {
ED_space_clip_get_aspect_dimension_aware(sclip, &r_aspect[0], &r_aspect[1]);
@@ -324,14 +174,14 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
{
- if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
if (t->options & CTX_PAINT_CURVE) {
r_vec[0] = dx;
r_vec[1] = dy;
}
else {
const float mval_f[2] = {(float)dx, (float)dy};
- ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
+ ED_view3d_win_to_delta(t->region, mval_f, r_vec, t->zfac);
}
}
else if (t->spacetype == SPACE_IMAGE) {
@@ -353,7 +203,7 @@ void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
convertViewVec2D(t->view, r_vec, dx, dy);
}
else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
- convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
+ convertViewVec2D(&t->region->v2d, r_vec, dx, dy);
}
else if (t->spacetype == SPACE_CLIP) {
if (t->options & CTX_MASK) {
@@ -375,8 +225,8 @@ void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy)
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
{
if (t->spacetype == SPACE_VIEW3D) {
- if (t->ar->regiontype == RGN_TYPE_WINDOW) {
- if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
+ if (t->region->regiontype == RGN_TYPE_WINDOW) {
+ if (ED_view3d_project_int_global(t->region, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* this is what was done in 2.64, perhaps we can be smarter? */
adr[0] = (int)2140000000.0f;
adr[1] = (int)2140000000.0f;
@@ -384,7 +234,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (t->options & CTX_MASK) {
float v[2];
@@ -394,7 +244,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
- ED_image_point_pos__reverse(sima, t->ar, v, v);
+ ED_image_point_pos__reverse(sima, t->region, v, v);
adr[0] = v[0];
adr[1] = v[1];
@@ -415,7 +265,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
else if (t->spacetype == SPACE_ACTION) {
int out[2] = {0, 0};
#if 0
- SpaceAction *sact = t->sa->spacedata.first;
+ SpaceAction *sact = t->area->spacedata.first;
if (sact->flag & SACTION_DRAWTIME) {
//vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
@@ -446,7 +296,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
adr[1] = out[1];
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (t->options & CTX_MASK) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -459,7 +309,7 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
- ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
+ ED_clip_point_stable_pos__reverse(sc, t->region, v, v);
adr[0] = v[0];
adr[1] = v[1];
@@ -498,12 +348,12 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV
adr[0] = vec[0];
adr[1] = vec[1];
}
- else if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+ else if (t->region->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
- if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
+ if (ED_view3d_project_float_global(t->region, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
- adr[0] = t->ar->winx / 2.0f;
- adr[1] = t->ar->winy / 2.0f;
+ adr[0] = t->region->winx / 2.0f;
+ adr[1] = t->region->winy / 2.0f;
}
return;
}
@@ -527,7 +377,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) &&
!(t->options & CTX_PAINT_CURVE)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -551,7 +401,7 @@ void applyAspectRatio(TransInfo *t, float vec[2])
void removeAspectRatio(TransInfo *t, float vec[2])
{
if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if ((sima->flag & SI_COORDFLOATS) == 0) {
int width, height;
@@ -584,7 +434,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
else if (t->spacetype == SPACE_VIEW3D) {
if (t->options & CTX_PAINT_CURVE) {
wmWindow *window = CTX_wm_window(C);
- WM_paint_cursor_tag_redraw(window, t->ar);
+ WM_paint_cursor_tag_redraw(window, t->region);
}
else {
/* Do we need more refined tags? */
@@ -603,18 +453,18 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- // SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ // SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_GRAPH) {
- // SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ // SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NLA) {
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
}
else if (t->spacetype == SPACE_NODE) {
- // ED_area_tag_redraw(t->sa);
+ // ED_area_tag_redraw(t->area);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
}
else if (t->spacetype == SPACE_SEQ) {
@@ -630,24 +480,24 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
}
else if (t->options & CTX_PAINT_CURVE) {
wmWindow *window = CTX_wm_window(C);
- WM_paint_cursor_tag_redraw(window, t->ar);
+ WM_paint_cursor_tag_redraw(window, t->region);
}
else if (t->flag & T_CURSOR) {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
else {
// XXX how to deal with lock?
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
if (sima->lock) {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, OBEDIT_FROM_VIEW_LAYER(t->view_layer)->data);
}
else {
- ED_area_tag_redraw(t->sa);
+ ED_area_tag_redraw(t->area);
}
}
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *sc = (SpaceClip *)t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -667,7 +517,7 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
static void viewRedrawPost(bContext *C, TransInfo *t)
{
- ED_area_status_text(t->sa, NULL);
+ ED_area_status_text(t->area, NULL);
if (t->spacetype == SPACE_VIEW3D) {
/* if autokeying is enabled, send notifiers that keyframes were added */
@@ -709,7 +559,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
/* ************************** TRANSFORMATIONS **************************** */
-static void view_editmove(unsigned short UNUSED(event))
+static void view_editmove(ushort UNUSED(event))
{
#if 0 // TRANSFORM_FIX_ME
int refresh = 0;
@@ -797,42 +647,6 @@ static void view_editmove(unsigned short UNUSED(event))
/* ************************************************* */
-/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-enum {
- TFM_MODAL_CANCEL = 1,
- TFM_MODAL_CONFIRM = 2,
- TFM_MODAL_TRANSLATE = 3,
- TFM_MODAL_ROTATE = 4,
- TFM_MODAL_RESIZE = 5,
- TFM_MODAL_SNAP_INV_ON = 6,
- TFM_MODAL_SNAP_INV_OFF = 7,
- TFM_MODAL_SNAP_TOGGLE = 8,
- TFM_MODAL_AXIS_X = 9,
- TFM_MODAL_AXIS_Y = 10,
- TFM_MODAL_AXIS_Z = 11,
- TFM_MODAL_PLANE_X = 12,
- TFM_MODAL_PLANE_Y = 13,
- TFM_MODAL_PLANE_Z = 14,
- TFM_MODAL_CONS_OFF = 15,
- TFM_MODAL_ADD_SNAP = 16,
- TFM_MODAL_REMOVE_SNAP = 17,
-
- /* 18 and 19 used by numinput, defined in transform.h */
-
- TFM_MODAL_PROPSIZE_UP = 20,
- TFM_MODAL_PROPSIZE_DOWN = 21,
- TFM_MODAL_AUTOIK_LEN_INC = 22,
- TFM_MODAL_AUTOIK_LEN_DEC = 23,
-
- TFM_MODAL_EDGESLIDE_UP = 24,
- TFM_MODAL_EDGESLIDE_DOWN = 25,
-
- /* for analog input, like trackpad */
- TFM_MODAL_PROPSIZE = 26,
- /* node editor insert offset (aka auto-offset) direction toggle */
- TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27,
-};
-
static bool transform_modal_item_poll(const wmOperator *op, int value)
{
const TransInfo *t = op->customdata;
@@ -956,17 +770,18 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
{0, NULL, 0, NULL, NULL},
};
- wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
+ wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Transform Modal Map");
- keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
+ keymap = WM_modalkeymap_ensure(keyconf, "Transform Modal Map", modal_items);
keymap->poll_modal_item = transform_modal_item_poll;
return keymap;
}
-static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane)
+static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane)
{
if (!(t->flag & T_NO_CONSTRAINT)) {
+ char cmode = constraintModeToChar(t);
int constraint_axis, constraint_plane;
const bool edit_2d = (t->flag & T_2D_EDIT) != 0;
const char *msg1 = "", *msg2 = "", *msg3 = "";
@@ -974,21 +789,21 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
/* Initialize */
switch (key_type) {
- case XKEY:
+ case EVT_XKEY:
msg1 = TIP_("along X");
msg2 = TIP_("along %s X");
msg3 = TIP_("locking %s X");
axis = 'X';
constraint_axis = CON_AXIS0;
break;
- case YKEY:
+ case EVT_YKEY:
msg1 = TIP_("along Y");
msg2 = TIP_("along %s Y");
msg3 = TIP_("locking %s Y");
axis = 'Y';
constraint_axis = CON_AXIS1;
break;
- case ZKEY:
+ case EVT_ZKEY:
msg1 = TIP_("along Z");
msg2 = TIP_("along %s Z");
msg3 = TIP_("locking %s Z");
@@ -1001,7 +816,7 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis));
- if (edit_2d && (key_type != ZKEY)) {
+ if (edit_2d && (key_type != EVT_ZKEY)) {
if (cmode == axis) {
stopConstraint(t);
}
@@ -1010,34 +825,22 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
}
}
else if (!edit_2d) {
- if (cmode != axis) {
- /* First press, constraint to an axis. */
- t->orientation.index = 0;
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
- }
- else {
+ if (t->orientation.index == 0 || ELEM(cmode, '\0', axis)) {
/* Successive presses on existing axis, cycle orientation modes. */
t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types);
+ initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ }
- if (t->orientation.index == 0) {
- stopConstraint(t);
+ if (t->orientation.index == 0) {
+ stopConstraint(t);
+ }
+ else {
+ const short orientation = t->orientation.types[t->orientation.index];
+ if (is_plane == false) {
+ setUserConstraint(t, orientation, constraint_axis, msg2);
}
else {
- const short *orientation_ptr = t->orientation.types[t->orientation.index];
- const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL;
- if (is_plane == false) {
- setUserConstraint(t, orientation, constraint_axis, msg2);
- }
- else {
- setUserConstraint(t, orientation, constraint_plane, msg3);
- }
+ setUserConstraint(t, orientation, constraint_plane, msg3);
}
}
}
@@ -1047,7 +850,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm
int transformEvent(TransInfo *t, const wmEvent *event)
{
- char cmode = constraintModeToChar(t);
bool handled = false;
const int modifiers_prev = t->modifiers;
const int mode_prev = t->mode;
@@ -1103,7 +905,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- initTranslation(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1121,21 +923,20 @@ int transformEvent(TransInfo *t, const wmEvent *event)
resetTransRestrictions(t);
/* first try edge slide */
- initEdgeSlide(t);
+ transform_mode_init(t, NULL, TFM_EDGE_SLIDE);
/* if that fails, do vertex slide */
if (t->state == TRANS_CANCEL) {
resetTransModal(t);
t->state = TRANS_STARTING;
- initVertSlide(t);
+ transform_mode_init(t, NULL, TFM_VERT_SLIDE);
}
/* vert slide can fail on unconnected vertices (rare but possible) */
if (t->state == TRANS_CANCEL) {
resetTransModal(t);
- t->mode = TFM_TRANSLATION;
t->state = TRANS_STARTING;
restoreTransObjects(t);
resetTransRestrictions(t);
- initTranslation(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
}
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1168,10 +969,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
resetTransRestrictions(t);
if (t->mode == TFM_ROTATION) {
- initTrackball(t);
+ transform_mode_init(t, NULL, TFM_TRACKBALL);
}
else {
- initRotation(t);
+ transform_mode_init(t, NULL, TFM_ROTATION);
}
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1196,7 +997,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- initResize(t);
+ transform_mode_init(t, NULL, TFM_RESIZE);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1234,42 +1035,42 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_AXIS_X:
if (!(t->flag & T_NO_CONSTRAINT)) {
- transform_event_xyz_constraint(t, XKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_XKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Y:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
- transform_event_xyz_constraint(t, YKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_YKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_AXIS_Z:
if ((t->flag & (T_NO_CONSTRAINT)) == 0) {
- transform_event_xyz_constraint(t, ZKEY, cmode, false);
+ transform_event_xyz_constraint(t, EVT_ZKEY, false);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_X:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, XKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_XKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Y:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, YKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_YKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
case TFM_MODAL_PLANE_Z:
if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
- transform_event_xyz_constraint(t, ZKEY, cmode, true);
+ transform_event_xyz_constraint(t, EVT_ZKEY, true);
t->redraw |= TREDRAW_HARD;
handled = true;
}
@@ -1347,9 +1148,9 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_INSERTOFS_TOGGLE_DIR:
if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
- BLI_assert(t->sa->spacetype == t->spacetype);
+ BLI_assert(t->area->spacetype == t->spacetype);
if (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) {
snode->insert_ofs_dir = SNODE_INSERTOFS_DIR_LEFT;
@@ -1374,23 +1175,29 @@ int transformEvent(TransInfo *t, const wmEvent *event)
/* else do non-mapped events */
else if (event->val == KM_PRESS) {
switch (event->type) {
+ case EVT_ESCKEY:
case RIGHTMOUSE:
t->state = TRANS_CANCEL;
handled = true;
break;
- /* enforce redraw of transform when modifiers are used */
- case LEFTSHIFTKEY:
- case RIGHTSHIFTKEY:
- t->modifiers |= MOD_CONSTRAINT_PLANE;
- t->redraw |= TREDRAW_HARD;
- handled = true;
- break;
- case SPACEKEY:
+ case EVT_SPACEKEY:
+ case EVT_PADENTER:
+ case EVT_RETKEY:
+ if (event->is_repeat) {
+ break;
+ }
t->state = TRANS_CONFIRM;
handled = true;
break;
+ /* enforce redraw of transform when modifiers are used */
+ case EVT_LEFTSHIFTKEY:
+ case EVT_RIGHTSHIFTKEY:
+ t->modifiers |= MOD_CONSTRAINT_PLANE;
+ t->redraw |= TREDRAW_HARD;
+ handled = true;
+ break;
case MIDDLEMOUSE:
if ((t->flag & T_NO_CONSTRAINT) == 0) {
/* exception for switching to dolly, or trackball, in camera view */
@@ -1400,7 +1207,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
else if (t->mode == TFM_ROTATION) {
restoreTransObjects(t);
- initTrackball(t);
+ transform_mode_init(t, NULL, TFM_TRACKBALL);
}
}
else {
@@ -1409,17 +1216,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
stopConstraint(t);
}
else {
- if (event->shift) {
- /* bit hackish... but it prevents mmb select to print the
- * orientation from menu */
- float mati[3][3];
- strcpy(t->spacename, "global");
- unit_m3(mati);
- initSelectConstraint(t, mati);
- }
- else {
- initSelectConstraint(t, t->spacemtx);
- }
+ initSelectConstraint(t, event->shift);
postSelectConstraint(t);
}
}
@@ -1427,40 +1224,40 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
- case ESCKEY:
- t->state = TRANS_CANCEL;
- handled = true;
- break;
- case PADENTER:
- case RETKEY:
- t->state = TRANS_CONFIRM;
- handled = true;
- break;
- case GKEY:
+ case EVT_GKEY:
+ if (event->is_repeat) {
+ break;
+ }
/* only switch when... */
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- initTranslation(t);
+ transform_mode_init(t, NULL, TFM_TRANSLATION);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case SKEY:
+ case EVT_SKEY:
+ if (event->is_repeat) {
+ break;
+ }
/* only switch when... */
if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- initResize(t);
+ transform_mode_init(t, NULL, TFM_RESIZE);
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case RKEY:
+ case EVT_RKEY:
+ if (event->is_repeat) {
+ break;
+ }
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
@@ -1469,10 +1266,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
resetTransRestrictions(t);
if (t->mode == TFM_ROTATION) {
- initTrackball(t);
+ transform_mode_init(t, NULL, TFM_TRACKBALL);
}
else {
- initRotation(t);
+ transform_mode_init(t, NULL, TFM_ROTATION);
}
initSnapping(t, NULL); // need to reinit after mode change
t->redraw |= TREDRAW_HARD;
@@ -1480,7 +1277,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
}
break;
- case CKEY:
+ case EVT_CKEY:
+ if (event->is_repeat) {
+ break;
+ }
if (event->alt) {
if (!(t->options & CTX_NO_PET)) {
t->flag ^= T_PROP_CONNECTED;
@@ -1491,7 +1291,10 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
}
break;
- case OKEY:
+ case EVT_OKEY:
+ if (event->is_repeat) {
+ break;
+ }
if (t->flag & T_PROP_EDIT && event->shift) {
t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
calculatePropRatio(t);
@@ -1499,7 +1302,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
- case PADPLUSKEY:
+ case EVT_PADPLUSKEY:
if (event->alt && t->flag & T_PROP_EDIT) {
t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) {
@@ -1510,7 +1313,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
- case PAGEUPKEY:
+ case EVT_PAGEUPKEY:
case WHEELDOWNMOUSE:
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, 1);
@@ -1521,7 +1324,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw = TREDRAW_HARD;
handled = true;
break;
- case PADMINUS:
+ case EVT_PADMINUS:
if (event->alt && t->flag & T_PROP_EDIT) {
t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f;
calculatePropRatio(t);
@@ -1529,7 +1332,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
- case PAGEDOWNKEY:
+ case EVT_PAGEDOWNKEY:
case WHEELUPMOUSE:
if (t->flag & T_AUTOIK) {
transform_autoik_update(t, -1);
@@ -1540,21 +1343,24 @@ int transformEvent(TransInfo *t, const wmEvent *event)
t->redraw = TREDRAW_HARD;
handled = true;
break;
- case LEFTALTKEY:
- case RIGHTALTKEY:
+ case EVT_LEFTALTKEY:
+ case EVT_RIGHTALTKEY:
if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
t->flag |= T_ALT_TRANSFORM;
t->redraw |= TREDRAW_HARD;
handled = true;
}
break;
- case NKEY:
+ case EVT_NKEY:
+ if (event->is_repeat) {
+ break;
+ }
if (ELEM(t->mode, TFM_ROTATION)) {
if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
restoreTransObjects(t);
resetTransModal(t);
resetTransRestrictions(t);
- initNormalRotation(t);
+ transform_mode_init(t, NULL, TFM_NORMAL_ROTATION);
t->redraw = TREDRAW_HARD;
handled = true;
}
@@ -1569,8 +1375,8 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
else if (event->val == KM_RELEASE) {
switch (event->type) {
- case LEFTSHIFTKEY:
- case RIGHTSHIFTKEY:
+ case EVT_LEFTSHIFTKEY:
+ case EVT_RIGHTSHIFTKEY:
t->modifiers &= ~MOD_CONSTRAINT_PLANE;
t->redraw |= TREDRAW_HARD;
handled = true;
@@ -1584,8 +1390,8 @@ int transformEvent(TransInfo *t, const wmEvent *event)
handled = true;
}
break;
- case LEFTALTKEY:
- case RIGHTALTKEY:
+ case EVT_LEFTALTKEY:
+ case EVT_RIGHTALTKEY:
if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
t->flag &= ~T_ALT_TRANSFORM;
t->redraw |= TREDRAW_HARD;
@@ -1685,17 +1491,17 @@ bool calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], floa
return success;
}
-static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *ar)
+static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegion *region)
{
/* Don't show overlays when not the active view and when overlay is disabled: T57139 */
bool ok = false;
- if (ar == t->ar) {
+ if (region == t->region) {
ok = true;
}
else {
- ScrArea *sa = CTX_wm_area(C);
- if (sa->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ if (area->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = area->spacedata.first;
if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) {
ok = true;
}
@@ -1704,11 +1510,11 @@ static bool transinfo_show_overlay(const struct bContext *C, TransInfo *t, ARegi
return ok;
}
-static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg)
+static void drawTransformView(const struct bContext *C, ARegion *region, void *arg)
{
TransInfo *t = arg;
- if (!transinfo_show_overlay(C, t, ar)) {
+ if (!transinfo_show_overlay(C, t, region)) {
return;
}
@@ -1718,7 +1524,7 @@ static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg)
drawPropCircle(C, t);
drawSnapping(C, t);
- if (ar == t->ar) {
+ if (region == t->region) {
/* edge slide, vert slide */
drawEdgeSlide(t);
drawVertSlide(t);
@@ -1730,13 +1536,13 @@ static void drawTransformView(const struct bContext *C, ARegion *ar, void *arg)
/* just draw a little warning message in the top-right corner of the viewport
* to warn that autokeying is enabled */
-static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
+static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *region)
{
const char *printable = IFACE_("Auto Keying On");
float printable_size[2];
int xco, yco;
- const rcti *rect = ED_region_visible_rect(ar);
+ const rcti *rect = ED_region_visible_rect(region);
const int font_id = BLF_default();
BLF_width_and_height(
@@ -1748,7 +1554,7 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
*/
- unsigned char color[3];
+ uchar color[3];
UI_GetThemeColorShade3ubv(TH_TEXT_HI, -50, color);
BLF_color3ubv(font_id, color);
#ifdef WITH_INTERNATIONAL
@@ -1770,15 +1576,15 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
GPU_blend(false);
}
-static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg)
+static void drawTransformPixel(const struct bContext *C, ARegion *region, void *arg)
{
TransInfo *t = arg;
- if (!transinfo_show_overlay(C, t, ar)) {
+ if (!transinfo_show_overlay(C, t, region)) {
return;
}
- if (ar == t->ar) {
+ if (region == t->region) {
Scene *scene = t->scene;
ViewLayer *view_layer = t->view_layer;
Object *ob = OBACT(view_layer);
@@ -1789,10 +1595,10 @@ static void drawTransformPixel(const struct bContext *C, ARegion *ar, void *arg)
* AND only for the active region (as showing all is too overwhelming)
*/
if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
- if (ar == t->ar) {
+ if (region == t->region) {
if (t->flag & (T_OBJECT | T_POSE)) {
if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
- drawAutoKeyWarning(t, ar);
+ drawAutoKeyWarning(t, region);
}
}
}
@@ -1871,18 +1677,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
ts->prop_mode = t->prop_mode;
}
}
-
- if (t->spacetype == SPACE_VIEW3D) {
- if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- !RNA_property_is_set(op->ptr, prop) &&
- (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) {
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- orient_slot->type = t->orientation.user;
- BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) ||
- (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) ==
- orient_slot->index_custom));
- }
- }
}
if (t->flag & T_MODAL) {
@@ -1909,33 +1703,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0);
}
- /* Orientation used for redo. */
- const bool use_orient_axis = (t->orient_matrix_is_set &&
- (RNA_struct_find_property(op->ptr, "orient_axis") != NULL));
- short orientation;
- if (t->con.mode & CON_APPLY) {
- orientation = t->con.orientation;
- if (orientation == V3D_ORIENT_CUSTOM) {
- const int orientation_index_custom = BKE_scene_transform_orientation_get_index(
- t->scene, t->orientation.custom);
- /* Maybe we need a t->con.custom_orientation?
- * Seems like it would always match t->orientation.custom. */
- orientation = V3D_ORIENT_CUSTOM + orientation_index_custom;
- BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
- }
- }
- else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) &&
- (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) {
- orientation = RNA_property_enum_get(op->ptr, prop);
- }
- else if (use_orient_axis) {
- /* We're not using an orientation, use the fallback. */
- orientation = t->orientation.unset;
- }
- else {
- orientation = V3D_ORIENT_GLOBAL;
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
if (t->flag & T_MODAL) {
if (t->con.mode & CON_APPLY) {
@@ -1955,56 +1722,40 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
- if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) {
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", orientation);
- }
- }
- if (t->con.mode & CON_APPLY) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]);
- }
- else if (use_orient_axis) {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]);
- }
- else {
- RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
- }
- }
- }
-
if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) {
- /* constraint orientation can be global, even if user selects something else
- * so use the orientation in the constraint if set */
+ short orient_set, orient_cur;
+ orient_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : -1;
+ orient_cur = t->orientation.types[t->orientation.index];
- /* Use 'orient_matrix' instead. */
- if (t->flag & T_MODAL) {
- if (orientation != V3D_ORIENT_CUSTOM_MATRIX) {
- RNA_property_enum_set(op->ptr, prop, orientation);
- }
+ if (!ELEM(orient_cur, orient_set, V3D_ORIENT_CUSTOM_MATRIX)) {
+ RNA_property_enum_set(op->ptr, prop, orient_cur);
+ orient_set = orient_cur;
+ }
+
+ if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ !RNA_property_is_set(op->ptr, prop))) {
+ /* Set the first time to register on redo. */
+ RNA_property_enum_set(op->ptr, prop, orient_set);
+ RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]);
}
}
if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
bool constraint_axis[3] = {false, false, false};
- if (t->flag & T_MODAL) {
- /* Only set if needed, so we can hide in the UI when nothing is set.
- * See 'transform_poll_property'. */
- if (t->con.mode & CON_APPLY) {
- if (t->con.mode & CON_AXIS0) {
- constraint_axis[0] = true;
- }
- if (t->con.mode & CON_AXIS1) {
- constraint_axis[1] = true;
- }
- if (t->con.mode & CON_AXIS2) {
- constraint_axis[2] = true;
- }
+ if (t->con.mode & CON_APPLY) {
+ if (t->con.mode & CON_AXIS0) {
+ constraint_axis[0] = true;
}
- if (ELEM(true, UNPACK3(constraint_axis))) {
- RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ if (t->con.mode & CON_AXIS1) {
+ constraint_axis[1] = true;
}
+ if (t->con.mode & CON_AXIS2) {
+ constraint_axis[2] = true;
+ }
+ RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
+ }
+ else {
+ RNA_property_unset(op->ptr, prop);
}
}
@@ -2031,6 +1782,43 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
}
}
+static void initSnapSpatial(TransInfo *t, float r_snap[3])
+{
+ if (t->spacetype == SPACE_VIEW3D) {
+ RegionView3D *rv3d = t->region->regiondata;
+
+ if (rv3d) {
+ View3D *v3d = t->area->spacedata.first;
+ r_snap[0] = 0.0f;
+ r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f;
+ r_snap[2] = r_snap[1] * 0.1f;
+ }
+ }
+ else if (t->spacetype == SPACE_IMAGE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.0625f;
+ r_snap[2] = 0.03125f;
+ }
+ else if (t->spacetype == SPACE_CLIP) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 0.125f;
+ r_snap[2] = 0.0625f;
+ }
+ else if (t->spacetype == SPACE_NODE) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = r_snap[2] = ED_node_grid_size();
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ r_snap[0] = 0.0f;
+ r_snap[1] = 1.0;
+ r_snap[2] = 0.1f;
+ }
+ else {
+ r_snap[0] = 0.0f;
+ r_snap[1] = r_snap[2] = 1.0f;
+ }
+}
+
/**
* \note caller needs to free 't' on a 0 return
* \warning \a event might be NULL (when tweaking from redo panel)
@@ -2093,15 +1881,21 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->spacemtx);
initTransInfo(C, t, op, event);
- initTransformOrientation(C, t);
+
+ /* Use the custom orientation when it is set. */
+ short orientation = t->orientation.types[0] == V3D_ORIENT_CUSTOM_MATRIX ?
+ V3D_ORIENT_CUSTOM_MATRIX :
+ t->orientation.types[t->orientation.index];
+
+ initTransformOrientation(C, t, orientation);
if (t->spacetype == SPACE_VIEW3D) {
t->draw_handle_apply = ED_region_draw_cb_activate(
- t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
+ t->region->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_pixel = ED_region_draw_cb_activate(
- t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
+ t->region->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2111,7 +1905,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_IMAGE) {
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2121,7 +1915,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_CLIP) {
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2131,7 +1925,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_NODE) {
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2141,7 +1935,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_GRAPH) {
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2151,7 +1945,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_ACTION) {
t->draw_handle_view = ED_region_draw_cb_activate(
- t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
+ t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C),
SPACE_TYPE_ANY,
RGN_TYPE_ANY,
@@ -2190,10 +1984,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
- if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) && event->ctrl) ||
- (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) ||
- (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) && event->alt) ||
- ((kmi->type == OSKEY) && event->oskey)) {
+ if ((ELEM(kmi->type, EVT_LEFTCTRLKEY, EVT_RIGHTCTRLKEY) && event->ctrl) ||
+ (ELEM(kmi->type, EVT_LEFTSHIFTKEY, EVT_RIGHTSHIFTKEY) && event->shift) ||
+ (ELEM(kmi->type, EVT_LEFTALTKEY, EVT_RIGHTALTKEY) && event->alt) ||
+ ((kmi->type == EVT_OSKEY) && event->oskey)) {
t->modifiers |= MOD_SNAP_INVERT;
}
break;
@@ -2218,33 +2012,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
calculatePropRatio(t);
calculateCenter(t);
- /* Overwrite initial values if operator supplied a non-null vector.
- *
- * Run before init functions so 'values_modal_offset' can be applied on mouse input.
- */
- BLI_assert(is_zero_v4(t->values_modal_offset));
- if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
- float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
-
- if (RNA_property_array_check(prop)) {
- RNA_float_get_array(op->ptr, "value", values);
- }
- else {
- values[0] = RNA_float_get(op->ptr, "value");
- }
-
- copy_v4_v4(t->values, values);
-
- if (t->flag & T_MODAL) {
- copy_v4_v4(t->values_modal_offset, values);
- t->redraw = TREDRAW_HARD;
- }
- else {
- copy_v4_v4(t->values, values);
- t->flag |= T_INPUT_IS_VALUES_FINAL;
- }
- }
-
if (event) {
/* Initialize accurate transform to settings requested by keymap. */
bool use_accurate = false;
@@ -2257,145 +2024,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initMouseInput(t, &t->mouse, t->center2d, event->mval, use_accurate);
}
- switch (mode) {
- case TFM_TRANSLATION:
- initTranslation(t);
- break;
- case TFM_ROTATION:
- initRotation(t);
- break;
- case TFM_RESIZE:
- initResize(t);
- break;
- case TFM_SKIN_RESIZE:
- initSkinResize(t);
- break;
- case TFM_TOSPHERE:
- initToSphere(t);
- break;
- case TFM_SHEAR:
- initShear(t);
- break;
- case TFM_BEND:
- initBend(t);
- break;
- case TFM_SHRINKFATTEN:
- initShrinkFatten(t);
- break;
- case TFM_TILT:
- initTilt(t);
- break;
- case TFM_CURVE_SHRINKFATTEN:
- initCurveShrinkFatten(t);
- break;
- case TFM_MASK_SHRINKFATTEN:
- initMaskShrinkFatten(t);
- break;
- case TFM_GPENCIL_SHRINKFATTEN:
- initGPShrinkFatten(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) */
- /* Note: we have to pick one, use the active object. */
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
- bArmature *arm = tc->poseobj->data;
- if (arm->drawtype == ARM_ENVELOPE) {
- initBoneEnvelope(t);
- t->mode = TFM_BONE_ENVELOPE_DIST;
- }
- else {
- initBoneSize(t);
- }
- break;
- }
- case TFM_BONE_ENVELOPE:
- initBoneEnvelope(t);
- break;
- case TFM_BONE_ENVELOPE_DIST:
- initBoneEnvelope(t);
- t->mode = TFM_BONE_ENVELOPE_DIST;
- break;
- case TFM_EDGE_SLIDE:
- case TFM_VERT_SLIDE: {
- const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
- const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
- const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
- if (mode == TFM_EDGE_SLIDE) {
- const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
- initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
- }
- else {
- initVertSlide_ex(t, use_even, flipped, use_clamp);
- }
- 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_DUPLICATE:
- /* same as TFM_TIME_EXTEND, but we need the mode info for later
- * so that duplicate-culling will work properly
- */
- if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
- initTranslation(t);
- }
- else {
- initTimeTranslate(t);
- }
- t->mode = mode;
- break;
- case TFM_TIME_EXTEND:
- /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
- * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
- * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
- * depending on which editor this was called from
- */
- if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
- initTranslation(t);
- }
- else {
- initTimeTranslate(t);
- }
- break;
- case TFM_BAKE_TIME:
- initBakeTime(t);
- break;
- case TFM_MIRROR:
- initMirror(t);
- break;
- case TFM_BWEIGHT:
- initBevelWeight(t);
- break;
- case TFM_ALIGN:
- initAlign(t);
- break;
- case TFM_SEQ_SLIDE:
- initSeqSlide(t);
- break;
- case TFM_NORMAL_ROTATION:
- initNormalRotation(t);
- break;
- case TFM_GPENCIL_OPACITY:
- initGPOpacity(t);
- break;
- }
+ transform_mode_init(t, op, mode);
if (t->state == TRANS_CANCEL) {
postTrans(C, t);
@@ -2413,38 +2042,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Constraint init from operator */
- if ((t->flag & T_MODAL) ||
- /* For mirror operator the constraint axes are effectively the values. */
- (RNA_struct_find_property(op->ptr, "value") == NULL)) {
- if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) &&
- RNA_property_is_set(op->ptr, prop)) {
- bool constraint_axis[3];
-
- RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
-
- if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
- t->con.mode |= CON_APPLY;
-
- if (constraint_axis[0]) {
- t->con.mode |= CON_AXIS0;
- }
- if (constraint_axis[1]) {
- t->con.mode |= CON_AXIS1;
- }
- if (constraint_axis[2]) {
- t->con.mode |= CON_AXIS2;
- }
-
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
- }
- }
- else {
- /* So we can adjust in non global orientation. */
- if (t->orientation.user != V3D_ORIENT_GLOBAL) {
- t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2;
- setUserConstraint(t, t->orientation.user, t->con.mode, "%s");
- }
+ if (t->con.mode & CON_APPLY) {
+ setUserConstraint(t, t->orientation.types[t->orientation.index], t->con.mode, "%s");
}
/* Don't write into the values when non-modal because they are already set from operator redo
@@ -2518,7 +2117,7 @@ void transformApply(bContext *C, TransInfo *t)
t->context = NULL;
}
-static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg)
+static void drawTransformApply(const bContext *C, ARegion *UNUSED(region), void *arg)
{
TransInfo *t = arg;
@@ -2575,6597 +2174,6 @@ int transformEnd(bContext *C, TransInfo *t)
return exit_code;
}
-/* ************************** TRANSFORM LOCKS **************************** */
-
-static void protectedTransBits(short protectflag, float vec[3])
-{
- 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[3])
-{
- 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[3], const float oldeul[3])
-{
- 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];
- }
-}
-
-/* this function only does the delta rotation */
-/* axis-angle is usually internally stored as quats... */
-static void protectedAxisAngleBits(
- short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle)
-{
- /* check that protection flags are set */
- if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
- return;
- }
-
- if (protectflag & OB_LOCK_ROT4D) {
- /* axis-angle getting limited as 4D entities that they are... */
- if (protectflag & OB_LOCK_ROTW) {
- *angle = oldAngle;
- }
- if (protectflag & OB_LOCK_ROTX) {
- axis[0] = oldAxis[0];
- }
- if (protectflag & OB_LOCK_ROTY) {
- axis[1] = oldAxis[1];
- }
- if (protectflag & OB_LOCK_ROTZ) {
- axis[2] = oldAxis[2];
- }
- }
- else {
- /* axis-angle get limited with euler... */
- float eul[3], oldeul[3];
-
- axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
- axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
-
- 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];
- }
-
- eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
-
- /* When converting to axis-angle,
- * we need a special exception for the case when there is no axis. */
- if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
- /* for now, rotate around y-axis then (so that it simply becomes the roll) */
- axis[1] = 1.0f;
- }
- }
-}
-
-/* this function only does the delta rotation */
-static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
-{
- /* check that protection flags are set */
- if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
- return;
- }
-
- if (protectflag & OB_LOCK_ROT4D) {
- /* quaternions getting limited as 4D entities that they are... */
- if (protectflag & OB_LOCK_ROTW) {
- quat[0] = oldquat[0];
- }
- if (protectflag & OB_LOCK_ROTX) {
- quat[1] = oldquat[1];
- }
- if (protectflag & OB_LOCK_ROTY) {
- quat[2] = oldquat[2];
- }
- if (protectflag & OB_LOCK_ROTZ) {
- quat[3] = oldquat[3];
- }
- }
- else {
- /* quaternions get limited with euler... (compatibility mode) */
- float eul[3], oldeul[3], nquat[4], noldquat[4];
- float qlen;
-
- qlen = normalize_qt_qt(nquat, quat);
- normalize_qt_qt(noldquat, oldquat);
-
- quat_to_eul(eul, nquat);
- quat_to_eul(oldeul, noldquat);
-
- 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];
- }
-
- eul_to_quat(quat, eul);
-
- /* restore original quat size */
- mul_qt_fl(quat, qlen);
-
- /* quaternions flip w sign to accumulate rotations correctly */
- if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) {
- mul_qt_fl(quat, -1.0f);
- }
- }
-}
-
-/* ******************* TRANSFORM LIMITS ********************** */
-
-static void constraintTransLim(TransInfo *t, TransData *td)
-{
- if (td->con) {
- const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(
- CONSTRAINT_TYPE_LOCLIMIT);
- const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(
- CONSTRAINT_TYPE_DISTLIMIT);
-
- bConstraintOb cob = {NULL};
- bConstraint *con;
- float ctime = (float)(t->scene->r.cfra);
-
- /* Make a temporary bConstraintOb for using these limit constraints
- * - they only care that cob->matrix is correctly set ;-)
- * - current space should be local
- */
- unit_m4(cob.matrix);
- copy_v3_v3(cob.matrix[3], td->loc);
-
- /* Evaluate valid constraints */
- for (con = td->con; con; con = con->next) {
- const bConstraintTypeInfo *cti = NULL;
- ListBase targets = {NULL, NULL};
-
- /* only consider constraint if enabled */
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
- 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;
- }
- cti = ctiLoc;
- }
- else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
- bDistLimitConstraint *data = con->data;
-
- if ((data->flag & LIMITDIST_TRANSFORM) == 0) {
- continue;
- }
- cti = ctiDist;
- }
-
- if (cti) {
- /* do space conversions */
- if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
- /* just multiply by td->mtx (this should be ok) */
- mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
- }
- else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
- /* skip... incompatible spacetype */
- continue;
- }
-
- /* get constraint targets if needed */
- BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
-
- /* do constraint */
- cti->evaluate_constraint(con, &cob, &targets);
-
- /* convert spaces again */
- if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
- /* just multiply by td->smtx (this should be ok) */
- mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
- }
-
- /* free targets list */
- BLI_freelistN(&targets);
- }
- }
-
- /* copy results from cob->matrix */
- copy_v3_v3(td->loc, cob.matrix[3]);
- }
-}
-
-static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
-{
- /* Make a temporary bConstraintOb for use by limit constraints
- * - they only care that cob->matrix is correctly set ;-)
- * - current space should be local
- */
- memset(cob, 0, sizeof(bConstraintOb));
- if (td->ext) {
- if (td->ext->rotOrder == ROT_MODE_QUAT) {
- /* quats */
- /* objects and bones do normalization first too, otherwise
- * we don't necessarily end up with a rotation matrix, and
- * then conversion back to quat gives a different result */
- float quat[4];
- normalize_qt_qt(quat, td->ext->quat);
- quat_to_mat4(cob->matrix, quat);
- }
- else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
- /* axis angle */
- axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
- }
- else {
- /* eulers */
- eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
- }
- }
-}
-
-static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
-{
- if (td->con) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
- bConstraintOb cob;
- bConstraint *con;
- bool do_limit = false;
-
- /* Evaluate valid constraints */
- for (con = td->con; con; con = con->next) {
- /* only consider constraint if enabled */
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
- 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;
-
- /* only use it if it's tagged for this purpose */
- if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
- continue;
- }
-
- /* skip incompatible spacetypes */
- if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
- continue;
- }
-
- /* only do conversion if necessary, to preserve quats and eulers */
- if (do_limit == false) {
- constraintob_from_transdata(&cob, td);
- do_limit = true;
- }
-
- /* do space conversions */
- if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
- /* just multiply by td->mtx (this should be ok) */
- mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
- }
-
- /* do constraint */
- cti->evaluate_constraint(con, &cob, NULL);
-
- /* convert spaces again */
- if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
- /* just multiply by td->smtx (this should be ok) */
- mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
- }
- }
- }
-
- if (do_limit) {
- /* copy results from cob->matrix */
- if (td->ext->rotOrder == ROT_MODE_QUAT) {
- /* quats */
- mat4_to_quat(td->ext->quat, cob.matrix);
- }
- else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
- /* axis angle */
- mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix);
- }
- else {
- /* eulers */
- mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
- }
- }
- }
-}
-
-static void constraintSizeLim(TransInfo *t, TransData *td)
-{
- if (td->con && td->ext) {
- const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
- bConstraintOb cob = {NULL};
- bConstraint *con;
- float size_sign[3], size_abs[3];
- int i;
-
- /* Make a temporary bConstraintOb for using these limit constraints
- * - they only care that cob->matrix is correctly set ;-)
- * - current space should be local
- */
- 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;
- }
-
- /* separate out sign to apply back later */
- for (i = 0; i < 3; i++) {
- size_sign[i] = signf(td->ext->size[i]);
- size_abs[i] = fabsf(td->ext->size[i]);
- }
-
- size_to_mat4(cob.matrix, size_abs);
- }
-
- /* Evaluate valid constraints */
- for (con = td->con; con; con = con->next) {
- /* only consider constraint if enabled */
- if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
- 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;
-
- /* 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) */
- mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
- }
- else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
- /* skip... incompatible spacetype */
- continue;
- }
-
- /* do constraint */
- cti->evaluate_constraint(con, &cob, NULL);
-
- /* convert spaces again */
- if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
- /* just multiply by td->smtx (this should be ok) */
- mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
- }
- }
- }
-
- /* copy results from cob->matrix */
- 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;
- }
-
- /* extrace scale from matrix and apply back sign */
- mat4_to_size(td->ext->size, cob.matrix);
- mul_v3_v3(td->ext->size, size_sign);
- }
- }
-}
-
-/* -------------------------------------------------------------------- */
-/* Transform (Bend) */
-
-/** \name Transform Bend
- * \{ */
-
-struct BendCustomData {
- /* All values are in global space. */
- float warp_sta[3];
- float warp_end[3];
-
- float warp_nor[3];
- float warp_tan[3];
-
- /* for applying the mouse distance */
- float warp_init_dist;
-};
-
-static void initBend(TransInfo *t)
-{
- const float mval_fl[2] = {UNPACK2(t->mval)};
- const float *curs;
- float tvec[3];
- struct BendCustomData *data;
-
- t->mode = TFM_BEND;
- t->transform = Bend;
- t->handleEvent = handleEventBend;
-
- setInputPostFct(&t->mouse, postInputRotation);
- initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING);
-
- t->idx_max = 1;
- t->num.idx_max = 1;
- t->snap[0] = 0.0f;
- t->snap[1] = SNAP_INCREMENTAL_ANGLE;
- t->snap[2] = t->snap[1] * 0.2;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
- t->num.unit_type[1] = B_UNIT_LENGTH;
-
- t->flag |= T_NO_CONSTRAINT;
-
- // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
- if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- calculateCenterCursor(t, t->center_global);
- }
- calculateCenterLocal(t, t->center_global);
-
- t->val = 0.0f;
-
- data = MEM_callocN(sizeof(*data), __func__);
-
- curs = t->scene->cursor.location;
- copy_v3_v3(data->warp_sta, curs);
- ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end);
-
- copy_v3_v3(data->warp_nor, t->viewinv[2]);
- normalize_v3(data->warp_nor);
-
- /* tangent */
- sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
- cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
- normalize_v3(data->warp_tan);
-
- data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
-
- t->custom.mode.data = data;
- t->custom.mode.use_free = true;
-}
-
-static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
-{
- eRedrawFlag status = TREDRAW_NOTHING;
-
- if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
- status = TREDRAW_HARD;
- }
-
- return status;
-}
-
-static void Bend(TransInfo *t, const int UNUSED(mval[2]))
-{
- float vec[3];
- float pivot_global[3];
- float warp_end_radius_global[3];
- int i;
- char str[UI_MAX_DRAW_STR];
- const struct BendCustomData *data = t->custom.mode.data;
- const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
-
- union {
- struct {
- float angle, scale;
- };
- float vector[2];
- } values;
-
- /* amount of radians for bend */
- copy_v2_v2(values.vector, t->values);
-
-#if 0
- snapGrid(t, angle_rad);
-#else
- /* hrmf, snapping radius is using 'angle' steps, need to convert to something else
- * this isnt essential but nicer to give reasonable snapping values for radius */
- if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) {
- const float radius_snap = 0.1f;
- const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
- values.scale *= snap_hack;
- snapGridIncrement(t, values.vector);
- values.scale /= snap_hack;
- }
-#endif
-
- if (applyNumInput(&t->num, values.vector)) {
- values.scale = values.scale / data->warp_init_dist;
- }
-
- copy_v2_v2(t->values_final, values.vector);
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN * 2];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str,
- sizeof(str),
- TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
- &c[0],
- &c[NUM_STR_REP_LEN],
- WM_bool_as_string(is_clamp));
- }
- else {
- /* default header print */
- BLI_snprintf(str,
- sizeof(str),
- TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
- RAD2DEGF(values.angle),
- values.scale * data->warp_init_dist,
- WM_bool_as_string(is_clamp));
- }
-
- values.angle *= -1.0f;
- values.scale *= data->warp_init_dist;
-
- /* calc 'data->warp_end' from 'data->warp_end_init' */
- copy_v3_v3(warp_end_radius_global, data->warp_end);
- dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
- /* done */
-
- /* calculate pivot */
- copy_v3_v3(pivot_global, data->warp_sta);
- if (values.angle > 0.0f) {
- madd_v3_v3fl(pivot_global,
- data->warp_tan,
- -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
- }
- else {
- madd_v3_v3fl(pivot_global,
- data->warp_tan,
- +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
- }
-
- /* TODO(campbell): xform, compensate object center. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
-
- float warp_sta_local[3];
- float warp_end_local[3];
- float warp_end_radius_local[3];
- float pivot_local[3];
-
- if (tc->use_local_mat) {
- sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]);
- sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]);
- sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
- sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
- }
- else {
- copy_v3_v3(warp_sta_local, data->warp_sta);
- copy_v3_v3(warp_end_local, data->warp_end);
- copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
- copy_v3_v3(pivot_local, pivot_global);
- }
-
- for (i = 0; i < tc->data_len; i++, td++) {
- float mat[3][3];
- float delta[3];
- float fac, fac_scaled;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (UNLIKELY(values.angle == 0.0f)) {
- copy_v3_v3(td->loc, td->iloc);
- continue;
- }
-
- copy_v3_v3(vec, td->iloc);
- mul_m3_v3(td->mtx, vec);
-
- fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
- if (is_clamp) {
- CLAMP(fac, 0.0f, 1.0f);
- }
-
- if (t->options & CTX_GPENCIL_STROKES) {
- /* grease pencil multiframe falloff */
- bGPDstroke *gps = (bGPDstroke *)td->extra;
- if (gps != NULL) {
- fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff;
- }
- else {
- fac_scaled = fac * td->factor;
- }
- }
- else {
- fac_scaled = fac * td->factor;
- }
-
- axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
- interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
- sub_v3_v3(delta, warp_sta_local);
-
- /* delta is subtracted, rotation adds back this offset */
- sub_v3_v3(vec, delta);
-
- sub_v3_v3(vec, pivot_local);
- mul_m3_v3(mat, vec);
- add_v3_v3(vec, pivot_local);
-
- mul_m3_v3(td->smtx, vec);
-
- /* rotation */
- if ((t->flag & T_POINTS) == 0) {
- ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
- }
-
- /* location */
- copy_v3_v3(td->loc, vec);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Shear) */
-
-/** \name Transform Shear
- * \{ */
-
-static void initShear_mouseInputMode(TransInfo *t)
-{
- float dir[3];
- bool dir_flip = false;
- copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]);
-
- /* Needed for axis aligned view gizmo. */
- if (t->orientation.user == V3D_ORIENT_VIEW) {
- if (t->orient_axis_ortho == 0) {
- if (t->center2d[1] > t->mouse.imval[1]) {
- dir_flip = !dir_flip;
- }
- }
- else if (t->orient_axis_ortho == 1) {
- if (t->center2d[0] > t->mouse.imval[0]) {
- dir_flip = !dir_flip;
- }
- }
- }
-
- /* Without this, half the gizmo handles move in the opposite direction. */
- if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
- dir_flip = !dir_flip;
- }
-
- if (dir_flip) {
- negate_v3(dir);
- }
-
- mul_mat3_m4_v3(t->viewmat, dir);
- if (normalize_v2(dir) == 0.0f) {
- dir[0] = 1.0f;
- }
- setCustomPointsFromDirection(t, &t->mouse, dir);
-
- initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
-}
-
-static void initShear(TransInfo *t)
-{
- t->mode = TFM_SHEAR;
- t->transform = applyShear;
- t->handleEvent = handleEventShear;
-
- if (t->orient_axis == t->orient_axis_ortho) {
- t->orient_axis = 2;
- t->orient_axis_ortho = 1;
- }
-
- initShear_mouseInputMode(t);
-
- t->idx_max = 0;
- t->num.idx_max = 0;
- t->snap[0] = 0.0f;
- t->snap[1] = 0.1f;
- t->snap[2] = t->snap[1] * 0.1f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
-{
- eRedrawFlag status = TREDRAW_NOTHING;
-
- if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
- /* Use custom.mode.data pointer to signal Shear direction */
- do {
- t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3;
- } while (t->orient_axis_ortho == t->orient_axis);
-
- initShear_mouseInputMode(t);
-
- status = TREDRAW_HARD;
- }
- else if (event->type == XKEY && event->val == KM_PRESS) {
- t->orient_axis_ortho = (t->orient_axis + 1) % 3;
- initShear_mouseInputMode(t);
-
- status = TREDRAW_HARD;
- }
- else if (event->type == YKEY && event->val == KM_PRESS) {
- t->orient_axis_ortho = (t->orient_axis + 2) % 3;
- initShear_mouseInputMode(t);
-
- status = TREDRAW_HARD;
- }
-
- return status;
-}
-
-static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
-{
- float vec[3];
- float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
- float value;
- int i;
- char str[UI_MAX_DRAW_STR];
- const bool is_local_center = transdata_check_local_center(t, t->around);
-
- value = t->values[0];
-
- snapGridIncrement(t, &value);
-
- applyNumInput(&t->num, &value);
-
- t->values_final[0] = value;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext);
- }
- else {
- /* default header print */
- BLI_snprintf(str,
- sizeof(str),
- TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"),
- value,
- t->proptext);
- }
-
- unit_m3(smat);
- smat[1][0] = value;
-
- copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]);
- copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]);
- cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
- invert_m3_m3(axismat, axismat_inv);
-
- mul_m3_series(totmat, axismat_inv, smat, axismat);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- const float *center, *co;
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (t->flag & T_EDIT) {
- mul_m3_series(tmat, td->smtx, totmat, td->mtx);
- }
- else {
- copy_m3_m3(tmat, totmat);
- }
-
- if (is_local_center) {
- center = td->center;
- co = td->loc;
- }
- else {
- center = tc->center_local;
- co = td->center;
- }
-
- sub_v3_v3v3(vec, co, center);
-
- mul_m3_v3(tmat, vec);
-
- add_v3_v3(vec, center);
- sub_v3_v3(vec, co);
-
- if (t->options & CTX_GPENCIL_STROKES) {
- /* grease pencil multiframe falloff */
- bGPDstroke *gps = (bGPDstroke *)td->extra;
- if (gps != NULL) {
- mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
- }
- else {
- mul_v3_fl(vec, td->factor);
- }
- }
- else {
- mul_v3_fl(vec, td->factor);
- }
-
- add_v3_v3v3(td->loc, td->iloc, vec);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Resize) */
-
-/** \name Transform Resize
- * \{ */
-
-static void initResize(TransInfo *t)
-{
- t->mode = TFM_RESIZE;
- t->transform = applyResize;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
-
- t->flag |= T_NULL_ONE;
- t->num.val_flag[0] |= NUM_NULL_ONE;
- t->num.val_flag[1] |= NUM_NULL_ONE;
- t->num.val_flag[2] |= NUM_NULL_ONE;
- t->num.flag |= NUM_AFFECT_ALL;
- if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
- t->num.val_flag[1] |= NUM_NO_ZERO;
- t->num.val_flag[2] |= NUM_NO_ZERO;
-#endif
- }
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
- t->num.unit_type[1] = B_UNIT_NONE;
- t->num.unit_type[2] = B_UNIT_NONE;
-}
-
-static void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
- size_t ofs = 0;
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
- }
-
- if (t->con.mode & CON_APPLY) {
- switch (t->num.idx_max) {
- case 0:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Scale: %s%s %s"),
- &tvec[0],
- t->con.text,
- t->proptext);
- break;
- case 1:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Scale: %s : %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- t->con.text,
- t->proptext);
- break;
- case 2:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Scale: %s : %s : %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- t->con.text,
- t->proptext);
- break;
- }
- }
- else {
- if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Scale X: %s Y: %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- t->con.text,
- t->proptext);
- }
- else {
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Scale X: %s Y: %s Z: %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- t->con.text,
- t->proptext);
- }
- }
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
- }
-}
-
-/**
- * \a smat is reference matrix only.
- *
- * \note this is a tricky area, before making changes see: T29633, T42444
- */
-static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
-{
- float rmat[3][3];
-
- mat3_to_rot_size(rmat, size, mat);
-
- /* first tried with dotproduct... but the sign flip is crucial */
- if (dot_v3v3(rmat[0], smat[0]) < 0.0f) {
- size[0] = -size[0];
- }
- if (dot_v3v3(rmat[1], smat[1]) < 0.0f) {
- size[1] = -size[1];
- }
- if (dot_v3v3(rmat[2], smat[2]) < 0.0f) {
- size[2] = -size[2];
- }
-}
-
-static void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
-{
- float tmat[3][3], smat[3][3], center[3];
- float vec[3];
-
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(smat, mat, td->mtx);
- mul_m3_m3m3(tmat, td->smtx, smat);
- }
- else {
- copy_m3_m3(tmat, mat);
- }
-
- if (t->con.applySize) {
- t->con.applySize(t, tc, td, tmat);
- }
-
- /* local constraint shouldn't alter center */
- if (transdata_check_local_center(t, t->around)) {
- copy_v3_v3(center, td->center);
- }
- else if (t->options & CTX_MOVIECLIP) {
- if (td->flag & TD_INDIVIDUAL_SCALE) {
- copy_v3_v3(center, td->center);
- }
- else {
- copy_v3_v3(center, tc->center_local);
- }
- }
- else {
- copy_v3_v3(center, tc->center_local);
- }
-
- /* Size checked needed since the 3D cursor only uses rotation fields. */
- if (td->ext && td->ext->size) {
- float fsize[3];
-
- if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
- float obsizemat[3][3];
- /* Reorient the size mat to fit the oriented object. */
- mul_m3_m3m3(obsizemat, tmat, td->axismtx);
- /* print_m3("obsizemat", obsizemat); */
- TransMat3ToSize(obsizemat, td->axismtx, fsize);
- /* print_v3("fsize", fsize); */
- }
- else {
- mat3_to_size(fsize, tmat);
- }
-
- protectedSizeBits(td->protectflag, fsize);
-
- if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */
- if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
- /* scale val and reset size */
- *td->val = td->ival * (1 + (fsize[0] - 1) * 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] * (1 + (fsize[0] - 1) * td->factor);
- td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
- td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor);
- }
- }
-
- constraintSizeLim(t, td);
- }
-
- /* For individual element center, Editmode need to use iloc */
- if (t->flag & T_POINTS) {
- sub_v3_v3v3(vec, td->iloc, center);
- }
- else {
- sub_v3_v3v3(vec, td->center, center);
- }
-
- mul_m3_v3(tmat, vec);
-
- add_v3_v3(vec, center);
- if (t->flag & T_POINTS) {
- sub_v3_v3(vec, td->iloc);
- }
- else {
- sub_v3_v3(vec, td->center);
- }
-
- /* grease pencil falloff */
- if (t->options & CTX_GPENCIL_STROKES) {
- bGPDstroke *gps = (bGPDstroke *)td->extra;
- mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
-
- /* scale stroke thickness */
- if (td->val) {
- snapGridIncrement(t, t->values_final);
- applyNumInput(&t->num, t->values_final);
-
- float ratio = t->values_final[0];
- *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
- CLAMP_MIN(*td->val, 0.001f);
- }
- }
- else {
- mul_v3_fl(vec, td->factor);
- }
-
- if (t->flag & (T_OBJECT | T_POSE)) {
- mul_m3_v3(td->smtx, vec);
- }
-
- protectedTransBits(td->protectflag, vec);
- if (td->loc) {
- add_v3_v3v3(td->loc, td->iloc, vec);
- }
-
- constraintTransLim(t, td);
-}
-
-static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
-{
- float mat[3][3];
- int i;
- char str[UI_MAX_DRAW_STR];
-
- if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
- }
- else {
- float ratio = t->values[0];
-
- copy_v3_fl(t->values_final, ratio);
-
- snapGridIncrement(t, t->values_final);
-
- if (applyNumInput(&t->num, t->values_final)) {
- constraintNumInput(t, t->values_final);
- }
-
- applySnapping(t, t->values_final);
- }
-
- size_to_mat3(mat, t->values_final);
- if (t->con.mode & CON_APPLY) {
- t->con.applySize(t, NULL, NULL, mat);
-
- /* Only so we have re-usable value with redo. */
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- int j = 0;
- for (i = 0; i < 3; i++) {
- if (!(t->con.mode & (CON_AXIS0 << i))) {
- t->values_final[i] = 1.0f;
- }
- else {
- pvec[j++] = t->values_final[i];
- }
- }
- headerResize(t, pvec, str);
- }
- else {
- headerResize(t, t->values_final, str);
- }
-
- copy_m3_m3(t->mat, mat); // used in gizmo
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- ElementResize(t, tc, td, mat);
- }
- }
-
- /* evil hack - redo resize if cliping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) {
- size_to_mat3(mat, t->values_final);
-
- if (t->con.mode & CON_APPLY) {
- t->con.applySize(t, NULL, NULL, mat);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- ElementResize(t, tc, td, mat);
- }
-
- /* In proportional edit it can happen that */
- /* vertices in the radius of the brush end */
- /* outside the clipping area */
- /* XXX HACK - dg */
- if (t->flag & T_PROP_EDIT_ALL) {
- clipUVData(t);
- }
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Skin) */
-
-/** \name Transform Skin
- * \{ */
-
-static void initSkinResize(TransInfo *t)
-{
- t->mode = TFM_SKIN_RESIZE;
- t->transform = applySkinResize;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
-
- t->flag |= T_NULL_ONE;
- t->num.val_flag[0] |= NUM_NULL_ONE;
- t->num.val_flag[1] |= NUM_NULL_ONE;
- t->num.val_flag[2] |= NUM_NULL_ONE;
- t->num.flag |= NUM_AFFECT_ALL;
- if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
- t->num.val_flag[1] |= NUM_NO_ZERO;
- t->num.val_flag[2] |= NUM_NO_ZERO;
-#endif
- }
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
- t->num.unit_type[1] = B_UNIT_NONE;
- t->num.unit_type[2] = B_UNIT_NONE;
-}
-
-static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
-{
- float mat[3][3];
- int i;
- char str[UI_MAX_DRAW_STR];
-
- if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
- }
- else {
- copy_v3_fl(t->values_final, t->values[0]);
-
- snapGridIncrement(t, t->values_final);
-
- if (applyNumInput(&t->num, t->values_final)) {
- constraintNumInput(t, t->values_final);
- }
-
- applySnapping(t, t->values_final);
- }
-
- size_to_mat3(mat, t->values_final);
-
- headerResize(t, t->values_final, str);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float tmat[3][3], smat[3][3];
- float fsize[3];
-
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (t->flag & T_EDIT) {
- mul_m3_m3m3(smat, mat, td->mtx);
- mul_m3_m3m3(tmat, td->smtx, smat);
- }
- else {
- copy_m3_m3(tmat, mat);
- }
-
- if (t->con.applySize) {
- t->con.applySize(t, NULL, NULL, tmat);
- }
-
- mat3_to_size(fsize, tmat);
- td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
- td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (ToSphere) */
-
-/** \name Transform ToSphere
- * \{ */
-
-static void initToSphere(TransInfo *t)
-{
- int i;
-
- t->mode = TFM_TOSPHERE;
- t->transform = applyToSphere;
-
- initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
- t->flag |= T_NO_CONSTRAINT;
-
- // Calculate average radius
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- t->val += len_v3v3(tc->center_local, td->iloc);
- }
- }
-
- t->val /= (float)t->data_len_all;
-}
-
-static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
-{
- float vec[3];
- float ratio, radius;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- CLAMP(ratio, 0.0f, 1.0f);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %s %s"), c, t->proptext);
- }
- else {
- /* default header print */
- BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float tratio;
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- sub_v3_v3v3(vec, td->iloc, tc->center_local);
-
- radius = normalize_v3(vec);
-
- tratio = ratio * td->factor;
-
- mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
-
- add_v3_v3v3(td->loc, tc->center_local, vec);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Rotation) */
-
-/** \name Transform Rotation
- * \{ */
-
-static void postInputRotation(TransInfo *t, float values[3])
-{
- float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
- if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, NULL, axis_final, values);
- }
-}
-
-static void initRotation(TransInfo *t)
-{
- t->mode = TFM_ROTATION;
- t->transform = applyRotation;
-
- setInputPostFct(&t->mouse, postInputRotation);
- initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
-
- t->idx_max = 0;
- t->num.idx_max = 0;
- t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
-
- copy_v3_fl(t->num.val_inc, t->snap[2]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
-
- if (t->flag & T_2D_EDIT) {
- t->flag |= T_NO_CONSTRAINT;
- }
-}
-
-/* Used by Transform Rotation and Transform Normal Rotation */
-static void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
-{
- size_t ofs = 0;
-
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
- }
- else {
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_("Rot: %.2f%s %s"),
- RAD2DEGF(final),
- t->con.text,
- t->proptext);
- }
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
- }
-}
-
-/**
- * Applies values of rotation to `td->loc` and `td->ext->quat`
- * based on a rotation matrix (mat) and a pivot (center).
- *
- * Protected axis and other transform settings are taken into account.
- */
-static void ElementRotation_ex(TransInfo *t,
- TransDataContainer *tc,
- TransData *td,
- const float mat[3][3],
- const float *center)
-{
- float vec[3], totmat[3][3], smat[3][3];
- float eul[3], fmat[3][3], quat[4];
-
- if (t->flag & T_POINTS) {
- mul_m3_m3m3(totmat, mat, td->mtx);
- mul_m3_m3m3(smat, td->smtx, totmat);
-
- /* apply gpencil falloff */
- if (t->options & CTX_GPENCIL_STROKES) {
- bGPDstroke *gps = (bGPDstroke *)td->extra;
- float sx = smat[0][0];
- float sy = smat[1][1];
- float sz = smat[2][2];
-
- mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
- /* fix scale */
- smat[0][0] = sx;
- smat[1][1] = sy;
- smat[2][2] = sz;
- }
-
- sub_v3_v3v3(vec, td->iloc, center);
- mul_m3_v3(smat, vec);
-
- add_v3_v3v3(td->loc, vec, center);
-
- sub_v3_v3v3(vec, td->loc, td->iloc);
- protectedTransBits(td->protectflag, vec);
- add_v3_v3v3(td->loc, td->iloc, vec);
-
- if (td->flag & TD_USEQUAT) {
- mul_m3_series(fmat, td->smtx, mat, td->mtx);
- mat3_to_quat(quat, fmat); // Actual transform
-
- if (td->ext->quat) {
- mul_qt_qtqt(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) {
- // Extract and invert armature object matrix
-
- if ((td->flag & TD_NO_LOC) == 0) {
- sub_v3_v3v3(vec, td->center, center);
-
- mul_m3_v3(tc->mat3, vec); // To Global space
- mul_m3_v3(mat, vec); // Applying rotation
- mul_m3_v3(tc->imat3, vec); // To Local space
-
- add_v3_v3(vec, center);
- /* vec now is the location where the object has to be */
-
- sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location
-
- /* special exception, see TD_PBONE_LOCAL_MTX definition comments */
- if (td->flag & TD_PBONE_LOCAL_MTX_P) {
- /* do nothing */
- }
- else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
- mul_m3_v3(tc->mat3, vec); // To Global space
- mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location)
- }
- else {
- mul_m3_v3(tc->mat3, vec); // To Global space
- mul_m3_v3(td->smtx, vec); // To Pose space
- }
-
- protectedTransBits(td->protectflag, vec);
-
- add_v3_v3v3(td->loc, td->iloc, vec);
-
- constraintTransLim(t, td);
- }
-
- /* rotation */
- /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
- * and ElementRotation() might be called in Translation context (with align snapping),
- * we need to be sure to actually use the *rotation* matrix here...
- * So no other way than storing it in some dedicated members of td->ext! */
- if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */
- /* euler or quaternion/axis-angle? */
- if (td->ext->rotOrder == ROT_MODE_QUAT) {
- mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
-
- mat3_to_quat(quat, fmat); /* Actual transform */
-
- mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
- /* this function works on end result */
- protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
- }
- else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
- /* calculate effect based on quats */
- float iquat[4], tquat[4];
-
- axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
-
- mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
- mat3_to_quat(quat, fmat); /* Actual transform */
- mul_qt_qtqt(tquat, quat, iquat);
-
- quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
-
- /* this function works on end result */
- protectedAxisAngleBits(td->protectflag,
- td->ext->rotAxis,
- td->ext->rotAngle,
- td->ext->irotAxis,
- td->ext->irotAngle);
- }
- else {
- float eulmat[3][3];
-
- mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
- mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
-
- /* calculate the total rotatation in eulers */
- copy_v3_v3(eul, td->ext->irot);
- eulO_to_mat3(eulmat, eul, td->ext->rotOrder);
-
- /* mat = transform, obmat = bone rotation */
- mul_m3_m3m3(fmat, smat, eulmat);
-
- mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
-
- /* and apply (to end result only) */
- protectedRotateBits(td->protectflag, eul, td->ext->irot);
- copy_v3_v3(td->ext->rot, eul);
- }
-
- constraintRotLim(t, td);
- }
- }
- else {
- if ((td->flag & TD_NO_LOC) == 0) {
- /* translation */
- sub_v3_v3v3(vec, td->center, center);
- mul_m3_v3(mat, vec);
- add_v3_v3(vec, center);
- /* vec now is the location where the object has to be */
- sub_v3_v3(vec, td->center);
- mul_m3_v3(td->smtx, vec);
-
- protectedTransBits(td->protectflag, vec);
-
- add_v3_v3v3(td->loc, td->iloc, vec);
- }
-
- constraintTransLim(t, td);
-
- /* rotation */
- if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself
- /* euler or quaternion? */
- if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
- /* can be called for texture space translate for example, then opt out */
- if (td->ext->quat) {
- mul_m3_series(fmat, td->smtx, mat, td->mtx);
- mat3_to_quat(quat, fmat); // Actual transform
-
- mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
- /* this function works on end result */
- protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
- }
- }
- else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
- /* calculate effect based on quats */
- float iquat[4], tquat[4];
-
- axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
-
- mul_m3_series(fmat, td->smtx, mat, td->mtx);
- mat3_to_quat(quat, fmat); // Actual transform
- mul_qt_qtqt(tquat, quat, iquat);
-
- quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
-
- /* this function works on end result */
- protectedAxisAngleBits(td->protectflag,
- td->ext->rotAxis,
- td->ext->rotAngle,
- td->ext->irotAxis,
- td->ext->irotAngle);
- }
- else {
- float obmat[3][3];
-
- mul_m3_m3m3(totmat, mat, td->mtx);
- mul_m3_m3m3(smat, td->smtx, totmat);
-
- /* calculate the total rotatation in eulers */
- add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */
- eulO_to_mat3(obmat, eul, td->ext->rotOrder);
- /* mat = transform, obmat = object rotation */
- mul_m3_m3m3(fmat, smat, obmat);
-
- mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
-
- /* correct back for delta rot */
- sub_v3_v3v3(eul, eul, td->ext->drot);
-
- /* and apply */
- protectedRotateBits(td->protectflag, eul, td->ext->irot);
- copy_v3_v3(td->ext->rot, eul);
- }
-
- constraintRotLim(t, td);
- }
- }
-}
-
-static void ElementRotation(
- TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around)
-{
- const float *center;
-
- /* local constraint shouldn't alter center */
- if (transdata_check_local_center(t, around)) {
- center = td->center;
- }
- else {
- center = tc->center_local;
- }
-
- ElementRotation_ex(t, tc, td, mat, center);
-}
-
-static float large_rotation_limit(float angle)
-{
- /* Limit rotation to 1001 turns max
- * (otherwise iterative handling of 'large' rotations would become too slow). */
- const float angle_max = (float)(M_PI * 2000.0);
- if (fabsf(angle) > angle_max) {
- const float angle_sign = angle < 0.0f ? -1.0f : 1.0f;
- angle = angle_sign * (fmodf(fabsf(angle), (float)(M_PI * 2.0)) + angle_max);
- }
- return angle;
-}
-
-static void applyRotationValue(TransInfo *t,
- float angle,
- float axis[3],
- const bool is_large_rotation)
-{
- float mat[3][3];
- int i;
-
- const float angle_sign = angle < 0.0f ? -1.0f : 1.0f;
- /* We cannot use something too close to 180°, or 'continuous' rotation may fail
- * due to computing error... */
- const float angle_step = angle_sign * (float)(0.9 * M_PI);
-
- if (is_large_rotation) {
- /* Just in case, calling code should have already done that in practice
- * (for UI feedback reasons). */
- angle = large_rotation_limit(angle);
- }
-
- axis_angle_normalized_to_mat3(mat, axis, angle);
- /* Counter for needed updates (when we need to update to non-default matrix,
- * we also need another update on next iteration to go back to default matrix,
- * hence the '2' value used here, instead of a mere boolean). */
- short do_update_matrix = 0;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- float angle_final = angle;
- if (t->con.applyRot) {
- t->con.applyRot(t, tc, td, axis, NULL);
- angle_final = angle * td->factor;
- /* Even though final angle might be identical to orig value,
- * we have to update the rotation matrix in that case... */
- do_update_matrix = 2;
- }
- else if (t->flag & T_PROP_EDIT) {
- angle_final = angle * td->factor;
- }
-
- /* Rotation is very likely to be above 180°, we need to do rotation by steps.
- * Note that this is only needed when doing 'absolute' rotation
- * (i.e. from initial rotation again, typically when using numinput).
- * regular incremental rotation (from mouse/widget/...) will be called often enough,
- * hence steps are small enough to be properly handled without that complicated trick.
- * Note that we can only do that kind of stepped rotation if we have initial rotation values
- * (and access to some actual rotation value storage).
- * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing).
- * Also need to be in Euler rotation mode, the others never allow more than one turn anyway.
- */
- if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) {
- copy_v3_v3(td->ext->rot, td->ext->irot);
- for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final);
- angle_progress += angle_step) {
- axis_angle_normalized_to_mat3(mat, axis, angle_progress);
- ElementRotation(t, tc, td, mat, t->around);
- }
- do_update_matrix = 2;
- }
- else if (angle_final != angle) {
- do_update_matrix = 2;
- }
-
- if (do_update_matrix > 0) {
- axis_angle_normalized_to_mat3(mat, axis, angle_final);
- do_update_matrix--;
- }
-
- ElementRotation(t, tc, td, mat, t->around);
- }
- }
-}
-
-static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
-
- float final;
-
- final = t->values[0];
-
- snapGridIncrement(t, &final);
-
- float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
-
- if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, NULL, axis_final, NULL);
- }
-
- applySnapping(t, &final);
-
- if (applyNumInput(&t->num, &final)) {
- /* We have to limit the amount of turns to a reasonable number here,
- * to avoid things getting *very* slow, see how applyRotationValue() handles those... */
- final = large_rotation_limit(final);
- }
-
- t->values_final[0] = final;
-
- headerRotation(t, str, final);
-
- const bool is_large_rotation = hasNumInput(&t->num);
- applyRotationValue(t, final, axis_final, is_large_rotation);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Rotation - Trackball) */
-
-/** \name Transform Rotation - Trackball
- * \{ */
-
-static void initTrackball(TransInfo *t)
-{
- t->mode = TFM_TRACKBALL;
- t->transform = applyTrackball;
-
- initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
-
- t->idx_max = 1;
- t->num.idx_max = 1;
- t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
-
- copy_v3_fl(t->num.val_inc, t->snap[2]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
- t->num.unit_type[1] = B_UNIT_ROTATION;
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static void applyTrackballValue(TransInfo *t,
- const float axis1[3],
- const float axis2[3],
- const float angles[2])
-{
- float mat[3][3];
- float axis[3];
- float angle;
- int i;
-
- mul_v3_v3fl(axis, axis1, angles[0]);
- madd_v3_v3fl(axis, axis2, angles[1]);
- angle = normalize_v3(axis);
- axis_angle_normalized_to_mat3(mat, axis, angle);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (t->flag & T_PROP_EDIT) {
- axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
- }
-
- ElementRotation(t, tc, td, mat, t->around);
- }
- }
-}
-
-static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
- size_t ofs = 0;
- float axis1[3], axis2[3];
-#if 0 /* UNUSED */
- float mat[3][3], totmat[3][3], smat[3][3];
-#endif
- float phi[2];
-
- copy_v3_v3(axis1, t->persinv[0]);
- copy_v3_v3(axis2, t->persinv[1]);
- normalize_v3(axis1);
- normalize_v3(axis2);
-
- copy_v2_v2(phi, t->values);
-
- snapGridIncrement(t, phi);
-
- applyNumInput(&t->num, phi);
-
- copy_v2_v2(t->values_final, phi);
-
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN * 2];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- ofs += BLI_snprintf(str + ofs,
- sizeof(str) - ofs,
- TIP_("Trackball: %s %s %s"),
- &c[0],
- &c[NUM_STR_REP_LEN],
- t->proptext);
- }
- else {
- ofs += BLI_snprintf(str + ofs,
- sizeof(str) - ofs,
- TIP_("Trackball: %.2f %.2f %s"),
- RAD2DEGF(phi[0]),
- RAD2DEGF(phi[1]),
- t->proptext);
- }
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
- }
-
-#if 0 /* UNUSED */
- axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
- axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
-
- mul_m3_m3m3(mat, smat, totmat);
-
- // TRANSFORM_FIX_ME
- //copy_m3_m3(t->mat, mat); // used in gizmo
-#endif
-
- applyTrackballValue(t, axis1, axis2, phi);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Normal Rotation) */
-
-/** \name Transform Normal Rotation
- * \{ */
-
-static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm)
-{
- BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
- // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
-
- tc->custom.mode.data = lnors_ed_arr;
- tc->custom.mode.free_cb = freeCustomNormalArray;
-}
-
-void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
-{
- BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data;
-
- if (t->state == TRANS_CANCEL) {
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
-
- /* Restore custom loop normal on cancel */
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data);
- }
- }
-
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
-
- tc->custom.mode.data = NULL;
- tc->custom.mode.free_cb = NULL;
-}
-
-static void initNormalRotation(TransInfo *t)
-{
- t->mode = TFM_NORMAL_ROTATION;
- t->transform = applyNormalRotation;
-
- setInputPostFct(&t->mouse, postInputRotation);
- initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
-
- t->idx_max = 0;
- t->num.idx_max = 0;
- t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
-
- copy_v3_fl(t->num.val_inc, t->snap[2]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
-
- BKE_editmesh_ensure_autosmooth(em, tc->obedit->data);
- BKE_editmesh_lnorspace_update(em, tc->obedit->data);
-
- storeCustomLNorValue(tc, bm);
- }
-}
-
-/* Works by getting custom normal from clnor_data, transform, then store */
-static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
-
- float axis_final[3];
- copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]);
-
- if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
- t->con.applyRot(t, NULL, NULL, axis_final, NULL);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
-
- BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data;
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
-
- float axis[3];
- float mat[3][3];
- float angle = t->values[0];
- copy_v3_v3(axis, axis_final);
-
- snapGridIncrement(t, &angle);
-
- applySnapping(t, &angle);
-
- applyNumInput(&t->num, &angle);
-
- headerRotation(t, str, angle);
-
- axis_angle_normalized_to_mat3(mat, axis, angle);
-
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc);
-
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
- }
-
- t->values_final[0] = angle;
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Translation) */
-
-static void initSnapSpatial(TransInfo *t, float r_snap[3])
-{
- if (t->spacetype == SPACE_VIEW3D) {
- RegionView3D *rv3d = t->ar->regiondata;
-
- if (rv3d) {
- View3D *v3d = t->sa->spacedata.first;
- r_snap[0] = 0.0f;
- r_snap[1] = ED_view3d_grid_view_scale(t->scene, v3d, rv3d, NULL) * 1.0f;
- r_snap[2] = r_snap[1] * 0.1f;
- }
- }
- else if (t->spacetype == SPACE_IMAGE) {
- r_snap[0] = 0.0f;
- r_snap[1] = 0.0625f;
- r_snap[2] = 0.03125f;
- }
- else if (t->spacetype == SPACE_CLIP) {
- r_snap[0] = 0.0f;
- r_snap[1] = 0.125f;
- r_snap[2] = 0.0625f;
- }
- else if (t->spacetype == SPACE_NODE) {
- r_snap[0] = 0.0f;
- r_snap[1] = r_snap[2] = ED_node_grid_size();
- }
- else if (t->spacetype == SPACE_GRAPH) {
- r_snap[0] = 0.0f;
- r_snap[1] = 1.0;
- r_snap[2] = 0.1f;
- }
- else {
- r_snap[0] = 0.0f;
- r_snap[1] = r_snap[2] = 1.0f;
- }
-}
-
-/** \name Transform Translation
- * \{ */
-
-static void initTranslation(TransInfo *t)
-{
- if (t->spacetype == SPACE_ACTION) {
- /* this space uses time translate */
- BKE_report(t->reports,
- RPT_ERROR,
- "Use 'Time_Translate' transform mode instead of 'Translation' mode "
- "for translating keyframes in Dope Sheet Editor");
- t->state = TRANS_CANCEL;
- }
-
- t->mode = TFM_TRANSLATION;
- t->transform = applyTranslation;
-
- initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
-
- t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2;
- t->num.flag = 0;
- t->num.idx_max = t->idx_max;
-
- copy_v3_v3(t->snap, t->snap_spatial);
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- if (t->spacetype == SPACE_VIEW3D) {
- /* Handling units makes only sense in 3Dview... See T38877. */
- t->num.unit_type[0] = B_UNIT_LENGTH;
- t->num.unit_type[1] = B_UNIT_LENGTH;
- t->num.unit_type[2] = B_UNIT_LENGTH;
- }
- else {
- /* SPACE_GRAPH, SPACE_ACTION, etc. could use some time units, when we have them... */
- t->num.unit_type[0] = B_UNIT_NONE;
- t->num.unit_type[1] = B_UNIT_NONE;
- t->num.unit_type[2] = B_UNIT_NONE;
- }
-}
-
-static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
-{
- size_t ofs = 0;
- char tvec[NUM_STR_REP_LEN * 3];
- char distvec[NUM_STR_REP_LEN];
- char autoik[NUM_STR_REP_LEN];
- float dist;
-
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- dist = len_v3(t->num.val);
- }
- else {
- float dvec[3];
-
- copy_v3_v3(dvec, vec);
- applyAspectRatio(t, dvec);
-
- dist = len_v3(vec);
- if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- int i;
-
- for (i = 0; i < 3; i++) {
- bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i],
- NUM_STR_REP_LEN,
- dvec[i] * t->scene->unit.scale_length,
- 4,
- B_UNIT_LENGTH,
- &t->scene->unit,
- true);
- }
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]);
- }
- }
-
- if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
- bUnit_AsString2(distvec,
- sizeof(distvec),
- dist * t->scene->unit.scale_length,
- 4,
- B_UNIT_LENGTH,
- &t->scene->unit,
- false);
- }
- else if (dist > 1e10f || dist < -1e10f) {
- /* prevent string buffer overflow */
- BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
- }
- else {
- BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist);
- }
-
- if (t->flag & T_AUTOIK) {
- short chainlen = t->settings->autoik_chainlen;
-
- if (chainlen) {
- BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen);
- }
- else {
- autoik[0] = '\0';
- }
- }
- else {
- autoik[0] = '\0';
- }
-
- if (t->con.mode & CON_APPLY) {
- switch (t->num.idx_max) {
- case 0:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "D: %s (%s)%s %s %s",
- &tvec[0],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
- break;
- case 1:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "D: %s D: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
- break;
- case 2:
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "D: %s D: %s D: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
- break;
- }
- }
- else {
- if (t->flag & T_2D_EDIT) {
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "Dx: %s Dy: %s (%s)%s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- distvec,
- t->con.text,
- t->proptext);
- }
- else {
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- distvec,
- t->con.text,
- t->proptext,
- autoik);
- }
- }
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
- }
-
- if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
-
- if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
- const char *str_old = BLI_strdup(str);
- const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? TIP_("right") :
- TIP_("left");
- char str_km[64];
-
- WM_modalkeymap_items_to_string(
- t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, str_km, sizeof(str_km));
-
- ofs += BLI_snprintf(str,
- UI_MAX_DRAW_STR,
- TIP_("Auto-offset set to %s - press %s to toggle direction | %s"),
- str_dir,
- str_km,
- str_old);
-
- MEM_freeN((void *)str_old);
- }
- }
-}
-
-static void applyTranslationValue(TransInfo *t, const float vec[3])
-{
- const bool apply_snap_align_rotation = usingSnappingNormal(
- t); // && (t->tsnap.status & POINT_INIT);
- float tvec[3];
-
- /* The ideal would be "apply_snap_align_rotation" only when a snap point is found
- * so, maybe inside this function is not the best place to apply this rotation.
- * but you need "handle snapping rotation before doing the translation" (really?) */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
-
- float pivot[3];
- if (apply_snap_align_rotation) {
- copy_v3_v3(pivot, t->tsnap.snapTarget);
- /* The pivot has to be in local-space (see T49494) */
- if (tc->use_local_mat) {
- mul_m4_v3(tc->imat, pivot);
- }
- }
-
- TransData *td = tc->data;
- for (int i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- float rotate_offset[3] = {0};
- bool use_rotate_offset = false;
-
- /* handle snapping rotation before doing the translation */
- if (apply_snap_align_rotation) {
- float mat[3][3];
-
- if (validSnappingNormal(t)) {
- const float *original_normal;
-
- /* In pose mode, we want to align normals with Y axis of bones... */
- if (t->flag & T_POSE) {
- original_normal = td->axismtx[1];
- }
- else {
- original_normal = td->axismtx[2];
- }
-
- rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
- }
- else {
- unit_m3(mat);
- }
-
- ElementRotation_ex(t, tc, td, mat, pivot);
-
- if (td->loc) {
- use_rotate_offset = true;
- sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
- }
- }
-
- if (t->con.applyVec) {
- float pvec[3];
- t->con.applyVec(t, tc, td, vec, tvec, pvec);
- }
- else {
- copy_v3_v3(tvec, vec);
- }
-
- mul_m3_v3(td->smtx, tvec);
-
- if (use_rotate_offset) {
- add_v3_v3(tvec, rotate_offset);
- }
-
- if (t->options & CTX_GPENCIL_STROKES) {
- /* grease pencil multiframe falloff */
- bGPDstroke *gps = (bGPDstroke *)td->extra;
- if (gps != NULL) {
- mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
- }
- else {
- mul_v3_fl(tvec, td->factor);
- }
- }
- else {
- /* proportional editing falloff */
- mul_v3_fl(tvec, td->factor);
- }
-
- protectedTransBits(td->protectflag, tvec);
-
- if (td->loc) {
- add_v3_v3v3(td->loc, td->iloc, tvec);
- }
-
- constraintTransLim(t, td);
- }
- }
-}
-
-static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
- float values_final[3];
-
- if (t->flag & T_INPUT_IS_VALUES_FINAL) {
- copy_v3_v3(t->values_final, t->values);
- }
- else {
- copy_v3_v3(t->values_final, t->values);
- if ((t->con.mode & CON_APPLY) == 0) {
- snapGridIncrement(t, t->values_final);
- }
-
- if (applyNumInput(&t->num, t->values_final)) {
- removeAspectRatio(t, t->values_final);
- }
-
- applySnapping(t, t->values_final);
- }
- copy_v3_v3(values_final, t->values_final);
-
- if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
- headerTranslation(t, pvec, str);
-
- /* only so we have re-usable value with redo, see T46741. */
- mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
- }
- else {
- headerTranslation(t, t->values_final, str);
- copy_v3_v3(values_final, t->values_final);
- }
-
- /* don't use 't->values' now on */
-
- applyTranslationValue(t, values_final);
-
- /* evil hack - redo translation if clipping needed */
- if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
- applyTranslationValue(t, values_final);
-
- /* In proportional edit it can happen that */
- /* vertices in the radius of the brush end */
- /* outside the clipping area */
- /* XXX HACK - dg */
- if (t->flag & T_PROP_EDIT_ALL) {
- clipUVData(t);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Shrink-Fatten) */
-
-/** \name Transform Shrink-Fatten
- * \{ */
-
-static void initShrinkFatten(TransInfo *t)
-{
- // If not in mesh edit mode, fallback to Resize
- if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
- initResize(t);
- }
- else {
- t->mode = TFM_SHRINKFATTEN;
- t->transform = applyShrinkFatten;
-
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_LENGTH;
-
- t->flag |= T_NO_CONSTRAINT;
- }
-}
-
-static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
-{
- float distance;
- int i;
- char str[UI_MAX_DRAW_STR];
- size_t ofs = 0;
-
- distance = -t->values[0];
-
- snapGridIncrement(t, &distance);
-
- applyNumInput(&t->num, &distance);
-
- t->values_final[0] = -distance;
-
- /* header print for NumInput */
- ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs);
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c);
- }
- else {
- /* default header print */
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance);
- }
-
- if (t->proptext[0]) {
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext);
- }
- ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs);
-
- if (t->keymap) {
- wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
- if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs);
- }
- }
- BLI_snprintf(str + ofs,
- sizeof(str) - ofs,
- TIP_(" or Alt) Even Thickness %s"),
- WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
- /* done with header string */
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- float tdistance; /* temp dist */
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- /* get the final offset */
- tdistance = distance * td->factor;
- if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) {
- tdistance *= td->ext->isize[0]; /* shell factor */
- }
-
- madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Tilt) */
-
-/** \name Transform Tilt
- * \{ */
-
-static void initTilt(TransInfo *t)
-{
- t->mode = TFM_TILT;
- t->transform = applyTilt;
-
- initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
-
- t->idx_max = 0;
- t->num.idx_max = 0;
- t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
-
- copy_v3_fl(t->num.val_inc, t->snap[2]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
-{
- int i;
- char str[UI_MAX_DRAW_STR];
-
- float final;
-
- final = t->values[0];
-
- snapGridIncrement(t, &final);
-
- applyNumInput(&t->num, &final);
-
- t->values_final[0] = final;
-
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str, sizeof(str), TIP_("Tilt: %s° %s"), &c[0], t->proptext);
-
- /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
- t->values_final[0] = final;
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Curve Shrink/Fatten) */
-
-/** \name Transform Curve Shrink/Fatten
- * \{ */
-
-static void initCurveShrinkFatten(TransInfo *t)
-{
- t->mode = TFM_CURVE_SHRINKFATTEN;
- t->transform = applyCurveShrinkFatten;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
-{
- float ratio;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (td->val) {
- *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) {
- *td->val = 0.001f;
- }
- }
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Mask Shrink/Fatten) */
-
-/** \name Transform Mask Shrink/Fatten
- * \{ */
-
-static void initMaskShrinkFatten(TransInfo *t)
-{
- t->mode = TFM_MASK_SHRINKFATTEN;
- t->transform = applyMaskShrinkFatten;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
-{
- float ratio;
- int i;
- bool initial_feather = false;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %s"), c);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %3f"), ratio);
- }
-
- /* detect if no points have feather yet */
- if (ratio > 1.0f) {
- initial_feather = true;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (td->ival >= 0.001f) {
- initial_feather = false;
- }
- }
- }
- }
-
- /* apply shrink/fatten */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (td->val) {
- if (initial_feather) {
- *td->val = td->ival + (ratio - 1.0f) * 0.01f;
- }
- else {
- *td->val = td->ival * ratio;
- }
-
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) {
- *td->val = 0.001f;
- }
- }
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (GPencil Shrink/Fatten) */
-
-/** \name Transform GPencil Strokes Shrink/Fatten
- * \{ */
-
-static void initGPShrinkFatten(TransInfo *t)
-{
- t->mode = TFM_GPENCIL_SHRINKFATTEN;
- t->transform = applyGPShrinkFatten;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
-{
- float ratio;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (td->val) {
- *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- if (*td->val <= 0.0f) {
- *td->val = 0.001f;
- }
- }
- }
- }
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (GPencil Opacity) */
-
-/** \name Transform GPencil Strokes Opacity
- * \{ */
-
-static void initGPOpacity(TransInfo *t)
-{
- t->mode = TFM_GPENCIL_OPACITY;
- t->transform = applyGPOpacity;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_ZERO;
-#ifdef USE_NUM_NO_ZERO
- t->num.val_flag[0] |= NUM_NO_ZERO;
-#endif
-
- t->flag |= T_NO_CONSTRAINT;
-}
-
-static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
-{
- float ratio;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, sizeof(str), TIP_("Opacity: %s"), c);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- if (td->val) {
- *td->val = td->ival * ratio;
- /* apply PET */
- *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
- CLAMP(*td->val, 0.0f, 1.0f);
- }
- }
- }
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Push/Pull) */
-
-/** \name Transform Push/Pull
- * \{ */
-
-static void initPushPull(TransInfo *t)
-{
- t->mode = TFM_PUSHPULL;
- t->transform = applyPushPull;
-
- initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_LENGTH;
-}
-
-static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
-{
- float vec[3], axis_global[3];
- float distance;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- distance = t->values[0];
-
- snapGridIncrement(t, &distance);
-
- applyNumInput(&t->num, &distance);
-
- t->values_final[0] = distance;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str, sizeof(str), TIP_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
- }
- else {
- /* default header print */
- BLI_snprintf(
- str, sizeof(str), TIP_("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, NULL, axis_global, NULL);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- sub_v3_v3v3(vec, tc->center_local, td->center);
- if (t->con.applyRot && t->con.mode & CON_APPLY) {
- float axis[3];
- copy_v3_v3(axis, axis_global);
- t->con.applyRot(t, tc, td, axis, NULL);
-
- mul_m3_v3(td->smtx, axis);
- if (isLockConstraint(t)) {
- float dvec[3];
- project_v3_v3v3(dvec, vec, axis);
- sub_v3_v3(vec, dvec);
- }
- else {
- project_v3_v3v3(vec, vec, axis);
- }
- }
- normalize_v3_length(vec, distance * td->factor);
-
- add_v3_v3v3(td->loc, td->iloc, vec);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Bevel Weight) */
-
-/** \name Transform Bevel Weight
- * \{ */
-
-static void initBevelWeight(TransInfo *t)
-{
- t->mode = TFM_BWEIGHT;
- t->transform = applyBevelWeight;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
-{
- float weight;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- weight = t->values[0];
-
- CLAMP_MAX(weight, 1.0f);
-
- snapGridIncrement(t, &weight);
-
- applyNumInput(&t->num, &weight);
-
- t->values_final[0] = weight;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (weight >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%s %s"), c, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %s %s"), c, t->proptext);
- }
- }
- else {
- /* default header print */
- if (weight >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%.3f %s"), weight, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %.3f %s"), weight, t->proptext);
- }
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Crease) */
-
-/** \name Transform Crease
- * \{ */
-
-static void initCrease(TransInfo *t)
-{
- t->mode = TFM_CREASE;
- t->transform = applyCrease;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
-{
- float crease;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- crease = t->values[0];
-
- CLAMP_MAX(crease, 1.0f);
-
- snapGridIncrement(t, &crease);
-
- applyNumInput(&t->num, &crease);
-
- t->values_final[0] = crease;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (crease >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Crease: +%s %s"), c, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Crease: %s %s"), c, t->proptext);
- }
- }
- else {
- /* default header print */
- if (crease >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Crease: +%.3f %s"), crease, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Crease: %.3f %s"), crease, t->proptext);
- }
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (EditBone (B-bone) width scaling) */
-
-/** \name Transform B-bone width scaling
- * \{ */
-
-static void initBoneSize(TransInfo *t)
-{
- t->mode = TFM_BONESIZE;
- t->transform = applyBoneSize;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
-
- t->idx_max = 2;
- t->num.idx_max = 2;
- t->num.val_flag[0] |= NUM_NULL_ONE;
- t->num.val_flag[1] |= NUM_NULL_ONE;
- t->num.val_flag[2] |= NUM_NULL_ONE;
- t->num.flag |= NUM_AFFECT_ALL;
- t->snap[0] = 0.0f;
- t->snap[1] = 0.1f;
- t->snap[2] = t->snap[1] * 0.1f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
- t->num.unit_type[1] = B_UNIT_NONE;
- t->num.unit_type[2] = B_UNIT_NONE;
-}
-
-static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
- BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.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) {
- BLI_snprintf(
- str, UI_MAX_DRAW_STR, TIP_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
- }
- else {
- BLI_snprintf(str,
- UI_MAX_DRAW_STR,
- TIP_("ScaleB: %s : %s : %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- t->con.text,
- t->proptext);
- }
- }
- else {
- BLI_snprintf(str,
- UI_MAX_DRAW_STR,
- TIP_("ScaleB X: %s Y: %s Z: %s%s %s"),
- &tvec[0],
- &tvec[NUM_STR_REP_LEN],
- &tvec[NUM_STR_REP_LEN * 2],
- t->con.text,
- t->proptext);
- }
-}
-
-static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
-{
- float tmat[3][3], smat[3][3], oldy;
- float sizemat[3][3];
-
- mul_m3_m3m3(smat, mat, td->mtx);
- mul_m3_m3m3(tmat, td->smtx, smat);
-
- if (t->con.applySize) {
- t->con.applySize(t, tc, td, tmat);
- }
-
- /* we've tucked the scale in loc */
- oldy = td->iloc[1];
- size_to_mat3(sizemat, td->iloc);
- mul_m3_m3m3(tmat, tmat, sizemat);
- mat3_to_size(td->loc, tmat);
- td->loc[1] = oldy;
-}
-
-static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
-{
- float size[3], mat[3][3];
- float ratio = t->values[0];
- int i;
- char str[UI_MAX_DRAW_STR];
-
- copy_v3_fl(size, ratio);
-
- snapGridIncrement(t, size);
-
- if (applyNumInput(&t->num, size)) {
- constraintNumInput(t, size);
- }
-
- copy_v3_v3(t->values_final, size);
-
- size_to_mat3(mat, size);
-
- if (t->con.applySize) {
- t->con.applySize(t, NULL, NULL, mat);
- }
-
- copy_m3_m3(t->mat, mat); // used in gizmo
-
- headerBoneSize(t, size, str);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- ElementBoneSize(t, tc, td, mat);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Bone Envelope) */
-
-/** \name Transform Bone Envelope
- * \{ */
-
-static void initBoneEnvelope(TransInfo *t)
-{
- t->mode = TFM_BONE_ENVELOPE;
- t->transform = applyBoneEnvelope;
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
-{
- float ratio;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- ratio = t->values[0];
-
- snapGridIncrement(t, &ratio);
-
- applyNumInput(&t->num, &ratio);
-
- t->values_final[0] = ratio;
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
- BLI_snprintf(str, sizeof(str), TIP_("Envelope: %s"), c);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Envelope: %3f"), ratio);
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Edge Slide) */
-
-/** \name Transform Edge Slide
- * \{ */
-
-/**
- * Get the first valid EdgeSlideData.
- *
- * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that
- * may leave items with invalid custom data in the transform data container.
- */
-static EdgeSlideData *edgeSlideFirstGet(TransInfo *t)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
- if (sld == NULL) {
- continue;
- }
- return sld;
- }
- BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid");
- return NULL;
-}
-
-static void calcEdgeSlideCustomPoints(struct TransInfo *t)
-{
- EdgeSlideData *sld = edgeSlideFirstGet(t);
-
- setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
-
- /* setCustomPoints isn't normally changing as the mouse moves,
- * in this case apply mouse input immediately so we don't refresh
- * with the value from the previous points */
- applyMouseInput(t, &t->mouse, t->mval, t->values);
-}
-
-static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
-{
- BMIter iter;
- BMEdge *e_iter;
-
- BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) {
- return e_iter;
- }
- }
-
- return NULL;
-}
-
-/* interpoaltes along a line made up of 2 segments (used for edge slide) */
-static void interp_line_v3_v3v3v3(
- float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
-{
- float t_mid, t_delta;
-
- /* could be pre-calculated */
- t_mid = line_point_factor_v3(v2, v1, v3);
-
- t_delta = t - t_mid;
- if (t_delta < 0.0f) {
- if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
- copy_v3_v3(p, v2);
- }
- else {
- interp_v3_v3v3(p, v1, v2, t / t_mid);
- }
- }
- else {
- t = t - t_mid;
- t_mid = 1.0f - t_mid;
-
- if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
- copy_v3_v3(p, v3);
- }
- else {
- interp_v3_v3v3(p, v2, v3, t / t_mid);
- }
- }
-}
-
-/**
- * Find the closest point on the ngon on the opposite side.
- * used to set the edge slide distance for ngons.
- */
-static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3])
-{
- /* skip adjacent edges */
- BMLoop *l_first = l_tmp->next;
- BMLoop *l_last = l_tmp->prev;
- BMLoop *l_iter;
- float dist = FLT_MAX;
- bool found = false;
-
- l_iter = l_first;
- do {
- float tvec[3];
- if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) {
- const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
- /* allow some overlap to avoid missing the intersection because of float precision */
- if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
- /* likelihood of multiple intersections per ngon is quite low,
- * it would have to loop back on its self, but better support it
- * so check for the closest opposite edge */
- const float tdist = len_v3v3(l_tmp->v->co, tvec);
- if (tdist < dist) {
- copy_v3_v3(r_co, tvec);
- dist = tdist;
- found = true;
- }
- }
- }
- } while ((l_iter = l_iter->next) != l_last);
-
- return found;
-}
-
-/**
- * Given 2 edges and a loop, step over the loops
- * and calculate a direction to slide along.
- *
- * \param r_slide_vec: the direction to slide,
- * the length of the vector defines the slide distance.
- */
-static BMLoop *get_next_loop(
- BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
-{
- BMLoop *l_first;
- float vec_accum[3] = {0.0f, 0.0f, 0.0f};
- float vec_accum_len = 0.0f;
- int i = 0;
-
- BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
- BLI_assert(BM_vert_in_edge(l->e, v));
-
- l_first = l;
- do {
- l = BM_loop_other_edge_loop(l, v);
-
- if (l->e == e_next) {
- if (i) {
- normalize_v3_length(vec_accum, vec_accum_len / (float)i);
- }
- else {
- /* When there is no edge to slide along,
- * we must slide along the vector defined by the face we're attach to */
- BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v);
-
- BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next));
-
- if (l_tmp->f->len == 4) {
- /* we could use code below, but in this case
- * sliding diagonally across the quad works well */
- sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co);
- }
- else {
- float tdir[3];
- BM_loop_calc_face_direction(l_tmp, tdir);
- cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
-#if 0
- /* rough guess, we can do better! */
- normalize_v3_length(vec_accum,
- (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
-#else
- /* be clever, check the opposite ngon edge to slide into.
- * this gives best results */
- {
- float tvec[3];
- float dist;
-
- if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) {
- dist = len_v3v3(l_tmp->v->co, tvec);
- }
- else {
- dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
- }
-
- normalize_v3_length(vec_accum, dist);
- }
-#endif
- }
- }
-
- copy_v3_v3(r_slide_vec, vec_accum);
- return l;
- }
- else {
- /* accumulate the normalized edge vector,
- * normalize so some edges don't skew the result */
- float tvec[3];
- sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co);
- vec_accum_len += normalize_v3(tvec);
- add_v3_v3(vec_accum, tvec);
- i += 1;
- }
-
- if (BM_loop_other_edge_loop(l, v)->e == e_next) {
- if (i) {
- normalize_v3_length(vec_accum, vec_accum_len / (float)i);
- }
-
- copy_v3_v3(r_slide_vec, vec_accum);
- return BM_loop_other_edge_loop(l, v);
- }
-
- } while ((l != l->radial_next) && ((l = l->radial_next) != l_first));
-
- if (i) {
- normalize_v3_length(vec_accum, vec_accum_len / (float)i);
- }
-
- copy_v3_v3(r_slide_vec, vec_accum);
-
- return NULL;
-}
-
-/**
- * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
- */
-static void calcEdgeSlide_mval_range(TransInfo *t,
- TransDataContainer *tc,
- EdgeSlideData *sld,
- const int *sv_table,
- const int loop_nr,
- const float mval[2],
- const bool use_occlude_geometry,
- const bool use_calc_direction)
-{
- TransDataEdgeSlideVert *sv_array = sld->sv;
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- ARegion *ar = t->ar;
- View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
- float projectMat[4][4];
- BMBVHTree *bmbvh;
-
- /* only for use_calc_direction */
- float(*loop_dir)[3] = NULL, *loop_maxdist = NULL;
-
- float mval_start[2], mval_end[2];
- float mval_dir[3], dist_best_sq;
- BMIter iter;
- BMEdge *e;
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- }
-
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
- }
-
- if (use_occlude_geometry) {
- bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
- }
- else {
- bmbvh = NULL;
- }
-
- /* find mouse vectors, the global one, and one per loop in case we have
- * multiple loops selected, in case they are oriented different */
- zero_v3(mval_dir);
- dist_best_sq = -1.0f;
-
- if (use_calc_direction) {
- loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
- loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
- copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
- }
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- int i;
-
- /* search cross edges for visible edge to the mouse cursor,
- * then use the shared vertex to calculate screen vector*/
- for (i = 0; i < 2; i++) {
- BMIter iter_other;
- BMEdge *e_other;
-
- BMVert *v = i ? e->v1 : e->v2;
- BM_ITER_ELEM (e_other, &iter_other, v, BM_EDGES_OF_VERT) {
- /* screen-space coords */
- float sco_a[3], sco_b[3];
- float dist_sq;
- int j, l_nr;
-
- if (BM_elem_flag_test(e_other, BM_ELEM_SELECT)) {
- continue;
- }
-
- /* This test is only relevant if object is not wire-drawn! See [#32068]. */
- if (use_occlude_geometry &&
- !BMBVH_EdgeVisible(bmbvh, e_other, t->depsgraph, ar, v3d, tc->obedit)) {
- continue;
- }
-
- BLI_assert(sv_table[BM_elem_index_get(v)] != -1);
- j = sv_table[BM_elem_index_get(v)];
-
- if (sv_array[j].v_side[1]) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[1]->co, sco_b, projectMat);
- }
- else {
- add_v3_v3v3(sco_b, v->co, sv_array[j].dir_side[1]);
- ED_view3d_project_float_v3_m4(ar, sco_b, sco_b, projectMat);
- }
-
- if (sv_array[j].v_side[0]) {
- ED_view3d_project_float_v3_m4(ar, sv_array[j].v_side[0]->co, sco_a, projectMat);
- }
- else {
- add_v3_v3v3(sco_a, v->co, sv_array[j].dir_side[0]);
- ED_view3d_project_float_v3_m4(ar, sco_a, sco_a, projectMat);
- }
-
- /* global direction */
- dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
- if ((dist_best_sq == -1.0f) ||
- /* intentionally use 2d size on 3d vector */
- (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) {
- dist_best_sq = dist_sq;
- sub_v3_v3v3(mval_dir, sco_b, sco_a);
- }
-
- if (use_calc_direction) {
- /* per loop direction */
- l_nr = sv_array[j].loop_nr;
- if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
- loop_maxdist[l_nr] = dist_sq;
- sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
- }
- }
- }
- }
- }
- }
-
- if (use_calc_direction) {
- int i;
- sv_array = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv_array++) {
- /* switch a/b if loop direction is different from global direction */
- int l_nr = sv_array->loop_nr;
- if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
- swap_v3_v3(sv_array->dir_side[0], sv_array->dir_side[1]);
- SWAP(BMVert *, sv_array->v_side[0], sv_array->v_side[1]);
- }
- }
-
- MEM_freeN(loop_dir);
- MEM_freeN(loop_maxdist);
- }
-
- /* possible all of the edge loops are pointing directly at the view */
- if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
- mval_dir[0] = 0.0f;
- mval_dir[1] = 100.0f;
- }
-
- /* zero out start */
- zero_v2(mval_start);
-
- /* dir holds a vector along edge loop */
- copy_v2_v2(mval_end, mval_dir);
- mul_v2_fl(mval_end, 0.5f);
-
- sld->mval_start[0] = t->mval[0] + mval_start[0];
- sld->mval_start[1] = t->mval[1] + mval_start[1];
-
- sld->mval_end[0] = t->mval[0] + mval_end[0];
- sld->mval_end[1] = t->mval[1] + mval_end[1];
-
- if (bmbvh) {
- BKE_bmbvh_free(bmbvh);
- }
-}
-
-static void calcEdgeSlide_even(TransInfo *t,
- TransDataContainer *tc,
- EdgeSlideData *sld,
- const float mval[2])
-{
- TransDataEdgeSlideVert *sv = sld->sv;
-
- if (sld->totsv > 0) {
- ARegion *ar = t->ar;
- RegionView3D *rv3d = NULL;
- float projectMat[4][4];
-
- int i = 0;
-
- float v_proj[2];
- float dist_sq = 0;
- float dist_min_sq = FLT_MAX;
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- rv3d = t->ar ? t->ar->regiondata : NULL;
- }
-
- if (!rv3d) {
- /* ok, let's try to survive this */
- unit_m4(projectMat);
- }
- else {
- ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
- }
-
- for (i = 0; i < sld->totsv; i++, sv++) {
- /* Set length */
- sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
-
- ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
- dist_sq = len_squared_v2v2(mval, v_proj);
- if (dist_sq < dist_min_sq) {
- dist_min_sq = dist_sq;
- sld->curr_sv_index = i;
- }
- }
- }
- else {
- sld->curr_sv_index = 0;
- }
-}
-
-static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
-{
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- BMIter iter;
- BMEdge *e;
- BMVert *v;
- TransDataEdgeSlideVert *sv_array;
- int sv_tot;
- int *sv_table; /* BMVert -> sv_array index */
- EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
- float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- int numsel, i, loop_nr;
- bool use_occlude_geometry = false;
- View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
-
- sld->curr_sv_index = 0;
-
- /*ensure valid selection*/
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- BMIter iter2;
- numsel = 0;
- BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- /* BMESH_TODO: this is probably very evil,
- * set v->e to a selected edge*/
- v->e = e;
-
- numsel++;
- }
- }
-
- if (numsel == 0 || numsel > 2) {
- MEM_freeN(sld);
- return false; /* invalid edge selection */
- }
- }
- }
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- /* note, any edge with loops can work, but we won't get predictable results, so bail out */
- if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) {
- /* can edges with at least once face user */
- MEM_freeN(sld);
- return false;
- }
- }
- }
-
- sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
-
-#define INDEX_UNSET -1
-#define INDEX_INVALID -2
-
- {
- int j = 0;
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- sv_table[i] = INDEX_UNSET;
- j += 1;
- }
- else {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- sv_table[i] = INDEX_INVALID;
- }
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
-
- if (!j) {
- MEM_freeN(sld);
- MEM_freeN(sv_table);
- return false;
- }
- sv_tot = j;
- }
-
- sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
- loop_nr = 0;
-
- STACK_DECLARE(sv_array);
- STACK_INIT(sv_array, sv_tot);
-
- while (1) {
- float vec_a[3], vec_b[3];
- BMLoop *l_a, *l_b;
- BMLoop *l_a_prev, *l_b_prev;
- BMVert *v_first;
- /* If this succeeds call get_next_loop()
- * which calculates the direction to slide based on clever checks.
- *
- * otherwise we simply use 'e_dir' as an edge-rail.
- * (which is better when the attached edge is a boundary, see: T40422)
- */
-#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \
- ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2))
-
- v = NULL;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- break;
- }
- }
-
- if (!v) {
- break;
- }
-
- if (!v->e) {
- continue;
- }
-
- v_first = v;
-
- /*walk along the edge loop*/
- e = v->e;
-
- /*first, rewind*/
- do {
- e = get_other_edge(v, e);
- if (!e) {
- e = v->e;
- break;
- }
-
- if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) {
- break;
- }
-
- v = BM_edge_other_vert(e, v);
- } while (e != v_first->e);
-
- BM_elem_flag_disable(v, BM_ELEM_TAG);
-
- l_a = e->l;
- l_b = e->l->radial_next;
-
- /* regarding e_next, use get_next_loop()'s improved interpolation where possible */
- {
- BMEdge *e_next = get_other_edge(v, e);
- if (e_next) {
- get_next_loop(v, l_a, e, e_next, vec_a);
- }
- else {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_a, e, l_tmp->e, vec_a);
- }
- else {
- sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
- }
- }
- }
-
- /* !BM_edge_is_boundary(e); */
- if (l_b != l_a) {
- BMEdge *e_next = get_other_edge(v, e);
- if (e_next) {
- get_next_loop(v, l_b, e, e_next, vec_b);
- }
- else {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_b, e, l_tmp->e, vec_b);
- }
- else {
- sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
- }
- }
- }
- else {
- l_b = NULL;
- }
-
- l_a_prev = NULL;
- l_b_prev = NULL;
-
-#define SV_FROM_VERT(v) \
- ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \
- ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \
- STACK_PUSH_RET_PTR(sv_array)) : \
- (&sv_array[sv_table[BM_elem_index_get(v)]]))
-
- /*iterate over the loop*/
- v_first = v;
- do {
- bool l_a_ok_prev;
- bool l_b_ok_prev;
- TransDataEdgeSlideVert *sv;
- BMVert *v_prev;
- BMEdge *e_prev;
-
- /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
- BLI_assert(v != NULL);
- BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
- sv = SV_FROM_VERT(v);
- sv->v = v;
- copy_v3_v3(sv->v_co_orig, v->co);
- sv->loop_nr = loop_nr;
-
- if (l_a || l_a_prev) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
- sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_side[0], vec_a);
- }
-
- if (l_b || l_b_prev) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
- sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
- copy_v3_v3(sv->dir_side[1], vec_b);
- }
-
- v_prev = v;
- v = BM_edge_other_vert(e, v);
-
- e_prev = e;
- e = get_other_edge(v, e);
-
- if (!e) {
- BLI_assert(v != NULL);
-
- BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
- sv = SV_FROM_VERT(v);
-
- sv->v = v;
- copy_v3_v3(sv->v_co_orig, v->co);
- sv->loop_nr = loop_nr;
-
- if (l_a) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
- if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
- }
- else {
- sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
- }
- }
-
- if (l_b) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
- if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
- get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
- }
- else {
- sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co);
- }
- }
-
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
-
- break;
- }
- l_a_ok_prev = (l_a != NULL);
- l_b_ok_prev = (l_b != NULL);
-
- l_a_prev = l_a;
- l_b_prev = l_b;
-
- if (l_a) {
- l_a = get_next_loop(v, l_a, e_prev, e, vec_a);
- }
- else {
- zero_v3(vec_a);
- }
-
- if (l_b) {
- l_b = get_next_loop(v, l_b, e_prev, e, vec_b);
- }
- else {
- zero_v3(vec_b);
- }
-
- if (l_a && l_b) {
- /* pass */
- }
- else {
- if (l_a || l_b) {
- /* find the opposite loop if it was missing previously */
- if (l_a == NULL && l_b && (l_b->radial_next != l_b)) {
- l_a = l_b->radial_next;
- }
- else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) {
- l_b = l_a->radial_next;
- }
- }
- else if (e->l != NULL) {
- /* if there are non-contiguous faces, we can still recover
- * the loops of the new edges faces */
-
- /* note!, the behavior in this case means edges may move in opposite directions,
- * this could be made to work more usefully. */
-
- if (l_a_ok_prev) {
- l_a = e->l;
- l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL;
- }
- else if (l_b_ok_prev) {
- l_b = e->l;
- l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL;
- }
- }
-
- if (!l_a_ok_prev && l_a) {
- get_next_loop(v, l_a, e, e_prev, vec_a);
- }
- if (!l_b_ok_prev && l_b) {
- get_next_loop(v, l_b, e, e_prev, vec_b);
- }
- }
-
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
- } while ((e != v_first->e) && (l_a || l_b));
-
-#undef SV_FROM_VERT
-#undef INDEX_UNSET
-#undef INDEX_INVALID
-
- loop_nr++;
-
-#undef EDGESLIDE_VERT_IS_INNER
- }
-
- /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
-
- BLI_assert(STACK_SIZE(sv_array) == sv_tot);
-
- sld->sv = sv_array;
- sld->totsv = sv_tot;
-
- /* use for visibility checks */
- if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
- !XRAY_ENABLED(v3d));
- }
-
- calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
-
- if (rv3d) {
- calcEdgeSlide_even(t, tc, sld, mval);
- }
-
- tc->custom.mode.data = sld;
-
- MEM_freeN(sv_table);
-
- return true;
-}
-
-/**
- * A simple version of #createEdgeSlideVerts_double_side
- * Which assumes the longest unselected.
- */
-static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
-{
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- BMIter iter;
- BMEdge *e;
- TransDataEdgeSlideVert *sv_array;
- int sv_tot;
- int *sv_table; /* BMVert -> sv_array index */
- EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
- float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
- int loop_nr;
- bool use_occlude_geometry = false;
- View3D *v3d = NULL;
- RegionView3D *rv3d = NULL;
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* background mode support */
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- }
-
- sld->curr_sv_index = 0;
- /* ensure valid selection */
- {
- int i = 0, j = 0;
- BMVert *v;
-
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- float len_sq_max = -1.0f;
- BMIter iter2;
- BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- float len_sq = BM_edge_calc_length_squared(e);
- if (len_sq > len_sq_max) {
- len_sq_max = len_sq;
- v->e = e;
- }
- }
- }
-
- if (len_sq_max != -1.0f) {
- j++;
- }
- }
- BM_elem_index_set(v, i); /* set_inline */
- }
- bm->elem_index_dirty &= ~BM_VERT;
-
- if (!j) {
- MEM_freeN(sld);
- return false;
- }
-
- sv_tot = j;
- }
-
- BLI_assert(sv_tot != 0);
- /* over alloc */
- sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
-
- /* same loop for all loops, weak but we dont connect loops in this case */
- loop_nr = 1;
-
- sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
-
- {
- int i = 0, j = 0;
- BMVert *v;
-
- BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
- sv_table[i] = -1;
- if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
- if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
- TransDataEdgeSlideVert *sv;
- sv = &sv_array[j];
- sv->v = v;
- copy_v3_v3(sv->v_co_orig, v->co);
- sv->v_side[0] = BM_edge_other_vert(v->e, v);
- sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
- sv->loop_nr = 0;
- sv_table[i] = j;
- j += 1;
- }
- }
- }
- }
-
- /* check for wire vertices,
- * interpolate the directions of wire verts between non-wire verts */
- if (sv_tot != bm->totvert) {
- const int sv_tot_nowire = sv_tot;
- TransDataEdgeSlideVert *sv_iter = sv_array;
-
- for (int i = 0; i < sv_tot_nowire; i++, sv_iter++) {
- BMIter eiter;
- BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
- /* walk over wire */
- TransDataEdgeSlideVert *sv_end = NULL;
- BMEdge *e_step = e;
- BMVert *v = sv_iter->v;
- int j;
-
- j = sv_tot;
-
- while (1) {
- BMVert *v_other = BM_edge_other_vert(e_step, v);
- int endpoint = ((sv_table[BM_elem_index_get(v_other)] != -1) +
- (BM_vert_is_edge_pair(v_other) == false));
-
- if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
- BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
- (endpoint == 0)) {
- /* scan down the list */
- TransDataEdgeSlideVert *sv;
- BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
- sv_table[BM_elem_index_get(v_other)] = j;
- sv = &sv_array[j];
- sv->v = v_other;
- copy_v3_v3(sv->v_co_orig, v_other->co);
- copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
- j++;
-
- /* advance! */
- v = v_other;
- e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
- }
- else {
- if ((endpoint == 2) && (sv_tot != j)) {
- BLI_assert(BM_elem_index_get(v_other) != -1);
- sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
- }
- break;
- }
- }
-
- if (sv_end) {
- int sv_tot_prev = sv_tot;
- const float *co_src = sv_iter->v->co;
- const float *co_dst = sv_end->v->co;
- const float *dir_src = sv_iter->dir_side[0];
- const float *dir_dst = sv_end->dir_side[0];
- sv_tot = j;
-
- while (j-- != sv_tot_prev) {
- float factor;
- factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
- interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
- }
- }
- }
- }
- }
-
- /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
-
- sld->sv = sv_array;
- sld->totsv = sv_tot;
-
- /* use for visibility checks */
- if (t->spacetype == SPACE_VIEW3D) {
- v3d = t->sa ? t->sa->spacedata.first : NULL;
- rv3d = t->ar ? t->ar->regiondata : NULL;
- use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
- !XRAY_ENABLED(v3d));
- }
-
- calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
-
- if (rv3d) {
- calcEdgeSlide_even(t, tc, sld, mval);
- }
-
- tc->custom.mode.data = sld;
-
- MEM_freeN(sv_table);
-
- return true;
-}
-
-void projectEdgeSlideData(TransInfo *t, bool is_final)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- trans_mesh_customdata_correction_apply(tc, is_final);
- }
-}
-
-void freeEdgeSlideVerts(TransInfo *UNUSED(t),
- TransDataContainer *UNUSED(tc),
- TransCustomData *custom_data)
-{
- EdgeSlideData *sld = custom_data->data;
-
- if (sld == NULL) {
- return;
- }
-
- MEM_freeN(sld->sv);
- MEM_freeN(sld);
-
- custom_data->data = NULL;
-}
-
-static void initEdgeSlide_ex(
- TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
-{
- EdgeSlideData *sld;
- bool ok = false;
-
- t->mode = TFM_EDGE_SLIDE;
- t->transform = applyEdgeSlide;
- t->handleEvent = handleEventEdgeSlide;
-
- {
- EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
- slp->use_even = use_even;
- slp->flipped = flipped;
- /* happens to be best for single-sided */
- if (use_double_side == false) {
- slp->flipped = !flipped;
- }
- slp->perc = 0.0f;
-
- if (!use_clamp) {
- t->flag |= T_ALT_TRANSFORM;
- }
-
- t->custom.mode.data = slp;
- t->custom.mode.use_free = true;
- }
-
- if (use_double_side) {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- ok |= createEdgeSlideVerts_double_side(t, tc);
- }
- }
- else {
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- ok |= createEdgeSlideVerts_single_side(t, tc);
- }
- }
-
- if (!ok) {
- t->state = TRANS_CANCEL;
- return;
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- sld = tc->custom.mode.data;
- if (!sld) {
- continue;
- }
- tc->custom.mode.free_cb = freeEdgeSlideVerts;
- }
-
- trans_mesh_customdata_correction_init(t);
-
- /* set custom point first if you want value to be initialized by init */
- calcEdgeSlideCustomPoints(t);
- initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void initEdgeSlide(TransInfo *t)
-{
- initEdgeSlide_ex(t, true, false, false, true);
-}
-
-static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
-{
- if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
-
- if (slp) {
- switch (event->type) {
- case EKEY:
- if (event->val == KM_PRESS) {
- slp->use_even = !slp->use_even;
- calcEdgeSlideCustomPoints(t);
- return TREDRAW_HARD;
- }
- break;
- case FKEY:
- if (event->val == KM_PRESS) {
- slp->flipped = !slp->flipped;
- calcEdgeSlideCustomPoints(t);
- return TREDRAW_HARD;
- }
- break;
- case CKEY:
- /* use like a modifier key */
- if (event->val == KM_PRESS) {
- t->flag ^= T_ALT_TRANSFORM;
- calcEdgeSlideCustomPoints(t);
- return TREDRAW_HARD;
- }
- break;
- case EVT_MODAL_MAP:
-#if 0
- switch (event->val) {
- case TFM_MODAL_EDGESLIDE_DOWN:
- sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
- return TREDRAW_HARD;
- case TFM_MODAL_EDGESLIDE_UP:
- sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
- return TREDRAW_HARD;
- }
-#endif
- break;
- case MOUSEMOVE:
- calcEdgeSlideCustomPoints(t);
- break;
- default:
- break;
- }
- }
- }
- return TREDRAW_NOTHING;
-}
-
-static void drawEdgeSlide(TransInfo *t)
-{
- if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) {
- const EdgeSlideParams *slp = t->custom.mode.data;
- EdgeSlideData *sld = edgeSlideFirstGet(t);
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
-
- /* Even mode */
- if ((slp->use_even == true) || (is_clamp == false)) {
- const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
-
- GPU_depth_test(false);
-
- GPU_blend(true);
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
-
- GPU_matrix_push();
- GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
-
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
-
- if (slp->use_even == true) {
- float co_a[3], co_b[3], co_mark[3];
- TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- const float fac = (slp->perc + 1.0f) / 2.0f;
- const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
- const float guide_size = ctrl_size - 0.5f;
- const int alpha_shade = -30;
-
- add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
- add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
-
- GPU_line_width(line_size);
- immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- immBeginAtMost(GPU_PRIM_LINES, 4);
- if (curr_sv->v_side[0]) {
- immVertex3fv(pos, curr_sv->v_side[0]->co);
- immVertex3fv(pos, curr_sv->v_co_orig);
- }
- if (curr_sv->v_side[1]) {
- immVertex3fv(pos, curr_sv->v_side[1]->co);
- immVertex3fv(pos, curr_sv->v_co_orig);
- }
- immEnd();
-
- {
- float *co_test = NULL;
- if (slp->flipped) {
- if (curr_sv->v_side[1]) {
- co_test = curr_sv->v_side[1]->co;
- }
- }
- else {
- if (curr_sv->v_side[0]) {
- co_test = curr_sv->v_side[0]->co;
- }
- }
-
- if (co_test != NULL) {
- immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
- GPU_point_size(ctrl_size);
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(pos, co_test);
- immEnd();
- }
- }
-
- immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
- GPU_point_size(guide_size);
- immBegin(GPU_PRIM_POINTS, 1);
- interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
- immVertex3fv(pos, co_mark);
- immEnd();
- }
- else {
- if (is_clamp == false) {
- const int side_index = sld->curr_side_unclamp;
- TransDataEdgeSlideVert *sv;
- int i;
- const int alpha_shade = -160;
-
- GPU_line_width(line_size);
- immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
- immBegin(GPU_PRIM_LINES, sld->totsv * 2);
-
- /* TODO(campbell): Loop over all verts */
- sv = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv++) {
- float a[3], b[3];
-
- if (!is_zero_v3(sv->dir_side[side_index])) {
- copy_v3_v3(a, sv->dir_side[side_index]);
- }
- else {
- copy_v3_v3(a, sv->dir_side[!side_index]);
- }
-
- mul_v3_fl(a, 100.0f);
- negate_v3_v3(b, a);
- add_v3_v3(a, sv->v_co_orig);
- add_v3_v3(b, sv->v_co_orig);
-
- immVertex3fv(pos, a);
- immVertex3fv(pos, b);
- }
- immEnd();
- }
- else {
- BLI_assert(0);
- }
- }
-
- immUnbindProgram();
-
- GPU_matrix_pop();
-
- GPU_blend(false);
-
- GPU_depth_test(true);
- }
- }
-}
-
-static void doEdgeSlide(TransInfo *t, float perc)
-{
- EdgeSlideParams *slp = t->custom.mode.data;
- EdgeSlideData *sld_active = edgeSlideFirstGet(t);
-
- slp->perc = perc;
-
- if (slp->use_even == false) {
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
- if (is_clamp) {
- const int side_index = (perc < 0.0f);
- const float perc_final = fabsf(perc);
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- TransDataEdgeSlideVert *sv = sld->sv;
- for (int i = 0; i < sld->totsv; i++, sv++) {
- madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
- }
- sld->curr_side_unclamp = side_index;
- }
- }
- else {
- const float perc_init = fabsf(perc) *
- ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
- const int side_index = sld_active->curr_side_unclamp;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- TransDataEdgeSlideVert *sv = sld->sv;
- for (int i = 0; i < sld->totsv; i++, sv++) {
- float dir_flip[3];
- float perc_final = perc_init;
- if (!is_zero_v3(sv->dir_side[side_index])) {
- copy_v3_v3(dir_flip, sv->dir_side[side_index]);
- }
- else {
- copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
- perc_final *= -1;
- }
- madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
- }
- }
- }
- }
- else {
- /**
- * Implementation note, even mode ignores the starting positions and uses
- * only the a/b verts, this could be changed/improved so the distance is
- * still met but the verts are moved along their original path (which may not be straight),
- * however how it works now is OK and matches 2.4x - Campbell
- *
- * \note `len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])`
- * is the same as the distance between the original vert locations,
- * same goes for the lines below.
- */
- TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
- const float curr_length_perc = curr_sv->edge_len *
- (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
-
- float co_a[3];
- float co_b[3];
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- EdgeSlideData *sld = tc->custom.mode.data;
-
- if (sld == NULL) {
- continue;
- }
-
- TransDataEdgeSlideVert *sv = sld->sv;
- for (int i = 0; i < sld->totsv; i++, sv++) {
- if (sv->edge_len > FLT_EPSILON) {
- const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
-
- add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
- add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
-
- if (slp->flipped) {
- interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
- }
- else {
- interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
- }
- }
- }
- }
- }
-}
-
-static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
- size_t ofs = 0;
- float final;
- EdgeSlideParams *slp = t->custom.mode.data;
- bool flipped = slp->flipped;
- bool use_even = slp->use_even;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
- const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
-
- final = t->values[0];
-
- snapGridIncrement(t, &final);
-
- /* only do this so out of range values are not displayed */
- if (is_constrained) {
- CLAMP(final, -1.0f, 1.0f);
- }
-
- applyNumInput(&t->num, &final);
-
- t->values_final[0] = final;
-
- /* header string */
- ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs);
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
- }
- else {
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
- }
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even));
- if (use_even) {
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped));
- }
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
- /* done with header string */
-
- /* do stuff here */
- doEdgeSlide(t, final);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Vert Slide) */
-
-/** \name Transform Vert Slide
- * \{ */
-
-static void calcVertSlideCustomPoints(struct TransInfo *t)
-{
- VertSlideParams *slp = t->custom.mode.data;
- VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
-
- const float *co_orig_3d = sv->co_orig_3d;
- const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr];
-
- float co_curr_2d[2], co_orig_2d[2];
-
- int mval_ofs[2], mval_start[2], mval_end[2];
-
- ED_view3d_project_float_v2_m4(t->ar, co_orig_3d, co_orig_2d, sld->proj_mat);
- ED_view3d_project_float_v2_m4(t->ar, co_curr_3d, co_curr_2d, sld->proj_mat);
-
- ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.imval[1] - co_orig_2d[1]);
- ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
- ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
-
- if (slp->flipped && slp->use_even) {
- setCustomPoints(t, &t->mouse, mval_start, mval_end);
- }
- else {
- setCustomPoints(t, &t->mouse, mval_end, mval_start);
- }
-
- /* setCustomPoints isn't normally changing as the mouse moves,
- * in this case apply mouse input immediately so we don't refresh
- * with the value from the previous points */
- applyMouseInput(t, &t->mouse, t->mval, t->values);
-}
-
-/**
- * Run once when initializing vert slide to find the reference edge
- */
-static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
-{
- /* Active object may have no selected vertices. */
- VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- float mval_fl[2] = {UNPACK2(mval)};
- TransDataVertSlideVert *sv;
-
- /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */
- float dist_sq = 0.0f;
- float dist_min_sq = FLT_MAX;
- int i;
-
- for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
- float co_2d[2];
-
- ED_view3d_project_float_v2_m4(t->ar, sv->co_orig_3d, co_2d, sld->proj_mat);
-
- dist_sq = len_squared_v2v2(mval_fl, co_2d);
- if (dist_sq < dist_min_sq) {
- dist_min_sq = dist_sq;
- sld->curr_sv_index = i;
- }
- }
-}
-
-/**
- * Run while moving the mouse to slide along the edge matching the mouse direction
- */
-static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
-{
- VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- float imval_fl[2] = {UNPACK2(t->mouse.imval)};
- float mval_fl[2] = {UNPACK2(mval)};
-
- float dir[3];
- TransDataVertSlideVert *sv;
- int i;
-
- /* note: we could save a matrix-multiply for each vertex
- * by finding the closest edge in local-space.
- * However this skews the outcome with non-uniform-scale. */
-
- /* first get the direction of the original mouse position */
- sub_v2_v2v2(dir, imval_fl, mval_fl);
- ED_view3d_win_to_delta(t->ar, dir, dir, t->zfac);
- normalize_v3(dir);
-
- for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
- if (sv->co_link_tot > 1) {
- float dir_dot_best = -FLT_MAX;
- int co_link_curr_best = -1;
- int j;
-
- for (j = 0; j < sv->co_link_tot; j++) {
- float tdir[3];
- float dir_dot;
-
- sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
- mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir);
- project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
-
- normalize_v3(tdir);
- dir_dot = dot_v3v3(dir, tdir);
- if (dir_dot > dir_dot_best) {
- dir_dot_best = dir_dot;
- co_link_curr_best = j;
- }
- }
-
- if (co_link_curr_best != -1) {
- sv->co_link_curr = co_link_curr_best;
- }
- }
- }
-}
-
-static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
-{
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
- BMesh *bm = em->bm;
- BMIter iter;
- BMIter eiter;
- BMEdge *e;
- BMVert *v;
- TransDataVertSlideVert *sv_array;
- VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
- int j;
-
- sld->curr_sv_index = 0;
-
- j = 0;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- bool ok = false;
- if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) {
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- ok = true;
- break;
- }
- }
- }
-
- if (ok) {
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- j += 1;
- }
- else {
- BM_elem_flag_disable(v, BM_ELEM_TAG);
- }
- }
-
- if (!j) {
- MEM_freeN(sld);
- return false;
- }
-
- sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array");
-
- j = 0;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
- int k;
- sv_array[j].v = v;
- copy_v3_v3(sv_array[j].co_orig_3d, v->co);
-
- k = 0;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- k++;
- }
- }
-
- sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k,
- __func__);
- sv_array[j].co_link_tot = k;
-
- k = 0;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- BMVert *v_other = BM_edge_other_vert(e, v);
- copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
- k++;
- }
- }
- j++;
- }
- }
-
- sld->sv = sv_array;
- sld->totsv = j;
-
- tc->custom.mode.data = sld;
-
- /* most likely will be set below */
- unit_m4(sld->proj_mat);
-
- if (t->spacetype == SPACE_VIEW3D) {
- /* view vars */
- RegionView3D *rv3d = NULL;
- ARegion *ar = t->ar;
-
- rv3d = ar ? ar->regiondata : NULL;
- if (rv3d) {
- ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
- }
- }
-
- /* XXX, calc vert slide across all objects */
- if (tc == t->data_container) {
- calcVertSlideMouseActiveVert(t, t->mval);
- calcVertSlideMouseActiveEdges(t, t->mval);
- }
-
- return true;
-}
-
-void projectVertSlideData(TransInfo *t, bool is_final)
-{
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- trans_mesh_customdata_correction_apply(tc, is_final);
- }
-}
-
-void freeVertSlideVerts(TransInfo *UNUSED(t),
- TransDataContainer *UNUSED(tc),
- TransCustomData *custom_data)
-{
- VertSlideData *sld = custom_data->data;
-
- if (!sld) {
- return;
- }
-
- if (sld->totsv > 0) {
- TransDataVertSlideVert *sv = sld->sv;
- int i = 0;
- for (i = 0; i < sld->totsv; i++, sv++) {
- MEM_freeN(sv->co_link_orig_3d);
- }
- }
-
- MEM_freeN(sld->sv);
- MEM_freeN(sld);
-
- custom_data->data = NULL;
-}
-
-static void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
-{
-
- t->mode = TFM_VERT_SLIDE;
- t->transform = applyVertSlide;
- t->handleEvent = handleEventVertSlide;
-
- {
- VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
- slp->use_even = use_even;
- slp->flipped = flipped;
- slp->perc = 0.0f;
-
- if (!use_clamp) {
- t->flag |= T_ALT_TRANSFORM;
- }
-
- t->custom.mode.data = slp;
- t->custom.mode.use_free = true;
- }
-
- bool ok = false;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- ok |= createVertSlideVerts(t, tc);
- VertSlideData *sld = tc->custom.mode.data;
- if (sld) {
- tc->custom.mode.free_cb = freeVertSlideVerts;
- }
- }
-
- if (ok == false) {
- t->state = TRANS_CANCEL;
- return;
- }
-
- trans_mesh_customdata_correction_init(t);
-
- /* set custom point first if you want value to be initialized by init */
- calcVertSlideCustomPoints(t);
- initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void initVertSlide(TransInfo *t)
-{
- initVertSlide_ex(t, false, false, true);
-}
-
-static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
-{
- if (t->mode == TFM_VERT_SLIDE) {
- VertSlideParams *slp = t->custom.mode.data;
-
- if (slp) {
- switch (event->type) {
- case EKEY:
- if (event->val == KM_PRESS) {
- slp->use_even = !slp->use_even;
- if (slp->flipped) {
- calcVertSlideCustomPoints(t);
- }
- return TREDRAW_HARD;
- }
- break;
- case FKEY:
- if (event->val == KM_PRESS) {
- slp->flipped = !slp->flipped;
- calcVertSlideCustomPoints(t);
- return TREDRAW_HARD;
- }
- break;
- case CKEY:
- /* use like a modifier key */
- if (event->val == KM_PRESS) {
- t->flag ^= T_ALT_TRANSFORM;
- calcVertSlideCustomPoints(t);
- return TREDRAW_HARD;
- }
- break;
-#if 0
- case EVT_MODAL_MAP:
- switch (event->val) {
- case TFM_MODAL_EDGESLIDE_DOWN:
- sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
- break;
- case TFM_MODAL_EDGESLIDE_UP:
- sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
- break;
- }
- break;
-#endif
- case MOUSEMOVE: {
- /* don't recalculate the best edge */
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
- if (is_clamp) {
- calcVertSlideMouseActiveEdges(t, event->mval);
- }
- calcVertSlideCustomPoints(t);
- break;
- }
- default:
- break;
- }
- }
- }
- return TREDRAW_NOTHING;
-}
-
-static void drawVertSlide(TransInfo *t)
-{
- if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
- const VertSlideParams *slp = t->custom.mode.data;
- VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
-
- /* Non-Prop mode */
- {
- TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
- TransDataVertSlideVert *sv;
- const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
- const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
- const int alpha_shade = -160;
- int i;
-
- GPU_depth_test(false);
-
- GPU_blend(true);
- GPU_blend_set_func_separate(
- GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
-
- GPU_matrix_push();
- GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
-
- GPU_line_width(line_size);
-
- const uint shdr_pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
-
- immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
- immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
-
- immBegin(GPU_PRIM_LINES, sld->totsv * 2);
- if (is_clamp) {
- sv = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv++) {
- immVertex3fv(shdr_pos, sv->co_orig_3d);
- immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]);
- }
- }
- else {
- sv = sld->sv;
- for (i = 0; i < sld->totsv; i++, sv++) {
- float a[3], b[3];
- sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
- mul_v3_fl(a, 100.0f);
- negate_v3_v3(b, a);
- add_v3_v3(a, sv->co_orig_3d);
- add_v3_v3(b, sv->co_orig_3d);
-
- immVertex3fv(shdr_pos, a);
- immVertex3fv(shdr_pos, b);
- }
- }
- immEnd();
-
- GPU_point_size(ctrl_size);
-
- immBegin(GPU_PRIM_POINTS, 1);
- immVertex3fv(shdr_pos,
- (slp->flipped && slp->use_even) ?
- curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
- curr_sv->co_orig_3d);
- immEnd();
-
- immUnbindProgram();
-
- /* direction from active vertex! */
- if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) {
- float zfac;
- float mval_ofs[2];
- float co_orig_3d[3];
- float co_dest_3d[3];
-
- mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
- mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
-
- mul_v3_m4v3(
- co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d);
- zfac = ED_view3d_calc_zfac(t->ar->regiondata, co_orig_3d, NULL);
-
- ED_view3d_win_to_delta(t->ar, mval_ofs, co_dest_3d, zfac);
-
- invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat,
- TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
- mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d);
-
- add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
-
- GPU_line_width(1.0f);
-
- immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
-
- float viewport_size[4];
- GPU_viewport_size_get_f(viewport_size);
- immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
-
- immUniform1i("colors_len", 0); /* "simple" mode */
- immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- immUniform1f("dash_width", 6.0f);
- immUniform1f("dash_factor", 0.5f);
-
- immBegin(GPU_PRIM_LINES, 2);
- immVertex3fv(shdr_pos, curr_sv->co_orig_3d);
- immVertex3fv(shdr_pos, co_dest_3d);
- immEnd();
-
- immUnbindProgram();
- }
-
- GPU_matrix_pop();
-
- GPU_depth_test(true);
- }
- }
-}
-
-static void doVertSlide(TransInfo *t, float perc)
-{
- VertSlideParams *slp = t->custom.mode.data;
-
- slp->perc = perc;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- VertSlideData *sld = tc->custom.mode.data;
- TransDataVertSlideVert *svlist = sld->sv, *sv;
- int i;
-
- sv = svlist;
-
- if (slp->use_even == false) {
- for (i = 0; i < sld->totsv; i++, sv++) {
- interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
- }
- }
- else {
- TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
- const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d,
- sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
- const float tperc = perc * edge_len_curr;
-
- for (i = 0; i < sld->totsv; i++, sv++) {
- float edge_len;
- float dir[3];
-
- sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
- edge_len = normalize_v3(dir);
-
- if (edge_len > FLT_EPSILON) {
- if (slp->flipped) {
- madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
- }
- else {
- madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
- }
- }
- else {
- copy_v3_v3(sv->v->co, sv->co_orig_3d);
- }
- }
- }
- }
-}
-
-static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
- size_t ofs = 0;
- float final;
- VertSlideParams *slp = t->custom.mode.data;
- const bool flipped = slp->flipped;
- const bool use_even = slp->use_even;
- const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
- const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
-
- final = t->values[0];
-
- snapGridIncrement(t, &final);
-
- /* only do this so out of range values are not displayed */
- if (is_constrained) {
- CLAMP(final, 0.0f, 1.0f);
- }
-
- applyNumInput(&t->num, &final);
-
- t->values_final[0] = final;
-
- /* header string */
- ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs);
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c, &t->scene->unit);
- ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
- }
- else {
- ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
- }
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even));
- if (use_even) {
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped));
- }
- ofs += BLI_snprintf(
- str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
- /* done with header string */
-
- /* do stuff here */
- doVertSlide(t, final);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (EditBone Roll) */
-
-/** \name Transform EditBone Roll
- * \{ */
-
-static void initBoneRoll(TransInfo *t)
-{
- t->mode = TFM_BONE_ROLL;
- t->transform = applyBoneRoll;
-
- initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
-
- t->idx_max = 0;
- t->num.idx_max = 0;
- t->snap[0] = 0.0f;
- t->snap[1] = DEG2RAD(5.0);
- t->snap[2] = DEG2RAD(1.0);
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
- t->num.unit_type[0] = B_UNIT_ROTATION;
-
- t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
-}
-
-static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
-{
- int i;
- char str[UI_MAX_DRAW_STR];
-
- float final;
-
- final = t->values[0];
-
- snapGridIncrement(t, &final);
-
- applyNumInput(&t->num, &final);
-
- t->values_final[0] = final;
-
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- BLI_snprintf(str, sizeof(str), TIP_("Roll: %s"), &c[0]);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Roll: %.2f"), RAD2DEGF(final));
- }
-
- /* set roll values */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- *(td->val) = td->ival - final;
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Bake-Time) */
-
-/** \name Transform Bake-Time
- * \{ */
-
-static void initBakeTime(TransInfo *t)
-{
- t->transform = applyBakeTime;
- initMouseInputMode(t, &t->mouse, INPUT_NONE);
-
- 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;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */
-}
-
-static void applyBakeTime(TransInfo *t, const int mval[2])
-{
- float time;
- int i;
- char str[UI_MAX_DRAW_STR];
-
- float fac = 0.1f;
-
- /* XXX, disable precision for now,
- * this isn't even accessible by the user */
-#if 0
- if (t->mouse.precision) {
- /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
- time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac;
- time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time);
- }
- else
-#endif
- {
- time = (float)(t->center2d[0] - mval[0]) * fac;
- }
-
- snapGridIncrement(t, &time);
-
- applyNumInput(&t->num, &time);
-
- /* header print for NumInput */
- if (hasNumInput(&t->num)) {
- char c[NUM_STR_REP_LEN];
-
- outputNumInput(&(t->num), c, &t->scene->unit);
-
- if (time >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Time: +%s %s"), c, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Time: %s %s"), c, t->proptext);
- }
- }
- else {
- /* default header print */
- if (time >= 0.0f) {
- BLI_snprintf(str, sizeof(str), TIP_("Time: +%.3f %s"), time, t->proptext);
- }
- else {
- BLI_snprintf(str, sizeof(str), TIP_("Time: %.3f %s"), time, t->proptext);
- }
- }
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Mirror) */
-
-/** \name Transform Mirror
- * \{ */
-
-static void initMirror(TransInfo *t)
-{
- t->transform = applyMirror;
- initMouseInputMode(t, &t->mouse, INPUT_NONE);
-
- t->flag |= T_NULL_ONE;
- if ((t->flag & T_EDIT) == 0) {
- t->flag |= T_NO_ZERO;
- }
-}
-
-static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
-{
- float size[3], mat[3][3];
- int i;
- char str[UI_MAX_DRAW_STR];
- copy_v3_v3(t->values_final, t->values);
-
- /*
- * OPTIMIZATION:
- * 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;
-
- size_to_mat3(mat, size);
-
- if (t->con.applySize) {
- t->con.applySize(t, NULL, NULL, mat);
- }
-
- BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- ElementResize(t, tc, td, mat);
- }
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
- }
- else {
- size[0] = size[1] = size[2] = 1;
-
- size_to_mat3(mat, size);
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- ElementResize(t, tc, td, mat);
- }
- }
-
- recalcData(t);
-
- if (t->flag & T_2D_EDIT) {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y)"));
- }
- else {
- ED_area_status_text(t->sa, TIP_("Select a mirror axis (X, Y, Z)"));
- }
- }
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Align) */
-
-/** \name Transform Align
- * \{ */
-
-static void initAlign(TransInfo *t)
-{
- t->flag |= T_NO_CONSTRAINT;
-
- t->transform = applyAlign;
-
- initMouseInputMode(t, &t->mouse, INPUT_NONE);
-}
-
-static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
-{
- float center[3];
- int i;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- /* saving original center */
- copy_v3_v3(center, tc->center_local);
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; 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)) {
- copy_v3_v3(tc->center_local, td->center);
- }
- else {
- if (t->settings->selectmode & SCE_SELECT_FACE) {
- copy_v3_v3(tc->center_local, td->center);
- }
- }
-
- invert_m3_m3(invmat, td->axismtx);
-
- mul_m3_m3m3(mat, t->spacemtx, invmat);
-
- ElementRotation(t, tc, td, mat, t->around);
- }
- /* restoring original center */
- copy_v3_v3(tc->center_local, center);
- }
-
- recalcData(t);
-
- ED_area_status_text(t->sa, TIP_("Align"));
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Sequencer Slide) */
-
-/** \name Transform Sequencer Slide
- * \{ */
-
-static void initSeqSlide(TransInfo *t)
-{
- t->transform = applySeqSlide;
-
- initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
-
- t->idx_max = 1;
- t->num.flag = 0;
- t->num.idx_max = t->idx_max;
-
- t->snap[0] = 0.0f;
- t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
- t->snap[2] = 10.0f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- /* Would be nice to have a time handling in units as well
- * (supporting frames in addition to "natural" time...). */
- t->num.unit_type[0] = B_UNIT_NONE;
- t->num.unit_type[1] = B_UNIT_NONE;
-}
-
-static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
- size_t ofs = 0;
-
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
- }
-
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
-
- if (t->keymap) {
- wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
- if (kmi) {
- ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs);
- }
- }
- ofs += BLI_snprintf(str + ofs,
- UI_MAX_DRAW_STR - ofs,
- TIP_(" or Alt) Expand to fit %s"),
- WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
-}
-
-static void applySeqSlideValue(TransInfo *t, const float val[2])
-{
- int i;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- if (td->flag & TD_NOACTION) {
- break;
- }
-
- if (td->flag & TD_SKIP) {
- continue;
- }
-
- madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
- }
- }
-}
-
-static void applySeqSlide(TransInfo *t, const int mval[2])
-{
- char str[UI_MAX_DRAW_STR];
-
- snapSequenceBounds(t, mval);
-
- if (t->con.mode & CON_APPLY) {
- float pvec[3] = {0.0f, 0.0f, 0.0f};
- float tvec[3];
- t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
- copy_v3_v3(t->values_final, tvec);
- }
- else {
- // snapGridIncrement(t, t->values);
- applyNumInput(&t->num, t->values);
- copy_v3_v3(t->values_final, t->values);
- }
-
- t->values_final[0] = floorf(t->values_final[0] + 0.5f);
- t->values_final[1] = floorf(t->values_final[1] + 0.5f);
-
- headerSeqSlide(t, t->values_final, str);
- applySeqSlideValue(t, t->values_final);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Animation Editors - Transform Utils
- *
- * Special Helpers for Various Settings
- */
-
-/** \name Animation Editor Utils
- * \{ */
-
-/* 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;
-
- if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
-
- if (saction) {
- autosnap = saction->autosnap;
- }
- }
- else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
-
- if (sipo) {
- autosnap = sipo->autosnap;
- }
- }
- else if (t->spacetype == SPACE_NLA) {
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
-
- if (snla) {
- autosnap = snla->autosnap;
- }
- }
- else {
- autosnap = SACTSNAP_OFF;
- }
-
- /* toggle autosnap on/off
- * - when toggling on, prefer nearest frame over 1.0 frame increments
- */
- if (t->modifiers & MOD_SNAP_INVERT) {
- if (autosnap) {
- autosnap = SACTSNAP_OFF;
- }
- else {
- autosnap = SACTSNAP_FRAME;
- }
- }
-
- return autosnap;
-}
-
-/* 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, TransData2D *td2d, AnimData *adt, short autosnap)
-{
- if (ELEM(autosnap, SACTSNAP_FRAME, SACTSNAP_SECOND, SACTSNAP_MARKER)) {
- float val;
-
- /* convert frame to nla-action time (if needed) */
- if (adt) {
- val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
- }
- else {
- val = *(td->val);
- }
-
- snapFrameTransform(t, autosnap, true, val, &val);
-
- /* convert frame out of nla-action time */
- if (adt) {
- *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
- }
- else {
- *(td->val) = val;
- }
- }
-
- /* If the handles are to be moved too
- * (as side-effect of keyframes moving, to keep the general effect)
- * offset them by the same amount so that the general angles are maintained
- * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked).
- */
- if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
- td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival;
- }
- if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
- td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival;
- }
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Animation Translation) */
-
-/** \name Transform Animation Translation
- * \{ */
-
-static void initTimeTranslate(TransInfo *t)
-{
- /* this tool is only really available in the Action Editor... */
- if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) {
- t->state = TRANS_CANCEL;
- }
-
- t->mode = TFM_TIME_TRANSLATE;
- t->transform = applyTimeTranslate;
-
- initMouseInputMode(t, &t->mouse, INPUT_NONE);
-
- /* num-input has max of (n-1) */
- t->idx_max = 0;
- t->num.flag = 0;
- t->num.idx_max = t->idx_max;
-
- /* initialize snap like for everything else */
- t->snap[0] = 0.0f;
- t->snap[1] = t->snap[2] = 1.0f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- /* No time unit supporting frames currently... */
- t->num.unit_type[0] = B_UNIT_NONE;
-}
-
-static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
- int ofs = 0;
-
- /* if numeric input is active, use results from that, otherwise apply snapping to result */
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- const short autosnap = getAnimEdit_SnapMode(t);
- float val = t->values_final[0];
-
- float snap_val;
- snapFrameTransform(t, autosnap, false, val, &snap_val);
-
- if (autosnap == SACTSNAP_FRAME) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
- }
- else if (autosnap == SACTSNAP_SECOND) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
- }
- else if (autosnap == SACTSNAP_TSTEP) {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
- }
- }
-
- ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]);
-
- if (t->flag & T_PROP_EDIT_ALL) {
- ofs += BLI_snprintf(
- str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
- }
-}
-
-static void applyTimeTranslateValue(TransInfo *t, float value)
-{
- Scene *scene = t->scene;
- int i;
-
- const short autosnap = getAnimEdit_SnapMode(t);
- const double secf = FPS;
-
- float deltax, val /* , valprev */;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- TransData2D *td2d = tc->data_2d;
- /* It doesn't matter whether we apply to t->data or
- * t->data2d, but t->data2d is more convenient. */
- for (i = 0; i < tc->data_len; i++, td++, td2d++) {
- /* It is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from.
- * (this is only valid when not in NLA)
- * (also: masks and gpencil dont have animadata)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
-
- /* valprev = *td->val; */ /* UNUSED */
-
- /* check if any need to apply nla-mapping */
- if (adt && (t->spacetype != SPACE_SEQ)) {
- deltax = value;
-
- if (autosnap == SACTSNAP_TSTEP) {
- deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- deltax = floorf(deltax + 0.5f);
- }
-
- val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
- val += deltax * td->factor;
- *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
- }
- else {
- deltax = val = t->values_final[0];
-
- if (autosnap == SACTSNAP_TSTEP) {
- val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- val = floorf(val + 0.5f);
- }
-
- *(td->val) = td->ival + val * td->factor;
- }
-
- /* apply nearest snapping */
- doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
- }
- }
-}
-
-static void applyTimeTranslate(TransInfo *t, const int mval[2])
-{
- View2D *v2d = (View2D *)t->view;
- char str[UI_MAX_DRAW_STR];
-
- /* calculate translation amount from mouse movement - in 'time-grid space' */
- if (t->flag & T_MODAL) {
- float cval[2], sval[2];
- UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[0], &sval[0], &sval[1]);
-
- /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
- t->values[0] = cval[0] - sval[0];
- }
-
- /* handle numeric-input stuff */
- t->vec[0] = t->values[0];
- applyNumInput(&t->num, &t->vec[0]);
- t->values_final[0] = t->vec[0];
- headerTimeTranslate(t, str);
-
- applyTimeTranslateValue(t, t->values_final[0]);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Animation Time Slide) */
-
-/** \name Transform Animation Time Slide
- * \{ */
-
-static 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;
- }
- else {
- t->state = TRANS_CANCEL;
- }
-
- t->mode = TFM_TIME_SLIDE;
- t->transform = applyTimeSlide;
-
- initMouseInputMode(t, &t->mouse, INPUT_NONE);
-
- {
- Scene *scene = t->scene;
- float *range;
- t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max");
- t->custom.mode.use_free = true;
-
- float min = 999999999.0f, max = -999999999.0f;
- int i;
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float val = *(td->val);
-
- /* strip/action time to global (mapped) time */
- if (adt) {
- val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
- }
-
- if (min > val) {
- min = val;
- }
- if (max < val) {
- max = val;
- }
- }
- }
-
- if (min == max) {
- /* just use the current frame ranges */
- min = (float)PSFRA;
- max = (float)PEFRA;
- }
-
- range[0] = min;
- range[1] = max;
- }
-
- /* num-input has max of (n-1) */
- t->idx_max = 0;
- t->num.flag = 0;
- t->num.idx_max = t->idx_max;
-
- /* initialize snap like for everything else */
- t->snap[0] = 0.0f;
- t->snap[1] = t->snap[2] = 1.0f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- /* No time unit supporting frames currently... */
- t->num.unit_type[0] = B_UNIT_NONE;
-}
-
-static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
-
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- const float *range = t->custom.mode.data;
- float minx = range[0];
- float maxx = range[1];
- float cval = t->values_final[0];
- float val;
-
- val = 2.0f * (cval - sval) / (maxx - minx);
- CLAMP(val, -1.0f, 1.0f);
-
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
- }
-
- BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("TimeSlide: %s"), &tvec[0]);
-}
-
-static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
-{
- int i;
- const float *range = t->custom.mode.data;
- float minx = range[0];
- float maxx = range[1];
-
- /* set value for drawing black line */
- if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
- saction->timeslide = cval;
- }
-
- /* It doesn't matter whether we apply to t->data or
- * t->data2d, but t->data2d is more convenient. */
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- for (i = 0; i < tc->data_len; i++, td++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
- * (this is only valid when not in NLA)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
-
- /* only apply to data if in range */
- if ((sval > minx) && (sval < maxx)) {
- float cvalc = CLAMPIS(cval, minx, maxx);
- float ival = td->ival;
- float timefac;
-
- /* NLA mapping magic here works as follows:
- * - "ival" goes from strip time to global time
- * - calculation is performed into td->val in global time
- * (since sval and min/max are all in global time)
- * - "td->val" then gets put back into strip time
- */
- if (adt) {
- /* strip to global */
- ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
- }
-
- /* left half? */
- if (ival < sval) {
- timefac = (sval - ival) / (sval - minx);
- *(td->val) = cvalc - timefac * (cvalc - minx);
- }
- else {
- timefac = (ival - sval) / (maxx - sval);
- *(td->val) = cvalc + timefac * (maxx - cvalc);
- }
-
- if (adt) {
- /* global to strip */
- *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
- }
- }
- }
- }
-}
-
-static void applyTimeSlide(TransInfo *t, const int mval[2])
-{
- View2D *v2d = (View2D *)t->view;
- float cval[2], sval[2];
- const float *range = t->custom.mode.data;
- float minx = range[0];
- float maxx = range[1];
- char str[UI_MAX_DRAW_STR];
-
- /* calculate mouse co-ordinates */
- UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
- UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]);
-
- /* t->values_final[0] stores cval[0], which is the current mouse-pointer location (in frames) */
- // XXX Need to be able to repeat this
- /* t->values_final[0] = cval[0]; */ /* UNUSED (reset again later). */
-
- /* handle numeric-input stuff */
- t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
- applyNumInput(&t->num, &t->vec[0]);
- t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0];
-
- headerTimeSlide(t, sval[0], str);
- applyTimeSlideValue(t, sval[0], t->values_final[0]);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/* Transform (Animation Time Scale) */
-
-/** \name Transform Animation Time Scale
- * \{ */
-
-static void initTimeScale(TransInfo *t)
-{
- float center[2];
-
- /* this tool is only really available in the Action Editor
- * AND NLA Editor (for strip scaling)
- */
- if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) {
- t->state = TRANS_CANCEL;
- }
-
- t->mode = TFM_TIME_SCALE;
- t->transform = applyTimeScale;
-
- /* recalculate center2d to use CFRA and mouse Y, since that's
- * what is used in time scale */
- if ((t->flag & T_OVERRIDE_CENTER) == 0) {
- t->center_global[0] = t->scene->r.cfra;
- projectFloatView(t, t->center_global, center);
- center[1] = t->mouse.imval[1];
- }
-
- /* force a reinit with the center2d used here */
- initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
-
- initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
-
- t->flag |= T_NULL_ONE;
- t->num.val_flag[0] |= 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;
-
- /* initialize snap like for everything else */
- t->snap[0] = 0.0f;
- t->snap[1] = t->snap[2] = 1.0f;
-
- copy_v3_fl(t->num.val_inc, t->snap[1]);
- t->num.unit_sys = t->scene->unit.system;
- t->num.unit_type[0] = B_UNIT_NONE;
-}
-
-static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
-{
- char tvec[NUM_STR_REP_LEN * 3];
-
- if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec, &t->scene->unit);
- }
- else {
- BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values_final[0]);
- }
-
- BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("ScaleX: %s"), &tvec[0]);
-}
-
-static void applyTimeScaleValue(TransInfo *t, float value)
-{
- Scene *scene = t->scene;
- int i;
-
- const short autosnap = getAnimEdit_SnapMode(t);
- const double secf = FPS;
-
- FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- TransData *td = tc->data;
- TransData2D *td2d = tc->data_2d;
- for (i = 0; i < tc->data_len; i++, td++, td2d++) {
- /* it is assumed that td->extra is a pointer to the AnimData,
- * whose active action is where this keyframe comes from
- * (this is only valid when not in NLA)
- */
- AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
- float startx = CFRA;
- float fac = value;
-
- if (autosnap == SACTSNAP_TSTEP) {
- fac = (float)(floor((double)fac / secf + 0.5) * secf);
- }
- else if (autosnap == SACTSNAP_STEP) {
- fac = floorf(fac + 0.5f);
- }
-
- /* take proportional editing into account */
- fac = ((fac - 1.0f) * td->factor) + 1;
-
- /* check if any need to apply nla-mapping */
- if (adt) {
- startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
- }
-
- /* now, calculate the new value */
- *(td->val) = ((td->ival - startx) * fac) + startx;
-
- /* apply nearest snapping */
- doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
- }
- }
-}
-
-static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
-{
- char str[UI_MAX_DRAW_STR];
-
- /* handle numeric-input stuff */
- t->vec[0] = t->values[0];
- applyNumInput(&t->num, &t->vec[0]);
- t->values_final[0] = t->vec[0];
- headerTimeScale(t, str);
-
- applyTimeScaleValue(t, t->values_final[0]);
-
- recalcData(t);
-
- ED_area_status_text(t->sa, str);
-}
-/** \} */
-
/* TODO, move to: transform_query.c */
bool checkUseAxisMatrix(TransInfo *t)
{
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 95506918d98..503e7bd4691 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -24,8 +24,8 @@
#ifndef __TRANSFORM_H__
#define __TRANSFORM_H__
-#include "ED_transform.h"
#include "ED_numinput.h"
+#include "ED_transform.h"
#include "ED_view3d.h"
#include "RE_engine.h"
@@ -270,114 +270,6 @@ typedef struct TransDataNla {
int handle;
} TransDataNla;
-struct LinkNode;
-
-/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
-typedef struct TransDataGenericSlideVert {
- struct BMVert *v;
- struct LinkNode **cd_loop_groups;
- float co_orig_3d[3];
-} TransDataGenericSlideVert;
-
-typedef struct TransDataEdgeSlideVert {
- /** #TransDataGenericSlideVert (header) */
- struct BMVert *v;
- struct LinkNode **cd_loop_groups;
- float v_co_orig[3];
- /* end generic */
-
- float edge_len;
-
- struct BMVert *v_side[2];
-
- /* add origvert.co to get the original locations */
- float dir_side[2][3];
-
- int loop_nr;
-} TransDataEdgeSlideVert;
-
-typedef struct EdgeSlideData {
- TransDataEdgeSlideVert *sv;
- int totsv;
-
- int mval_start[2], mval_end[2];
- int curr_sv_index;
-
- /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
- int curr_side_unclamp;
-} EdgeSlideData;
-
-typedef struct EdgeSlideParams {
- float perc;
-
- bool use_even;
- bool flipped;
-} EdgeSlideParams;
-
-typedef struct TransDataVertSlideVert {
- /** #TransDataGenericSlideVert (header) */
- struct BMVert *v;
- struct LinkNode **cd_loop_groups;
- float co_orig_3d[3];
- /* end generic */
-
- float (*co_link_orig_3d)[3];
- int co_link_tot;
- int co_link_curr;
-} TransDataVertSlideVert;
-
-typedef struct VertSlideData {
- TransDataVertSlideVert *sv;
- int totsv;
- int curr_sv_index;
-
- /* result of ED_view3d_ob_project_mat_get */
- float proj_mat[4][4];
-} VertSlideData;
-
-typedef struct VertSlideParams {
- float perc;
-
- bool use_even;
- bool flipped;
-} VertSlideParams;
-
-typedef struct BoneInitData {
- struct EditBone *bone;
- float tail[3];
- float rad_head;
- float rad_tail;
- float roll;
- float head[3];
- float dist;
- float xwidth;
- float zwidth;
-} BoneInitData;
-
-typedef struct PoseInitData_Mirror {
- /** Points to the bone which this info is initialized & restored to.
- * A NULL value is used to terminate the array. */
- struct bPoseChannel *pchan;
- struct {
- float loc[3];
- float size[3];
- union {
- float eul[3];
- float quat[4];
- float axis_angle[4];
- };
- float curve_in_x;
- float curve_out_x;
- float roll1;
- float roll2;
- } orig;
- /**
- * An extra offset to apply after mirroring.
- * Use with #POSE_MIRROR_RELATIVE.
- */
- float offset_mtx[4][4];
-} PoseInitData_Mirror;
-
typedef struct TransData {
/** Distance needed to affect element (for Proportionnal Editing). */
float dist;
@@ -639,17 +531,12 @@ typedef struct TransInfo {
bool is_launch_event_tweak;
struct {
- /** Orientation type when when we're not constrained.
- * nearly always global except for rotate which defaults to screen-space orientation. */
- short unset;
- /** Orientation to use when a key is pressed. */
- short user;
- /* Used when user is global. */
- short user_alt;
short index;
- short *types[2];
- /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */
+ short types[3];
+ /* this gets used when orientation.type[x] is V3D_ORIENT_CUSTOM */
struct TransformOrientation *custom;
+ /* this gets used when orientation.type[0] is V3D_ORIENT_CUSTOM_MATRIX */
+ float custom_matrix[3][3];
} orientation;
/** backup from view3d, to restore on end. */
short gizmo_flag;
@@ -674,23 +561,14 @@ typedef struct TransInfo {
/** Secondary axis, shear uses this. */
int orient_axis_ortho;
- /** Often this matrix has similar usage to #TransInfo.spacemtx however this
- * is used to define extra axes to operate on, not necessarily a space.
- *
- * For example, by default rotation operates on the view (`orient_matrix[2]`),
- * even when the current space isn't set to the view. */
- float orient_matrix[3][3];
- /** Don't overwrite when set by operator redo defines the orientation axis. */
- bool orient_matrix_is_set;
-
/** remove elements if operator is canceled. */
bool remove_on_cancel;
void *view;
/** Only valid (non null) during an operator called function. */
struct bContext *context;
- struct ScrArea *sa;
- struct ARegion *ar;
+ struct ScrArea *area;
+ struct ARegion *region;
struct Depsgraph *depsgraph;
struct Scene *scene;
struct ViewLayer *view_layer;
@@ -785,6 +663,10 @@ enum {
T_MODAL_CURSOR_SET = 1 << 26,
T_CLNOR_REBUILD = 1 << 27,
+
+ /* Special Aftertrans. */
+ T_AUTOMERGE = 1 << 28,
+ T_AUTOSPLIT = 1 << 29,
};
/** #TransInfo.modifiers */
@@ -875,6 +757,43 @@ enum {
MULTI_POINTS = 1 << 3,
};
+/** keymap modal items */
+/* NOTE: these values are saved in keymap files, do not change then but just add new ones. */
+enum {
+ TFM_MODAL_CANCEL = 1,
+ TFM_MODAL_CONFIRM = 2,
+ TFM_MODAL_TRANSLATE = 3,
+ TFM_MODAL_ROTATE = 4,
+ TFM_MODAL_RESIZE = 5,
+ TFM_MODAL_SNAP_INV_ON = 6,
+ TFM_MODAL_SNAP_INV_OFF = 7,
+ TFM_MODAL_SNAP_TOGGLE = 8,
+ TFM_MODAL_AXIS_X = 9,
+ TFM_MODAL_AXIS_Y = 10,
+ TFM_MODAL_AXIS_Z = 11,
+ TFM_MODAL_PLANE_X = 12,
+ TFM_MODAL_PLANE_Y = 13,
+ TFM_MODAL_PLANE_Z = 14,
+ TFM_MODAL_CONS_OFF = 15,
+ TFM_MODAL_ADD_SNAP = 16,
+ TFM_MODAL_REMOVE_SNAP = 17,
+
+ /* 18 and 19 used by numinput, defined in transform.h */
+
+ TFM_MODAL_PROPSIZE_UP = 20,
+ TFM_MODAL_PROPSIZE_DOWN = 21,
+ TFM_MODAL_AUTOIK_LEN_INC = 22,
+ TFM_MODAL_AUTOIK_LEN_DEC = 23,
+
+ TFM_MODAL_EDGESLIDE_UP = 24,
+ TFM_MODAL_EDGESLIDE_DOWN = 25,
+
+ /* for analog input, like trackpad */
+ TFM_MODAL_PROPSIZE = 26,
+ /* node editor insert offset (aka auto-offset) direction toggle */
+ TFM_MODAL_INSERTOFS_TOGGLE_DIR = 27,
+};
+
/* Hard min/max for proportional size. */
#define T_PROP_SIZE_MIN 1e-6f
#define T_PROP_SIZE_MAX 1e12f
@@ -900,8 +819,6 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2]);
void applyAspectRatio(TransInfo *t, float vec[2]);
void removeAspectRatio(TransInfo *t, float vec[2]);
-void drawPropCircle(const struct bContext *C, TransInfo *t);
-
struct wmKeyMap *transform_modal_keymap(struct wmKeyConfig *keyconf);
/*********************** transform_gizmo.c ********** */
@@ -915,32 +832,6 @@ void drawDial3d(const TransInfo *t);
/*********************** TransData Creation and General Handling *********** */
bool transdata_check_local_islands(TransInfo *t, short around);
-/*********************** Constraints *****************************/
-
-void drawConstraint(TransInfo *t);
-
-void getConstraintMatrix(TransInfo *t);
-void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
-void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
-void setLocalConstraint(TransInfo *t, int mode, const char text[]);
-void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
-
-void constraintNumInput(TransInfo *t, float vec[3]);
-
-bool isLockConstraint(TransInfo *t);
-int getConstraintSpaceDimension(TransInfo *t);
-int constraintModeToIndex(const TransInfo *t);
-char constraintModeToChar(const TransInfo *t);
-
-void startConstraint(TransInfo *t);
-void stopConstraint(TransInfo *t);
-
-void initSelectConstraint(TransInfo *t, float mtx[3][3]);
-void selectConstraint(TransInfo *t);
-void postSelectConstraint(TransInfo *t);
-
-void setNearestAxis(TransInfo *t);
-
/********************** Mouse Input ******************************/
typedef enum {
@@ -1021,7 +912,7 @@ void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot);
/*********************** Transform Orientations ******************************/
-void initTransformOrientation(struct bContext *C, TransInfo *t);
+void initTransformOrientation(struct bContext *C, TransInfo *t, short orientation);
/* Those two fill in mat and return non-zero on success */
bool createSpaceNormal(float mat[3][3], const float normal[3]);
@@ -1052,12 +943,6 @@ int getTransformOrientation(const struct bContext *C, float normal[3], float pla
void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-void freeEdgeSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-void projectEdgeSlideData(TransInfo *t, bool is_final);
-
-void freeVertSlideVerts(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data);
-void projectVertSlideData(TransInfo *t, bool is_final);
-
/* TODO. transform_query.c */
bool checkUseAxisMatrix(TransInfo *t);
@@ -1072,14 +957,14 @@ bool checkUseAxisMatrix(TransInfo *t);
(BLI_assert((t)->data_container_len == 1), (&(t)->data_container[0]))
#define FOREACH_TRANS_DATA_CONTAINER(t, th) \
- for (TransDataContainer *tc = t->data_container, \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = (t)->data_container, \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++)
#define FOREACH_TRANS_DATA_CONTAINER_INDEX(t, th, i) \
- for (TransDataContainer *tc = ((i = 0), t->data_container), \
- *tc_end = t->data_container + t->data_container_len; \
+ for (TransDataContainer *tc = ((i = 0), (t)->data_container), \
+ *tc_end = (t)->data_container + (t)->data_container_len; \
th != tc_end; \
th++, i++)
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index b43e1fec988..b07eb6edf5a 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -21,10 +21,10 @@
* \ingroup edtransform
*/
-#include <stdlib.h>
+#include <math.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <math.h>
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -32,20 +32,17 @@
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
-#include "BIF_glutil.h"
-
#include "GPU_immediate.h"
#include "GPU_matrix.h"
#include "GPU_state.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
-#include "BLI_string.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "ED_image.h"
#include "ED_view3d.h"
#include "BLT_translation.h"
@@ -55,6 +52,9 @@
#include "transform.h"
#include "transform_snap.h"
+/* Own include. */
+#include "transform_constraints.h"
+
static void drawObjectConstraint(TransInfo *t);
/* ************************** CONSTRAINTS ************************* */
@@ -171,7 +171,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3])
static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3])
{
if (t->spacetype == SPACE_VIEW3D) {
- // View3D *v3d = t->sa->spacedata.first;
+ // View3D *v3d = t->area->spacedata.first;
const float min_dist = 1.0f; /* v3d->clip_start; */
float dir[3];
float l;
@@ -713,7 +713,10 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte
break;
case V3D_ORIENT_VIEW:
BLI_snprintf(text, sizeof(text), ftext, TIP_("view"));
- setConstraint(t, t->spacemtx, mode, text);
+ float mtx[3][3];
+ copy_m3_m3(mtx, t->spacemtx);
+ negate_v3(mtx[2]);
+ setConstraint(t, mtx, mode, text);
break;
case V3D_ORIENT_CURSOR:
BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor"));
@@ -727,7 +730,9 @@ void setUserConstraint(TransInfo *t, short orientation, int mode, const char fte
BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix"));
setConstraint(t, t->spacemtx, mode, text);
break;
- case V3D_ORIENT_CUSTOM: {
+ case V3D_ORIENT_CUSTOM:
+ default: {
+ BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
char orientation_str[128];
BLI_snprintf(orientation_str,
sizeof(orientation_str),
@@ -846,8 +851,8 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
}
else if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
/* only scale y */
- rcti *mask = &t->ar->v2d.mask;
- rctf *datamask = &t->ar->v2d.cur;
+ rcti *mask = &t->region->v2d.mask;
+ rctf *datamask = &t->region->v2d.cur;
float xsize = BLI_rctf_size_x(datamask);
float ysize = BLI_rctf_size_y(datamask);
float xmask = BLI_rcti_size_x(mask);
@@ -984,17 +989,22 @@ void getConstraintMatrix(TransInfo *t)
/*------------------------- MMB Select -------------------------------*/
-void initSelectConstraint(TransInfo *t, float mtx[3][3])
+void initSelectConstraint(TransInfo *t, bool force_global)
{
- copy_m3_m3(t->con.mtx, mtx);
- t->con.mode |= CON_APPLY;
- t->con.mode |= CON_SELECT;
+ short orientation;
+ if (force_global) {
+ orientation = V3D_ORIENT_GLOBAL;
+ }
+ else {
+ if (t->orientation.index == 0) {
+ t->orientation.index = 1;
+ initTransformOrientation(t->context, t, t->orientation.types[t->orientation.index]);
+ }
+ orientation = t->orientation.types[t->orientation.index];
+ }
+ setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, "");
setNearestAxis(t);
- t->con.drawExtra = NULL;
- t->con.applyVec = applyAxisConstraintVec;
- t->con.applySize = applyAxisConstraintSize;
- t->con.applyRot = applyAxisConstraintRot;
}
void selectConstraint(TransInfo *t)
@@ -1055,7 +1065,7 @@ static void setNearestAxis3d(TransInfo *t)
* projecting them with ED_view3d_win_to_delta and then get the length of that vector.
*/
zfac = mul_project_m4_v3_zfac(t->persmat, t->center_global);
- zfac = len_v3(t->persinv[0]) * 2.0f / t->ar->winx * zfac * 30.0f;
+ zfac = len_v3(t->persinv[0]) * 2.0f / t->region->winx * zfac * 30.0f;
for (i = 0; i < 3; i++) {
float axis[3], axis_2d[2];
diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h
new file mode 100644
index 00000000000..c98234c83da
--- /dev/null
+++ b/source/blender/editors/transform/transform_constraints.h
@@ -0,0 +1,48 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#ifndef __TRANSFORM_CONSTRAINTS_H__
+#define __TRANSFORM_CONSTRAINTS_H__
+
+struct TransInfo;
+
+void constraintNumInput(TransInfo *t, float vec[3]);
+void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]);
+void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]);
+void setLocalConstraint(TransInfo *t, int mode, const char text[]);
+void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]);
+void drawConstraint(TransInfo *t);
+void drawPropCircle(const struct bContext *C, TransInfo *t);
+void startConstraint(TransInfo *t);
+void stopConstraint(TransInfo *t);
+void getConstraintMatrix(TransInfo *t);
+void initSelectConstraint(TransInfo *t, bool force_global);
+void selectConstraint(TransInfo *t);
+void postSelectConstraint(TransInfo *t);
+void setNearestAxis(TransInfo *t);
+int constraintModeToIndex(const TransInfo *t);
+char constraintModeToChar(const TransInfo *t);
+bool isLockConstraint(TransInfo *t);
+int getConstraintSpaceDimension(TransInfo *t);
+
+#endif
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index 869c23de74c..d6875f173e3 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -23,51 +23,53 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
-#include "DNA_space_types.h"
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_mask_types.h"
+#include "DNA_space_types.h"
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
+#include "BLI_kdtree.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_kdtree.h"
#include "BKE_animsys.h"
#include "BKE_armature.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_gpencil.h"
-#include "BKE_layer.h"
#include "BKE_key.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_mask.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
-#include "BKE_editmesh.h"
#include "BKE_tracking.h"
-#include "BKE_mask.h"
#include "BIK_api.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
-#include "ED_particle.h"
+#include "ED_clip.h"
#include "ED_image.h"
-#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
-#include "ED_object.h"
+#include "ED_keyframing.h"
#include "ED_markers.h"
+#include "ED_mask.h"
#include "ED_mesh.h"
#include "ED_node.h"
-#include "ED_clip.h"
-#include "ED_mask.h"
+#include "ED_object.h"
+#include "ED_particle.h"
+
+#include "UI_view2d.h"
#include "WM_api.h" /* for WM_event_add_notifier to deal with stabilization nodes */
#include "WM_types.h"
@@ -79,6 +81,12 @@
#include "transform.h"
#include "transform_convert.h"
+#include "transform_mode.h"
+
+bool transform_mode_use_local_origins(const TransInfo *t)
+{
+ return ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL);
+}
/**
* Transforming around ourselves is no use, fallback to individual origins,
@@ -86,14 +94,40 @@
*/
void transform_around_single_fallback(TransInfo *t)
{
- if ((t->data_len_all == 1) &&
- (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
- (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) {
- t->around = V3D_AROUND_LOCAL_ORIGINS;
+ if ((ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) &&
+ transform_mode_use_local_origins(t)) {
+
+ bool is_data_single = false;
+ if (t->data_len_all == 1) {
+ is_data_single = true;
+ }
+ else if (t->data_len_all == 3) {
+ if (t->obedit_type == OB_CURVE) {
+ /* Special case check for curve, if we have a single curve bezier triple selected
+ * treat */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ if (!tc->data_len) {
+ continue;
+ }
+ if (tc->data_len == 3) {
+ const TransData *td = tc->data;
+ if ((td[0].loc == td[1].loc) && (td[1].loc == td[2].loc)) {
+ is_data_single = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (is_data_single) {
+ t->around = V3D_AROUND_LOCAL_ORIGINS;
+ }
}
}
-/* ************************** Functions *************************** */
+/* -------------------------------------------------------------------- */
+/** \name Proportional Editing
+ * \{ */
static int trans_data_compare_dist(const void *a, const void *b)
{
@@ -203,8 +237,8 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
const bool use_island = transdata_check_local_islands(t, t->around);
if (t->flag & T_PROP_PROJECTED) {
- if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
- RegionView3D *rv3d = t->ar->regiondata;
+ if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) {
+ RegionView3D *rv3d = t->region->regiondata;
normalize_v3_v3(_proj_vec, rv3d->viewinv[2]);
proj_vec = _proj_vec;
}
@@ -330,7 +364,11 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
MEM_freeN(td_table);
}
-/* ********************* pose mode ************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Mode
+ * \{ */
static short apply_targetless_ik(Object *ob)
{
@@ -368,23 +406,25 @@ static short apply_targetless_ik(Object *ob)
}
for (; segcount; segcount--) {
Bone *bone;
- float rmat[4][4] /*, tmat[4][4], imat[4][4]*/;
+ float mat[4][4];
/* pose_mat(b) = pose_mat(b-1) * offs_bone * channel * constraint * IK */
- /* we put in channel the entire result of rmat = (channel * constraint * IK) */
- /* pose_mat(b) = pose_mat(b-1) * offs_bone * rmat */
- /* rmat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
+ /* we put in channel the entire result of mat = (channel * constraint * IK) */
+ /* pose_mat(b) = pose_mat(b-1) * offs_bone * mat */
+ /* mat = pose_mat(b) * inv(pose_mat(b-1) * offs_bone ) */
parchan = chanlist[segcount - 1];
bone = parchan->bone;
bone->flag |= BONE_TRANSFORM; /* ensures it gets an auto key inserted */
- BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, rmat);
-
+ BKE_armature_mat_pose_to_bone(parchan, parchan->pose_mat, mat);
/* apply and decompose, doesn't work for constraints or non-uniform scale well */
{
float rmat3[3][3], qrmat[3][3], imat3[3][3], smat[3][3];
- copy_m3_m4(rmat3, rmat);
+
+ copy_m3_m4(rmat3, mat);
+ /* Make sure that our rotation matrix only contains rotation and not scale. */
+ normalize_m3(rmat3);
/* rotation */
/* [#22409] is partially caused by this, as slight numeric error introduced during
@@ -404,7 +444,7 @@ static short apply_targetless_ik(Object *ob)
/* causes problems with some constraints (e.g. childof), so disable this */
/* as it is IK shouldn't affect location directly */
- /* copy_v3_v3(parchan->loc, rmat[3]); */
+ /* copy_v3_v3(parchan->loc, mat[3]); */
}
}
@@ -436,12 +476,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb)
}
}
-/* sets transform flags in the bones
- * returns total number of bones with BONE_TRANSFORM */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2])
+/* Sets transform flags in the bones.
+ * Returns total number of bones with `BONE_TRANSFORM`. */
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2])
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
@@ -450,15 +490,20 @@ int count_set_pose_transflags(Object *ob,
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
bone = pchan->bone;
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
if (PBONE_VISIBLE(arm, bone)) {
if ((bone->flag & BONE_SELECTED)) {
bone->flag |= BONE_TRANSFORM;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
bone->flag &= ~BONE_HINGE_CHILD_TRANSFORM;
bone->flag &= ~BONE_TRANSFORM_CHILD;
}
+ else {
+ bone->flag &= ~BONE_TRANSFORM;
+ }
}
/* make sure no bone can be transformed when a parent is transformed */
@@ -503,7 +548,11 @@ int count_set_pose_transflags(Object *ob,
return total;
}
-/* -------- Auto-IK ---------- */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Mode (Auto-IK)
+ * \{ */
/* adjust pose-channel's auto-ik chainlen */
static bool pchan_autoik_adjust(bPoseChannel *pchan, short chainlen)
@@ -628,7 +677,11 @@ static void pose_grab_with_ik_clear(Main *bmain, Object *ob)
}
}
-/* ********************* curve/surface ********* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Curve Surface
+ * \{ */
void calc_distanceCurveVerts(TransData *head, TransData *tail)
{
@@ -698,7 +751,11 @@ TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTr
return hdata;
}
-/* ********************* UV ****************** */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name UV Coordinates
+ * \{ */
bool clipUVTransform(TransInfo *t, float vec[2], const bool resize)
{
@@ -784,7 +841,36 @@ void clipUVData(TransInfo *t)
}
}
-/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Animation Editors (General)
+ * \{ */
+
+/**
+ * Used for `TFM_TIME_EXTEND`.
+ */
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe)
+{
+ char r_dir;
+ float center[2];
+ if (t->flag & T_MODAL) {
+ UI_view2d_region_to_view(
+ (View2D *)t->view, t->mouse.imval[0], t->mouse.imval[1], &center[0], &center[1]);
+ r_dir = (center[0] > cframe) ? 'R' : 'L';
+ {
+ /* XXX: This saves the direction in the "mirror" property to be used for redo! */
+ if (r_dir == 'R') {
+ t->flag |= T_NO_MIRROR;
+ }
+ }
+ }
+ else {
+ r_dir = (t->flag & T_NO_MIRROR) ? 'R' : 'L';
+ }
+
+ return r_dir;
+}
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
bool FrameOnMouseSide(char side, float frame, float cframe)
@@ -803,26 +889,11 @@ bool FrameOnMouseSide(char side, float frame, float cframe)
}
}
-/* ********************* ACTION EDITOR ****************** */
+/** \} */
-static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
-{
- const bGPDframe *frame_a = a;
- const bGPDframe *frame_b = b;
-
- if (frame_a->framenum < frame_b->framenum) {
- return -1;
- }
- if (frame_a->framenum > frame_b->framenum) {
- return 1;
- }
- *((bool *)thunk) = true;
- /* selected last */
- if ((frame_a->flag & GP_FRAME_SELECT) && ((frame_b->flag & GP_FRAME_SELECT) == 0)) {
- return 1;
- }
- return 0;
-}
+/* -------------------------------------------------------------------- */
+/** \name Animation Editor
+ * \{ */
static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
{
@@ -856,13 +927,13 @@ static void posttrans_gpd_clean(bGPdata *gpd)
bGPDframe *gpf, *gpfn;
bool is_double = false;
- BLI_listbase_sort_r(&gpl->frames, gpf_cmp_frame, &is_double);
+ BKE_gpencil_layer_frames_sort(gpl, &is_double);
if (is_double) {
for (gpf = gpl->frames.first; gpf; gpf = gpfn) {
gpfn = gpf->next;
if (gpfn && gpf->framenum == gpfn->framenum) {
- BKE_gpencil_layer_delframe(gpl, gpf);
+ BKE_gpencil_layer_frame_delete(gpl, gpf);
}
}
}
@@ -875,6 +946,8 @@ static void posttrans_gpd_clean(bGPdata *gpd)
}
/* set cache flag to dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, gpd);
}
static void posttrans_mask_clean(Mask *mask)
@@ -904,6 +977,8 @@ static void posttrans_mask_clean(Mask *mask)
}
#endif
}
+
+ WM_main_add_notifier(NC_MASK | NA_EDITED, mask);
}
/* Time + Average value */
@@ -985,7 +1060,7 @@ static void posttrans_fcurve_clean(FCurve *fcu,
}
else {
/* Compute the average values for each retained keyframe */
- for (tRetainedKeyframe *rk = retained_keys.first; rk; rk = rk->next) {
+ LISTBASE_FOREACH (tRetainedKeyframe *, rk, &retained_keys) {
rk->val = rk->val / (float)rk->tot_count;
}
}
@@ -1078,15 +1153,19 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
ANIM_animdata_freelist(&anim_data);
}
-/* ********************* GRAPH EDITOR ************************* */
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Graph Editor
+ * \{ */
/* struct for use in re-sorting BezTriples during Graph Editor transform */
typedef struct BeztMap {
BezTriple *bezt;
- unsigned int oldIndex; /* index of bezt in fcu->bezt array before sorting */
- unsigned int newIndex; /* index of bezt in fcu->bezt array after sorting */
- short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
- char pipo, cipo; /* interpolation of current and next segments */
+ uint oldIndex; /* index of bezt in fcu->bezt array before sorting */
+ uint newIndex; /* index of bezt in fcu->bezt array after sorting */
+ short swapHs; /* swap order of handles (-1=clear; 0=not checked, 1=swap) */
+ char pipo, cipo; /* interpolation of current and next segments */
} BeztMap;
/* This function converts an FCurve's BezTriple array to a BeztMap array
@@ -1249,6 +1328,12 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
MEM_freeN(adjusted);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Utilities
+ * \{ */
+
/* This function is called by recalcData during the Transform loop to recalculate
* the handles of curves and sort the keyframes so that the curves draw correctly.
* It is only called if some keyframes have moved out of order.
@@ -1258,7 +1343,7 @@ static void beztmap_to_data(TransInfo *t, FCurve *fcu, BeztMap *bezms, int totve
*/
void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimListElem *ale;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -1287,8 +1372,6 @@ void remake_graph_transdata(TransInfo *t, ListBase *anim_data)
}
}
-/* *********************** Transform data ******************* */
-
/* Little helper function for ObjectToTransData used to give certain
* constraints (ChildOf, FollowPath, and others that may be added)
* inverse corrections for transform, so that they aren't in CrazySpace.
@@ -1374,6 +1457,12 @@ bool constraints_list_needinv(TransInfo *t, ListBase *list)
return false;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (Auto-Keyframing)
+ * \{ */
+
/**
* Auto-keyframing feature - for objects
*
@@ -1395,10 +1484,10 @@ void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Objec
KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
ListBase dsources = {NULL, NULL};
float cfra = (float)CFRA; // xxx this will do for now
- short flag = 0;
+ eInsertKeyFlags flag = 0;
- /* get flags used for inserting keyframes */
- flag = ANIM_get_keyframing_flags(scene, 1);
+ /* Get flags used for inserting keyframes. */
+ flag = ANIM_get_keyframing_flags(scene, true);
/* add datasource override for the object */
ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
@@ -1417,7 +1506,6 @@ void autokeyframe_object(bContext *C, Scene *scene, ViewLayer *view_layer, Objec
if (adt && adt->action) {
ListBase nla_cache = {NULL, NULL};
for (fcu = adt->action->curves.first; fcu; fcu = fcu->next) {
- fcu->flag &= ~FCURVE_SELECTED;
insert_keyframe(bmain,
reports,
id,
@@ -1532,147 +1620,156 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
FCurve *fcu;
// TODO: this should probably be done per channel instead...
- if (autokeyframe_cfra_can_key(scene, id)) {
- ReportList *reports = CTX_wm_reports(C);
- ToolSettings *ts = scene->toolsettings;
- KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
- ListBase nla_cache = {NULL, NULL};
- float cfra = (float)CFRA;
- short flag = 0;
-
- /* flag is initialized from UserPref keyframing settings
- * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
- * visual keyframes even if flag not set, as it's not that useful otherwise
- * (for quick animation recording)
- */
- flag = ANIM_get_keyframing_flags(scene, 1);
+ if (!autokeyframe_cfra_can_key(scene, id)) {
+ /* tag channels that should have unkeyed data */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->bone->flag & BONE_TRANSFORM) {
+ /* tag this channel */
+ pchan->bone->flag |= BONE_UNKEYED;
+ }
+ }
+ return;
+ }
+
+ ReportList *reports = CTX_wm_reports(C);
+ ToolSettings *ts = scene->toolsettings;
+ KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
+ ListBase nla_cache = {NULL, NULL};
+ float cfra = (float)CFRA;
+ eInsertKeyFlags flag = 0;
- if (targetless_ik) {
- flag |= INSERTKEY_MATRIX;
+ /* flag is initialized from UserPref keyframing settings
+ * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
+ * visual keyframes even if flag not set, as it's not that useful otherwise
+ * (for quick animation recording)
+ */
+ flag = ANIM_get_keyframing_flags(scene, true);
+
+ if (targetless_ik) {
+ flag |= INSERTKEY_MATRIX;
+ }
+
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if ((pchan->bone->flag & BONE_TRANSFORM) == 0 &&
+ !((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
+ continue;
}
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if ((pchan->bone->flag & BONE_TRANSFORM) ||
- ((pose->flag & POSE_MIRROR_EDIT) && (pchan->bone->flag & BONE_TRANSFORM_MIRROR))) {
- ListBase dsources = {NULL, NULL};
-
- /* clear any 'unkeyed' flag it may have */
- pchan->bone->flag &= ~BONE_UNKEYED;
-
- /* add datasource override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
-
- /* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
- /* run the active Keying Set on the current datasource */
- ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- /* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
- if (act) {
- for (fcu = act->curves.first; fcu; fcu = fcu->next) {
- /* only insert keyframes for this F-Curve if it affects the current bone */
- if (strstr(fcu->rna_path, "bones")) {
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
-
- /* only if bone name matches too...
- * NOTE: this will do constraints too, but those are ok to do here too?
- */
- if (pchanName && STREQ(pchanName, pchan->name)) {
- insert_keyframe(bmain,
- reports,
- id,
- act,
- ((fcu->grp) ? (fcu->grp->name) : (NULL)),
- fcu->rna_path,
- fcu->array_index,
- cfra,
- ts->keyframe_type,
- &nla_cache,
- flag);
- }
-
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- }
- }
- }
- }
- /* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
- bool do_loc = false, do_rot = false, do_scale = false;
+ ListBase dsources = {NULL, NULL};
- /* Filter the conditions when this happens
- * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
- if (tmode == TFM_TRANSLATION) {
- if (targetless_ik) {
- do_rot = true;
- }
- else {
- do_loc = true;
- }
- }
- else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* clear any 'unkeyed' flag it may have */
+ pchan->bone->flag &= ~BONE_UNKEYED;
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_rot = true;
- }
- }
- else if (tmode == TFM_RESIZE) {
- if (ELEM(scene->toolsettings->transform_pivot_point,
- V3D_AROUND_CURSOR,
- V3D_AROUND_ACTIVE)) {
- do_loc = true;
- }
+ /* add datasource override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
- if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
- do_scale = true;
- }
+ /* only insert into active keyingset? */
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
+ /* run the active Keying Set on the current datasource */
+ ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ /* only insert into available channels? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
+ if (act) {
+ for (fcu = act->curves.first; fcu; fcu = fcu->next) {
+ /* only insert keyframes for this F-Curve if it affects the current bone */
+ if (strstr(fcu->rna_path, "bones") == NULL) {
+ continue;
}
+ char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- if (do_loc) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
- }
- if (do_rot) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ /* only if bone name matches too...
+ * NOTE: this will do constraints too, but those are ok to do here too?
+ */
+ if (pchanName && STREQ(pchanName, pchan->name)) {
+ insert_keyframe(bmain,
+ reports,
+ id,
+ act,
+ ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path,
+ fcu->array_index,
+ cfra,
+ ts->keyframe_type,
+ &nla_cache,
+ flag);
}
- if (do_scale) {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+
+ if (pchanName) {
+ MEM_freeN(pchanName);
}
}
- /* insert keyframe in all (transform) channels */
+ }
+ }
+ /* only insert keyframe if needed? */
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ bool do_loc = false, do_rot = false, do_scale = false;
+
+ /* Filter the conditions when this happens
+ * (assume that 'curarea->spacetype == SPACE_VIEW3D'). */
+ if (tmode == TFM_TRANSLATION) {
+ if (targetless_ik) {
+ do_rot = true;
+ }
else {
- KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ do_loc = true;
+ }
+ }
+ else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
}
- /* free temp info */
- BLI_freelistN(&dsources);
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_rot = true;
+ }
}
- }
+ else if (tmode == TFM_RESIZE) {
+ if (ELEM(scene->toolsettings->transform_pivot_point,
+ V3D_AROUND_CURSOR,
+ V3D_AROUND_ACTIVE)) {
+ do_loc = true;
+ }
- BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
- }
- else {
- /* tag channels that should have unkeyed data */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->bone->flag & BONE_TRANSFORM) {
- /* tag this channel */
- pchan->bone->flag |= BONE_UNKEYED;
+ if ((scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) == 0) {
+ do_scale = true;
+ }
+ }
+
+ if (do_loc) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_rot) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+ if (do_scale) {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_SCALING_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
}
}
+ /* insert keyframe in all (transform) channels */
+ else {
+ KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOC_ROT_SCALE_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+ }
+
+ /* free temp info */
+ BLI_freelistN(&dsources);
}
+
+ BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform (After-Transform Update)
+ * \{ */
+
/* Return if we need to update motion paths, only if they already exist,
* and we will insert a keyframe at the end of transform. */
bool motionpath_need_update_pose(Scene *scene, Object *ob)
@@ -1686,13 +1783,12 @@ bool motionpath_need_update_pose(Scene *scene, Object *ob)
static void special_aftertrans_update__movieclip(bContext *C, TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
ListBase *plane_tracks_base = BKE_tracking_get_active_plane_tracks(&clip->tracking);
const int framenr = ED_space_clip_get_clip_frame_number(sc);
/* Update coordinates of modified plane tracks. */
- for (MovieTrackingPlaneTrack *plane_track = plane_tracks_base->first; plane_track;
- plane_track = plane_track->next) {
+ LISTBASE_FOREACH (MovieTrackingPlaneTrack *, plane_track, plane_tracks_base) {
bool do_update = false;
if (plane_track->flag & PLANE_TRACK_HIDDEN) {
continue;
@@ -1728,11 +1824,11 @@ static void special_aftertrans_update__mask(bContext *C, TransInfo *t)
Mask *mask = NULL;
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
mask = ED_space_clip_get_mask(sc);
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
mask = ED_space_image_get_mask(sima);
}
else {
@@ -1763,7 +1859,7 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
if (canceled && t->remove_on_cancel) {
/* remove selected nodes on cancel */
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
bNodeTree *ntree = snode->edittree;
if (ntree) {
bNode *node, *node_next;
@@ -1779,8 +1875,8 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t)
static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
{
- /* so automerge supports mirror */
- if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
+ bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
+ if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1806,14 +1902,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
hflag = BM_ELEM_SELECT;
}
- if (t->scene->toolsettings->automerge & AUTO_MERGE) {
- if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) {
- EDBM_automerge_and_split(
- tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
- }
- else {
- EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
- }
+ if (t->flag & T_AUTOSPLIT) {
+ EDBM_automerge_and_split(
+ tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
+ }
+ else {
+ EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
}
/* Special case, this is needed or faces won't re-select.
@@ -1870,13 +1964,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
else {
if (t->mode == TFM_EDGE_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
projectEdgeSlideData(t, false);
}
else if (t->mode == TFM_VERT_SLIDE) {
- EdgeSlideParams *slp = t->custom.mode.data;
- slp->perc = 0.0;
projectVertSlideData(t, false);
}
}
@@ -1890,7 +1980,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* freeSeqData in transform_conversions.c does this
* keep here so the else at the end wont run... */
- SpaceSeq *sseq = (SpaceSeq *)t->sa->spacedata.first;
+ SpaceSeq *sseq = (SpaceSeq *)t->area->spacedata.first;
/* Marker transform, not especially nice but we may want to move markers
* at the same time as strips in the Video Sequencer. */
@@ -1916,16 +2006,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_NODE) {
- SpaceNode *snode = (SpaceNode *)t->sa->spacedata.first;
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
special_aftertrans_update__node(C, t);
if (canceled == 0) {
ED_node_post_apply_transform(C, snode->edittree);
- ED_node_link_insert(bmain, t->sa);
+ ED_node_link_insert(bmain, t->area);
}
/* clear link line */
- ED_node_link_intersect_test(t->sa, 0);
+ ED_node_link_intersect_test(t->area, 0);
}
else if (t->spacetype == SPACE_CLIP) {
if (t->options & CTX_MOVIECLIP) {
@@ -1936,7 +2026,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
}
else if (t->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac;
/* initialize relevant anim-context 'context' data */
@@ -2015,15 +2105,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* but we made duplicates, so get rid of these
*/
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- bGPdata *gpd;
+ ListBase anim_data = {NULL, NULL};
+ const int filter = ANIMFILTER_DATA_VISIBLE;
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (gpd = bmain->gpencils.first; gpd; gpd = gpd->id.next) {
- if (ID_REAL_USERS(gpd)) {
- posttrans_gpd_clean(gpd);
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ if (ale->datatype == ALE_GPFRAME) {
+ ale->id->tag |= LIB_TAG_DOIT;
+ }
+ }
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ if (ale->datatype == ALE_GPFRAME) {
+ if (ale->id->tag & LIB_TAG_DOIT) {
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_gpd_clean((bGPdata *)ale->id);
+ }
}
}
+ ANIM_animdata_freelist(&anim_data);
}
}
else if (ac.datatype == ANIMCONT_MASK) {
@@ -2037,15 +2136,24 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* User canceled the transform, but we made duplicates, so get rid of these.
*/
if ((saction->flag & SACTION_NOTRANSKEYCULL) == 0 && ((canceled == 0) || (duplicate))) {
- Mask *mask;
+ ListBase anim_data = {NULL, NULL};
+ const int filter = ANIMFILTER_DATA_VISIBLE;
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
- // XXX: BAD! this get gpencil datablocks directly from main db...
- // but that's how this currently works :/
- for (mask = bmain->masks.first; mask; mask = mask->id.next) {
- if (ID_REAL_USERS(mask)) {
- posttrans_mask_clean(mask);
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ if (ale->datatype == ALE_MASKLAY) {
+ ale->id->tag |= LIB_TAG_DOIT;
}
}
+ LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
+ if (ale->datatype == ALE_MASKLAY) {
+ if (ale->id->tag & LIB_TAG_DOIT) {
+ ale->id->tag &= ~LIB_TAG_DOIT;
+ posttrans_mask_clean((Mask *)ale->id);
+ }
+ }
+ }
+ ANIM_animdata_freelist(&anim_data);
}
}
@@ -2074,7 +2182,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
/* make sure all F-Curves are set correctly */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+ if (!ELEM(ac.datatype, ANIMCONT_GPENCIL)) {
ANIM_editkeyframes_refresh(&ac);
}
@@ -2082,7 +2190,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
saction->flag &= ~SACTION_MOVING;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bAnimContext ac;
const bool use_handle = (sipo->flag & SIPO_NOHANDLES) == 0;
@@ -2171,9 +2279,8 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
else if (t->flag & T_EDIT) {
if (t->obedit_type == OB_MESH) {
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
/* table needs to be created for each edit command, since vertices can move etc */
- ED_mesh_mirror_spatial_table(tc->obedit, em, NULL, NULL, 'e');
+ ED_mesh_mirror_spatial_table_end(tc->obedit);
/* TODO(campbell): xform: We need support for many mirror objects at once! */
break;
}
@@ -2208,7 +2315,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
/* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */
if (!canceled && (t->mode != TFM_DUMMY)) {
- count_set_pose_transflags(ob, t->mode, t->around, NULL);
+ transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL);
}
/* if target-less IK grabbing, we calculate the pchan transforms and clear flag */
@@ -2360,6 +2467,10 @@ int special_transform_moving(TransInfo *t)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name Transform Data Create
+ * \{ */
+
static int countAndCleanTransDataContainer(TransInfo *t)
{
BLI_assert(ELEM(t->data_len_all, 0, -1));
@@ -2518,7 +2629,7 @@ void createTransData(bContext *C, TransInfo *t)
t->obedit_type = -1;
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point trasnform */
- createTransSeqData(C, t);
+ createTransSeqData(t);
countAndCleanTransDataContainer(t);
}
else if (t->spacetype == SPACE_GRAPH) {
@@ -2659,7 +2770,7 @@ void createTransData(bContext *C, TransInfo *t)
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
has_transform_context = false;
- Object *ob_armature = modifiers_isDeformedByArmature(ob);
+ Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob);
if (ob_armature && ob_armature->mode & OB_MODE_POSE) {
Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature);
if (base_arm) {
@@ -2698,9 +2809,11 @@ void createTransData(bContext *C, TransInfo *t)
has_transform_context = false;
}
}
- else if ((ob) &&
- (ELEM(
- ob->mode, OB_MODE_PAINT_GPENCIL, OB_MODE_SCULPT_GPENCIL, OB_MODE_WEIGHT_GPENCIL))) {
+ else if ((ob) && (ELEM(ob->mode,
+ OB_MODE_PAINT_GPENCIL,
+ OB_MODE_SCULPT_GPENCIL,
+ OB_MODE_WEIGHT_GPENCIL,
+ OB_MODE_VERTEX_GPENCIL))) {
/* In grease pencil all transformations must be canceled if not Object or Edit. */
has_transform_context = false;
}
@@ -2726,16 +2839,16 @@ void createTransData(bContext *C, TransInfo *t)
}
/* Check if we're transforming the camera from the camera */
- if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
View3D *v3d = t->view;
- RegionView3D *rv3d = t->ar->regiondata;
+ RegionView3D *rv3d = t->region->regiondata;
if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) {
/* we could have a flag to easily check an object is being transformed */
if (v3d->camera->id.tag & LIB_TAG_DOIT) {
t->flag |= T_CAMERA;
}
}
- else if (v3d->ob_centre && v3d->ob_centre->id.tag & LIB_TAG_DOIT) {
+ else if (v3d->ob_center && v3d->ob_center->id.tag & LIB_TAG_DOIT) {
t->flag |= T_CAMERA;
}
}
@@ -2752,3 +2865,5 @@ void createTransData(bContext *C, TransInfo *t)
BLI_assert((!(t->flag & T_EDIT)) == (!(t->obedit_type != -1)));
}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 53ff9952d05..e5d758135e2 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -19,6 +19,7 @@
/** \file
* \ingroup edtransform
+ * \brief conversion and adaptation of different datablocks to a common struct.
*/
#ifndef __TRANSFORM_CONVERT_H__
@@ -36,10 +37,10 @@ struct bKinematicConstraint;
struct bPoseChannel;
/* transform_convert.c */
-int count_set_pose_transflags(Object *ob,
- const int mode,
- const short around,
- bool has_translate_rotate[2]);
+int transform_convert_pose_transflags_update(Object *ob,
+ const int mode,
+ const short around,
+ bool has_translate_rotate[2]);
void transform_autoik_update(TransInfo *t, short mode);
void autokeyframe_object(struct bContext *C,
struct Scene *scene,
@@ -60,81 +61,111 @@ void clipUVData(TransInfo *t);
/* transform_convert_action.c */
void flushTransIntFrameActionData(TransInfo *t);
+
/* transform_convert_armature.c */
+void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob);
void restoreMirrorPoseBones(TransDataContainer *tc);
void restoreBones(TransDataContainer *tc);
+
/* transform_convert_graph.c */
void flushTransGraphData(TransInfo *t);
+
/* transform_convert_mask.c */
void flushTransMasking(TransInfo *t);
+
/* transform_convert_mesh.c */
void flushTransUVs(TransInfo *t);
void trans_mesh_customdata_correction_init(TransInfo *t);
void trans_mesh_customdata_correction_apply(struct TransDataContainer *tc, bool is_final);
+
/* transform_convert_node.c */
void flushTransNodes(TransInfo *t);
+
/* transform_convert_object.c */
void trans_obdata_in_obmode_update_all(struct TransInfo *t);
void trans_obchild_in_obmode_update_all(struct TransInfo *t);
+
/* transform_convert_paintcurve.c */
void flushTransPaintCurve(TransInfo *t);
+
/* transform_convert_particle.c */
void flushTransParticles(TransInfo *t);
+
/* transform_convert_sequencer.c */
void flushTransSeq(TransInfo *t);
+
/* transform_convert_tracking.c */
void flushTransTracking(TransInfo *t);
/********************* intern **********************/
/* transform_convert.c */
+bool transform_mode_use_local_origins(const TransInfo *t);
void transform_around_single_fallback(TransInfo *t);
bool constraints_list_needinv(TransInfo *t, ListBase *list);
void calc_distanceCurveVerts(TransData *head, TransData *tail);
struct TransDataCurveHandleFlags *initTransDataCurveHandles(TransData *td, struct BezTriple *bezt);
+char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
bool FrameOnMouseSide(char side, float frame, float cframe);
/* transform_convert_action.c */
void createTransActionData(bContext *C, TransInfo *t);
+
/* transform_convert_armature.c */
struct bKinematicConstraint *has_targetless_ik(struct bPoseChannel *pchan);
void createTransPose(TransInfo *t);
void createTransArmatureVerts(TransInfo *t);
+
/* transform_convert_cursor.c */
void createTransCursor_image(TransInfo *t);
void createTransCursor_view3d(TransInfo *t);
+
/* transform_convert_curve.c */
void createTransCurveVerts(TransInfo *t);
+
/* transform_convert_graph.c */
void createTransGraphEditData(bContext *C, TransInfo *t);
+
/* transform_convert_gpencil.c */
void createTransGPencil(bContext *C, TransInfo *t);
+
/* transform_convert_lattice.c */
void createTransLatticeVerts(TransInfo *t);
+
/* transform_convert_mask.c */
void createTransMaskingData(bContext *C, TransInfo *t);
+
/* transform_convert_mball.c */
void createTransMBallVerts(TransInfo *t);
+
/* transform_convert_mesh.c */
void createTransEditVerts(TransInfo *t);
void createTransEdge(TransInfo *t);
void createTransUVs(bContext *C, TransInfo *t);
+
/* transform_convert_nla.c */
void createTransNlaData(bContext *C, TransInfo *t);
+
/* transform_convert_node.c */
void createTransNodeData(bContext *UNUSED(C), TransInfo *t);
+
/* transform_convert_object.c */
void clear_trans_object_base_flags(TransInfo *t);
void createTransObject(bContext *C, TransInfo *t);
void createTransTexspace(TransInfo *t);
+
/* transform_convert_paintcurve.c */
void createTransPaintCurveVerts(bContext *C, TransInfo *t);
+
/* transform_convert_particle.c */
void createTransParticleVerts(bContext *C, TransInfo *t);
+
/* transform_convert_sculpt.c */
void createTransSculpt(TransInfo *t);
+
/* transform_convert_sequence.c */
-void createTransSeqData(bContext *C, TransInfo *t);
+void createTransSeqData(TransInfo *t);
+
/* transform_convert_tracking.c */
void createTransTrackingData(bContext *C, TransInfo *t);
void cancelTransTracking(TransInfo *t);
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 0b1d2757435..21ef1539911 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -30,14 +30,12 @@
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_nla.h"
#include "BKE_report.h"
#include "ED_anim_api.h"
-#include "UI_view2d.h"
-
#include "transform.h"
#include "transform_convert.h"
@@ -299,8 +297,8 @@ void createTransActionData(bContext *C, TransInfo *t)
TransData2D *td2d = NULL;
tGPFtransdata *tfd = NULL;
- rcti *mask = &t->ar->v2d.mask;
- rctf *datamask = &t->ar->v2d.cur;
+ rcti *mask = &t->region->v2d.mask;
+ rctf *datamask = &t->region->v2d.cur;
float xsize = BLI_rctf_size_x(datamask);
float ysize = BLI_rctf_size_y(datamask);
@@ -315,7 +313,7 @@ void createTransActionData(bContext *C, TransInfo *t)
int count = 0;
float cfra;
- float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->ar->v2d.cur);
+ float ypos = 1.0f / ((ysize / xsize) * (xmask / ymask)) * BLI_rctf_cent_y(&t->region->v2d.cur);
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@@ -333,11 +331,7 @@ void createTransActionData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 0edf55ece7e..35bb7e3f0d8 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_action.h"
@@ -45,23 +46,47 @@
#include "transform.h"
#include "transform_convert.h"
-bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+typedef struct BoneInitData {
+ struct EditBone *bone;
+ float tail[3];
+ float rad_head;
+ float rad_tail;
+ float roll;
+ float head[3];
+ float dist;
+ float xwidth;
+ float zwidth;
+} BoneInitData;
+
+static bConstraint *add_temporary_ik_constraint(bPoseChannel *pchan,
+ bKinematicConstraint *targetless_con)
{
- bConstraint *con = pchan->constraints.first;
+ bConstraint *con = BKE_constraint_add_for_pose(
+ NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
- for (; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->enforce != 0.0f)) {
- bKinematicConstraint *data = con->data;
+ /* for draw, but also for detecting while pose solving */
+ pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
- if (data->tar == NULL) {
- return data;
- }
- if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
- return data;
- }
- }
+ bKinematicConstraint *temp_con_data = con->data;
+
+ if (targetless_con) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *temp_con_data = *targetless_con;
}
- return NULL;
+ else {
+ temp_con_data->flag = CONSTRAINT_IK_TIP;
+ }
+
+ temp_con_data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
+
+ return con;
+}
+
+static void update_deg_with_temporary_ik(Main *bmain, Object *ob)
+{
+ BIK_clear_data(ob->pose);
+ /* TODO(sergey): Consider doing partial update only. */
+ DEG_relations_tag_update(bmain);
}
static void add_pose_transdata(
@@ -206,8 +231,16 @@ static void add_pose_transdata(
}
td->loc = data->grabtarget;
copy_v3_v3(td->iloc, td->loc);
+
data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * targetless bone during transform. (Targetless IK constraints are treated as if they are
+ * disabled unless they are transformed). */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
+
/* only object matrix correction */
copy_m3_m3(td->mtx, omat);
pseudoinverse_m3_m3(td->smtx, td->mtx, PSEUDOINVERSE_EPSILON);
@@ -218,6 +251,30 @@ static void add_pose_transdata(
td->con = pchan->constraints.first;
}
+/* -------------------------------------------------------------------- */
+/** \name Pose Auto-IK
+ * \{ */
+
+bKinematicConstraint *has_targetless_ik(bPoseChannel *pchan)
+{
+ bConstraint *con = pchan->constraints.first;
+
+ for (; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0 &&
+ (con->enforce != 0.0f)) {
+ bKinematicConstraint *data = con->data;
+
+ if (data->tar == NULL) {
+ return data;
+ }
+ if (data->tar->type == OB_ARMATURE && data->subtarget[0] == 0) {
+ return data;
+ }
+ }
+ }
+ return NULL;
+}
+
/* adds the IK to pchan - returns if added */
static short pose_grab_with_ik_add(bPoseChannel *pchan)
{
@@ -232,7 +289,7 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* Rule: not if there's already an IK on this channel */
for (con = pchan->constraints.first; con; con = con->next) {
- if (con->type == CONSTRAINT_TYPE_KINEMATIC) {
+ if (con->type == CONSTRAINT_TYPE_KINEMATIC && (con->flag & CONSTRAINT_OFF) == 0) {
data = con->data;
if (data->tar == NULL || (data->tar->type == OB_ARMATURE && data->subtarget[0] == '\0')) {
@@ -247,22 +304,20 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* if no chain length has been specified,
* just make things obey standard rotation locks too */
if (data->rootbone == 0) {
- for (; pchan; pchan = pchan->parent) {
+ for (bPoseChannel *pchan_iter = pchan; pchan_iter; pchan_iter = pchan_iter->parent) {
/* here, we set ik-settings for bone from pchan->protectflag */
// XXX: careful with quats/axis-angle rotations where we're locking 4d components
- if (pchan->protectflag & OB_LOCK_ROTX) {
- pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTX) {
+ pchan_iter->ikflag |= BONE_IK_NO_XDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTY) {
- pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTY) {
+ pchan_iter->ikflag |= BONE_IK_NO_YDOF_TEMP;
}
- if (pchan->protectflag & OB_LOCK_ROTZ) {
- pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ if (pchan_iter->protectflag & OB_LOCK_ROTZ) {
+ pchan_iter->ikflag |= BONE_IK_NO_ZDOF_TEMP;
}
}
}
-
- return 0;
}
}
@@ -272,20 +327,8 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
}
}
- con = BKE_constraint_add_for_pose(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
+ data = add_temporary_ik_constraint(pchan, targetless)->data;
- /* for draw, but also for detecting while pose solving */
- pchan->constflag |= (PCHAN_HAS_IK | PCHAN_HAS_TARGET);
-
- data = con->data;
- if (targetless) {
- /* if exists, use values from last targetless (but disabled) IK-constraint as base */
- *data = *targetless;
- }
- else {
- data->flag = CONSTRAINT_IK_TIP;
- }
- data->flag |= CONSTRAINT_IK_TEMP | CONSTRAINT_IK_AUTO | CONSTRAINT_IK_POS;
copy_v3_v3(data->grabtarget, pchan->pose_tail);
/* watch-it! has to be 0 here, since we're still on the
@@ -398,14 +441,42 @@ static short pose_grab_with_ik(Main *bmain, Object *ob)
/* iTaSC needs clear for new IK constraints */
if (tot_ik) {
- BIK_clear_data(ob->pose);
- /* TODO(sergey): Consider doing partial update only. */
- DEG_relations_tag_update(bmain);
+ update_deg_with_temporary_ik(bmain, ob);
}
return (tot_ik) ? 1 : 0;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Pose Mirror
+ * \{ */
+
+typedef struct PoseInitData_Mirror {
+ /** Points to the bone which this info is initialized & restored to.
+ * A NULL value is used to terminate the array. */
+ struct bPoseChannel *pchan;
+ struct {
+ float loc[3];
+ float size[3];
+ union {
+ float eul[3];
+ float quat[4];
+ float axis_angle[4];
+ };
+ float curve_in_x;
+ float curve_out_x;
+ float roll1;
+ float roll2;
+ } orig;
+ /**
+ * An extra offset to apply after mirroring.
+ * Use with #POSE_MIRROR_RELATIVE.
+ */
+ float offset_mtx[4][4];
+} PoseInitData_Mirror;
+
static void pose_mirror_info_init(PoseInitData_Mirror *pid,
bPoseChannel *pchan,
bPoseChannel *pchan_orig,
@@ -475,6 +546,103 @@ static void pose_mirror_info_restore(const PoseInitData_Mirror *pid)
}
/**
+ * if pose bone (partial) selected, copy data.
+ * context; posemode armature, with mirror editing enabled.
+ */
+void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object *ob)
+{
+ float flip_mtx[4][4];
+ unit_m4(flip_mtx);
+ flip_mtx[0][0] = -1;
+
+ LISTBASE_FOREACH (bPoseChannel *, pchan_orig, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan_orig->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+ }
+
+ bPose *pose = ob->pose;
+ PoseInitData_Mirror *pid = NULL;
+ if ((t->mode != TFM_BONESIZE) && (pose->flag & POSE_MIRROR_RELATIVE)) {
+ pid = tc->custom.type.data;
+ }
+
+ TransData *td = tc->data;
+ for (int i = tc->data_len; i--; td++) {
+ bPoseChannel *pchan_orig = td->extra;
+ BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM);
+ /* No layer check, correct mirror is more important. */
+ bPoseChannel *pchan = BKE_pose_channel_get_mirrored(pose, pchan_orig->name);
+ if (pchan == NULL) {
+ continue;
+ }
+
+ /* Also do bbone scaling. */
+ pchan->bone->xwidth = pchan_orig->bone->xwidth;
+ pchan->bone->zwidth = pchan_orig->bone->zwidth;
+
+ /* We assume X-axis flipping for now. */
+ pchan->curve_in_x = pchan_orig->curve_in_x * -1;
+ pchan->curve_out_x = pchan_orig->curve_out_x * -1;
+ pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
+ pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
+
+ float pchan_mtx_final[4][4];
+ BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
+ mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
+ mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
+ if (pid) {
+ mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
+ }
+ BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
+
+ /* Set flag to let autokeyframe know to keyframe the mirrred bone. */
+ pchan->bone->flag |= BONE_TRANSFORM_MIRROR;
+
+ /* In this case we can do target-less IK grabbing. */
+ if (t->mode == TFM_TRANSLATION) {
+ bKinematicConstraint *data = has_targetless_ik(pchan);
+ if (data == NULL) {
+ continue;
+ }
+ mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
+ if (pid) {
+ /* TODO(germano): Realitve Mirror support */
+ }
+ data->flag |= CONSTRAINT_IK_AUTO;
+ /* Add a temporary auto IK constraint here, as we will only temporarily active this
+ * target-less bone during transform. (Target-less IK constraints are treated as if they are
+ * disabled unless they are transformed) */
+ add_temporary_ik_constraint(pchan, data);
+ Main *bmain = CTX_data_main(t->context);
+ update_deg_with_temporary_ik(bmain, ob);
+ }
+
+ if (pid) {
+ pid++;
+ }
+ }
+}
+
+void restoreMirrorPoseBones(TransDataContainer *tc)
+{
+ bPose *pose = tc->poseobj->pose;
+
+ if (!(pose->flag & POSE_MIRROR_EDIT)) {
+ return;
+ }
+
+ for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
+ pose_mirror_info_restore(pid);
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Convert Armature
+ * \{ */
+
+/**
* When objects array is NULL, use 't->data_container' as is.
*/
void createTransPose(TransInfo *t)
@@ -501,7 +669,9 @@ void createTransPose(TransInfo *t)
const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0);
/* set flags and count total */
- tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate);
+ tc->data_len = transform_convert_pose_transflags_update(
+ ob, t->mode, t->around, has_translate_rotate);
+
if (tc->data_len == 0) {
continue;
}
@@ -516,7 +686,10 @@ void createTransPose(TransInfo *t)
if (mirror) {
int total_mirrored = 0;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
+ /* Clear the MIRROR flag from previous runs. */
+ pchan->bone->flag &= ~BONE_TRANSFORM_MIRROR;
+
if ((pchan->bone->flag & BONE_TRANSFORM) &&
BKE_pose_channel_get_mirrored(ob->pose, pchan->name)) {
total_mirrored++;
@@ -566,7 +739,7 @@ void createTransPose(TransInfo *t)
}
if (mirror) {
- for (bPoseChannel *pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
bPoseChannel *pchan_mirror = BKE_pose_channel_get_mirrored(ob->pose, pchan->name);
if (pchan_mirror) {
@@ -588,7 +761,7 @@ void createTransPose(TransInfo *t)
/* use pose channels to fill trans data */
td = tc->data;
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
if (pchan->bone->flag & BONE_TRANSFORM) {
add_pose_transdata(t, pchan, ob, tc, td);
td++;
@@ -620,19 +793,6 @@ void createTransPose(TransInfo *t)
t->flag &= ~T_PROP_EDIT_ALL;
}
-void restoreMirrorPoseBones(TransDataContainer *tc)
-{
- bPose *pose = tc->poseobj->pose;
-
- if (!(pose->flag & POSE_MIRROR_EDIT)) {
- return;
- }
-
- for (PoseInitData_Mirror *pid = tc->custom.type.data; pid->pchan; pid++) {
- pose_mirror_info_restore(pid);
- }
-}
-
void restoreBones(TransDataContainer *tc)
{
bArmature *arm;
@@ -682,7 +842,6 @@ void restoreBones(TransDataContainer *tc)
}
}
-/* ********************* armature ************** */
void createTransArmatureVerts(TransInfo *t)
{
t->data_len_all = 0;
@@ -936,3 +1095,5 @@ void createTransArmatureVerts(TransInfo *t)
}
}
}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_convert_cursor.c b/source/blender/editors/transform/transform_convert_cursor.c
index 621f9dd63e2..e6a972bfc7c 100644
--- a/source/blender/editors/transform/transform_convert_cursor.c
+++ b/source/blender/editors/transform/transform_convert_cursor.c
@@ -44,7 +44,7 @@
void createTransCursor_image(TransInfo *t)
{
TransData *td;
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
float *cursor_location = sima->cursor;
{
diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c
index 487de27aff2..42ffe675dc5 100644
--- a/source/blender/editors/transform/transform_convert_curve.c
+++ b/source/blender/editors/transform/transform_convert_curve.c
@@ -25,11 +25,11 @@
#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_context.h"
#include "BKE_curve.h"
-#include "BKE_report.h"
#include "transform.h"
#include "transform_convert.h"
@@ -99,7 +99,7 @@ void createTransCurveVerts(TransInfo *t)
/* count total of vertices, check identical as in 2nd loop for making transdata! */
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
for (a = 0, bezt = nu->bezt; a < nu->pntsu; a++, bezt++) {
if (bezt->hide == 0) {
@@ -167,6 +167,8 @@ void createTransCurveVerts(TransInfo *t)
((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_CU_HANDLES) == 0) :
false;
+ bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ transform_mode_use_local_origins(t));
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc->obedit->obmat);
@@ -174,7 +176,7 @@ void createTransCurveVerts(TransInfo *t)
TransData *td = tc->data;
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- for (Nurb *nu = nurbs->first; nu; nu = nu->next) {
+ LISTBASE_FOREACH (Nurb *, nu, nurbs) {
if (nu->type == CU_BEZIER) {
TransData *head, *tail;
head = tail = td;
@@ -342,7 +344,7 @@ void createTransCurveVerts(TransInfo *t)
if (ELEM(t->mode, TFM_CURVE_SHRINKFATTEN, TFM_TILT, TFM_DUMMY) == 0) {
/* sets the handles based on their selection,
* do this after the data is copied to the TransData */
- BKE_nurb_handles_test(nu, !hide_handles);
+ BKE_nurb_handles_test(nu, !hide_handles, use_around_origins_for_handles_test);
}
}
else {
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 80c0afc3f56..efd7879c8b2 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -30,7 +30,6 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_gpencil.h"
-#include "BKE_report.h"
#include "ED_gpencil.h"
@@ -84,6 +83,8 @@ void createTransGPencil(bContext *C, TransInfo *t)
const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
+ (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -109,7 +110,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
*/
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
bGPDframe *gpf;
bGPDstroke *gps;
bGPDframe *init_gpf = gpl->actframe;
@@ -181,7 +182,7 @@ void createTransGPencil(bContext *C, TransInfo *t)
/* Second Pass: Build transdata array */
for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
bGPDframe *gpf = gpl->actframe;
bGPDstroke *gps;
@@ -197,11 +198,11 @@ void createTransGPencil(bContext *C, TransInfo *t)
int f_end = 0;
if (use_multiframe_falloff) {
- BKE_gpencil_get_range_selected(gpl, &f_init, &f_end);
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
}
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, obact, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
/* undo matrix */
invert_m4_m4(inverse_diff_mat, diff_mat);
@@ -227,10 +228,11 @@ void createTransGPencil(bContext *C, TransInfo *t)
for (gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
- /* if multiframe and falloff, recalculate and save value */
+ /* If multi-frame and falloff, recalculate and save value. */
float falloff = 1.0f; /* by default no falloff */
if ((is_multiedit) && (use_multiframe_falloff)) {
- /* Faloff depends on distance to active frame (relative to the overall frame range) */
+ /* Falloff depends on distance to active frame
+ * (relative to the overall frame range). */
falloff = BKE_gpencil_multiframe_falloff_calc(
gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
}
@@ -313,9 +315,9 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
/* for other transform modes (e.g. shrink-fatten), need to additional data
- * but never for scale or mirror
+ * but never for mirror
*/
- if ((t->mode != TFM_RESIZE) && (t->mode != TFM_MIRROR)) {
+ if ((t->mode != TFM_MIRROR) && (is_scale_thickness)) {
if (t->mode != TFM_GPENCIL_OPACITY) {
td->val = &pt->pressure;
td->ival = pt->pressure;
diff --git a/source/blender/editors/transform/transform_convert_graph.c b/source/blender/editors/transform/transform_convert_graph.c
index f6f982e854a..f6f0dd3c491 100644
--- a/source/blender/editors/transform/transform_convert_graph.c
+++ b/source/blender/editors/transform/transform_convert_graph.c
@@ -1,4 +1,4 @@
-/*
+/*
* 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
@@ -167,7 +167,7 @@ static void graph_bezt_get_transform_selection(const TransInfo *t,
bool *r_key,
bool *r_right_handle)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
bool key = (bezt->f2 & SELECT) != 0;
bool left = use_handle ? ((bezt->f1 & SELECT) != 0) : key;
bool right = use_handle ? ((bezt->f3 & SELECT) != 0) : key;
@@ -224,10 +224,10 @@ static void graph_key_shortest_dist(
*/
void createTransGraphEditData(bContext *C, TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
- ARegion *ar = t->ar;
- View2D *v2d = &ar->v2d;
+ ARegion *region = t->region;
+ View2D *v2d = &region->v2d;
TransData *td = NULL;
TransData2D *td2d = NULL;
@@ -261,11 +261,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
// XXX we still want this mode, but how to get this using standard transform too?
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
@@ -643,7 +639,7 @@ void createTransGraphEditData(bContext *C, TransInfo *t)
*/
void flushTransGraphData(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
TransData *td;
TransData2D *td2d;
TransDataGraph *tdg;
diff --git a/source/blender/editors/transform/transform_convert_lattice.c b/source/blender/editors/transform/transform_convert_lattice.c
index 15af24090f0..57d0f707971 100644
--- a/source/blender/editors/transform/transform_convert_lattice.c
+++ b/source/blender/editors/transform/transform_convert_lattice.c
@@ -29,7 +29,6 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_report.h"
#include "transform.h"
#include "transform_convert.h"
diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c
index 32152442acf..6c743da3e65 100644
--- a/source/blender/editors/transform/transform_convert_mask.c
+++ b/source/blender/editors/transform/transform_convert_mask.c
@@ -280,7 +280,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
}
if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
MovieClip *clip = ED_space_clip_get_clip(sc);
if (!clip) {
return;
@@ -333,7 +333,7 @@ void createTransMaskingData(bContext *C, TransInfo *t)
return;
}
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
tc->data_len = (is_prop_edit) ? count : countsel;
td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mask Editing)");
@@ -409,7 +409,7 @@ void flushTransMasking(TransInfo *t)
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- ED_mask_get_aspect(t->sa, t->ar, &asp[0], &asp[1]);
+ ED_mask_get_aspect(t->area, t->region, &asp[0], &asp[1]);
inv[0] = 1.0f / asp[0];
inv[1] = 1.0f / asp[1];
diff --git a/source/blender/editors/transform/transform_convert_mball.c b/source/blender/editors/transform/transform_convert_mball.c
index 5d7e36cc834..447733357d6 100644
--- a/source/blender/editors/transform/transform_convert_mball.c
+++ b/source/blender/editors/transform/transform_convert_mball.c
@@ -28,7 +28,6 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_report.h"
#include "transform.h"
#include "transform_convert.h"
diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c
index 5d3d1d936a2..24dda8c8464 100644
--- a/source/blender/editors/transform/transform_convert_mesh.c
+++ b/source/blender/editors/transform/transform_convert_mesh.c
@@ -29,9 +29,9 @@
#include "BLI_alloca.h"
#include "BLI_bitmap.h"
+#include "BLI_linklist_stack.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
-#include "BLI_linklist_stack.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
@@ -61,8 +61,10 @@
/* when transforming islands */
struct TransIslandData {
- float co[3];
- float axismtx[3][3];
+ float (*center)[3];
+ float (*axismtx)[3][3];
+ int island_tot;
+ int *island_vert_map;
};
/* -------------------------------------------------------------------- */
@@ -247,18 +249,19 @@ static void editmesh_set_connectivity_distance(BMesh *bm,
}
}
-static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
- int *r_island_tot,
- int **r_island_vert_map,
- bool calc_single_islands)
+static void editmesh_islands_info_calc(BMEditMesh *em,
+ const bool calc_single_islands,
+ const bool calc_island_axismtx,
+ struct TransIslandData *r_island_data)
{
BMesh *bm = em->bm;
- struct TransIslandData *trans_islands;
char htype;
char itype;
int i;
/* group vars */
+ float(*center)[3];
+ float(*axismtx)[3][3] = NULL;
int *groups_array;
int(*group_index)[2];
int group_tot;
@@ -283,7 +286,11 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
itype = BM_VERTS_OF_FACE;
}
- trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__);
+ center = MEM_mallocN(sizeof(*center) * group_tot, __func__);
+
+ if (calc_island_axismtx) {
+ axismtx = MEM_mallocN(sizeof(*axismtx) * group_tot, __func__);
+ }
vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__);
/* we shouldn't need this, but with incorrect selection flushing
@@ -311,7 +318,7 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.htype = htype;
- /* loop on each face in this group:
+ /* loop on each face or edge in this group:
* - assign r_vert_map
* - calculate (co, no)
*/
@@ -321,12 +328,14 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
ese.ele = ele_array[groups_array[fg_sta + j]];
BM_editselection_center(&ese, tmp_co);
- BM_editselection_normal(&ese, tmp_no);
- BM_editselection_plane(&ese, tmp_tangent);
-
add_v3_v3(co, tmp_co);
- add_v3_v3(no, tmp_no);
- add_v3_v3(tangent, tmp_tangent);
+
+ if (axismtx) {
+ BM_editselection_normal(&ese, tmp_no);
+ BM_editselection_plane(&ese, tmp_tangent);
+ add_v3_v3(no, tmp_no);
+ add_v3_v3(tangent, tmp_tangent);
+ }
{
/* setup vertex map */
@@ -340,18 +349,20 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len);
+ mul_v3_v3fl(center[i], co, 1.0f / (float)fg_len);
- if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) {
- /* pass */
- }
- else {
- if (normalize_v3(no) != 0.0f) {
- axis_dominant_v3_to_m3(trans_islands[i].axismtx, no);
- invert_m3(trans_islands[i].axismtx);
+ if (axismtx) {
+ if (createSpaceNormalTangent(axismtx[i], no, tangent)) {
+ /* pass */
}
else {
- unit_m3(trans_islands[i].axismtx);
+ if (normalize_v3(no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[i], no);
+ invert_m3(axismtx[i]);
+ }
+ else {
+ unit_m3(axismtx[i]);
+ }
}
}
}
@@ -372,22 +383,24 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
if (group_tot_single != 0) {
- trans_islands = MEM_reallocN(trans_islands,
- sizeof(*trans_islands) * (group_tot + group_tot_single));
+ center = MEM_reallocN(center, sizeof(*center) * (group_tot + group_tot_single));
+ if (axismtx) {
+ axismtx = MEM_reallocN(axismtx, sizeof(*axismtx) * (group_tot + group_tot_single));
+ }
BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) {
- struct TransIslandData *v_island = &trans_islands[group_tot];
vert_map[i] = group_tot;
+ copy_v3_v3(center[group_tot], v->co);
- copy_v3_v3(v_island->co, v->co);
-
- if (is_zero_v3(v->no) != 0.0f) {
- axis_dominant_v3_to_m3(v_island->axismtx, v->no);
- invert_m3(v_island->axismtx);
- }
- else {
- unit_m3(v_island->axismtx);
+ if (axismtx) {
+ if (is_zero_v3(v->no) != 0.0f) {
+ axis_dominant_v3_to_m3(axismtx[group_tot], v->no);
+ invert_m3(axismtx[group_tot]);
+ }
+ else {
+ unit_m3(axismtx[group_tot]);
+ }
}
group_tot += 1;
@@ -396,10 +409,10 @@ static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em,
}
}
- *r_island_tot = group_tot;
- *r_island_vert_map = vert_map;
-
- return trans_islands;
+ r_island_data->axismtx = axismtx;
+ r_island_data->center = center;
+ r_island_data->island_tot = group_tot;
+ r_island_data->island_vert_map = vert_map;
}
static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
@@ -567,7 +580,8 @@ static void VertsToTransData(TransInfo *t,
BMEditMesh *em,
BMVert *eve,
float *bweight,
- struct TransIslandData *v_island,
+ const struct TransIslandData *island_data,
+ const int island_index,
const bool no_island_center)
{
float *no, _no[3];
@@ -589,14 +603,17 @@ static void VertsToTransData(TransInfo *t,
no = eve->no;
}
- if (v_island) {
+ if (island_index != -1) {
if (no_island_center) {
copy_v3_v3(td->center, td->loc);
}
else {
- copy_v3_v3(td->center, v_island->co);
+ copy_v3_v3(td->center, island_data->center[island_index]);
}
- copy_m3_m3(td->axismtx, v_island->axismtx);
+ }
+
+ if ((island_index != -1) && island_data->axismtx) {
+ copy_m3_m3(td->axismtx, island_data->axismtx[island_index]);
}
else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
copy_v3_v3(td->center, td->loc);
@@ -654,9 +671,7 @@ void createTransEditVerts(TransInfo *t)
const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
int cd_vert_bweight_offset = -1;
- struct TransIslandData *island_info = NULL;
- int island_info_tot;
- int *island_vert_map = NULL;
+ struct TransIslandData island_data = {NULL};
/* Snap rotation along normal needs a common axis for whole islands,
* otherwise one get random crazy results, see T59104.
@@ -758,14 +773,17 @@ void createTransEditVerts(TransInfo *t)
(t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(em->selectmode & SCE_SELECT_VERTEX));
- island_info = editmesh_islands_info_calc(
- em, &island_info_tot, &island_vert_map, calc_single_islands);
+ /* The island axismtx is only necessary in some modes.
+ * TODO(Germano): Extend the list to exclude other modes. */
+ const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN);
+
+ editmesh_islands_info_calc(em, calc_single_islands, calc_island_axismtx, &island_data);
}
/* detect CrazySpace [tm] */
- if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) {
+ if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) {
int totleft = -1;
- if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) {
+ if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) {
BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
/* Use evaluated state because we need b-bone cache. */
@@ -809,21 +827,19 @@ void createTransEditVerts(TransInfo *t)
continue;
}
if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- struct TransIslandData *v_island = NULL;
float *bweight = (cd_vert_bweight_offset != -1) ?
BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) :
NULL;
- if (island_info) {
+ int island_index = -1;
+ if (island_data.island_vert_map) {
const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
- v_island = (island_vert_map[connected_index] != -1) ?
- &island_info[island_vert_map[connected_index]] :
- NULL;
+ island_index = island_data.island_vert_map[connected_index];
}
/* Do not use the island center in case we are using islands
* only to get axis for snap/rotate to normal... */
- VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate);
+ VertsToTransData(t, tob, tx, em, eve, bweight, &island_data, island_index, is_snap_rotate);
if (tx) {
tx++;
}
@@ -889,9 +905,16 @@ void createTransEditVerts(TransInfo *t)
}
}
- if (island_info) {
- MEM_freeN(island_info);
- MEM_freeN(island_vert_map);
+ if (island_data.center) {
+ MEM_freeN(island_data.center);
+ }
+
+ if (island_data.axismtx) {
+ MEM_freeN(island_data.axismtx);
+ }
+
+ if (island_data.island_vert_map) {
+ MEM_freeN(island_data.island_vert_map);
}
cleanup:
@@ -1030,7 +1053,15 @@ static void create_trans_vert_customdata_layer(BMVert *v,
void trans_mesh_customdata_correction_init(TransInfo *t)
{
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
- BLI_assert(tc->custom.type.data == NULL);
+ if (tc->custom.type.data) {
+ if (tc->custom.type.free_cb == trans_mesh_customdata_free_cb) {
+ /* Custom data correction has initiated before. */
+ continue;
+ }
+ else {
+ BLI_assert(false);
+ }
+ }
int i;
BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
@@ -1168,7 +1199,7 @@ static void trans_mesh_customdata_correction_apply_vert(struct TransCustomDataLa
BM_loop_interp_from_face(bm, l, f_copy, false, false);
/* make sure face-attributes are correct (e.g. #MLoopUV, #MLoopCol) */
- BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, 0x0, CD_MASK_NORMAL);
+ BM_elem_attrs_copy_ex(tcld->bm_origfaces, bm, f_copy, l->f, BM_ELEM_SELECT, CD_MASK_NORMAL);
/* weight the loop */
if (do_loop_weight) {
@@ -1600,7 +1631,7 @@ void createTransUVs(bContext *C, TransInfo *t)
void flushTransUVs(TransInfo *t)
{
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
const bool use_pixel_snap = ((sima->pixel_snap_mode != SI_PIXEL_SNAP_DISABLED) &&
(t->state != TRANS_CANCEL));
diff --git a/source/blender/editors/transform/transform_convert_nla.c b/source/blender/editors/transform/transform_convert_nla.c
index 114968ec83f..2978c36b15f 100644
--- a/source/blender/editors/transform/transform_convert_nla.c
+++ b/source/blender/editors/transform/transform_convert_nla.c
@@ -26,17 +26,15 @@
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
-#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_nla.h"
#include "BKE_report.h"
#include "ED_anim_api.h"
-#include "UI_view2d.h"
-
#include "transform.h"
#include "transform_convert.h"
@@ -73,11 +71,7 @@ void createTransNlaData(bContext *C, TransInfo *t)
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- float xmouse, ymouse;
-
- UI_view2d_region_to_view(&ac.ar->v2d, t->mouse.imval[0], t->mouse.imval[1], &xmouse, &ymouse);
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
}
else {
/* normal transform - both sides of current frame are considered */
diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c
index ee4aa053444..d783bfdf40e 100644
--- a/source/blender/editors/transform/transform_convert_node.c
+++ b/source/blender/editors/transform/transform_convert_node.c
@@ -109,7 +109,7 @@ void createTransNodeData(bContext *UNUSED(C), TransInfo *t)
const float dpi_fac = UI_DPI_FAC;
TransData *td;
TransData2D *td2d;
- SpaceNode *snode = t->sa->spacedata.first;
+ SpaceNode *snode = t->area->spacedata.first;
bNode *node;
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
@@ -188,7 +188,7 @@ void flushTransNodes(TransInfo *t)
/* handle intersection with noodles */
if (tc->data_len == 1) {
- ED_node_link_intersect_test(t->sa, 1);
+ ED_node_link_intersect_test(t->area, 1);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 16dfdd35c32..8deba0f7ad0 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -63,12 +63,10 @@ typedef struct TransDataObject {
* - The key is object data #Object.
* - The value is #XFormObjectSkipChild.
*/
- struct GHash *obchild_in_obmode_map;
+ struct XFormObjectSkipChild_Container *xcs;
} TransDataObject;
-static void trans_obchild_in_obmode_free_all(TransDataObject *tdo);
-
static void freeTransObjectCustomData(TransInfo *t,
TransDataContainer *UNUSED(tc),
TransCustomData *custom_data)
@@ -81,7 +79,7 @@ static void freeTransObjectCustomData(TransInfo *t,
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
- trans_obchild_in_obmode_free_all(tdo);
+ ED_object_xform_skip_child_container_destroy(tdo->xcs);
}
MEM_freeN(tdo);
}
@@ -117,140 +115,19 @@ void trans_obdata_in_obmode_update_all(TransInfo *t)
* Don't transform unselected children, this is done using the parent inverse matrix.
*
* \note The complex logic here is caused by mixed selection within a single selection chain,
- * otherwise we only need #OB_SKIP_CHILD_PARENT_IS_XFORM for single objects.
+ * otherwise we only need #XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM for single objects.
*
* \{ */
-enum {
- /**
- * The parent is transformed, this is held in place.
- */
- OB_SKIP_CHILD_PARENT_IS_XFORM = 1,
- /**
- * The same as #OB_SKIP_CHILD_PARENT_IS_XFORM,
- * however this objects parent isn't transformed directly.
- */
- OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT = 3,
- /**
- * Use the parent invert matrix to apply transformation,
- * this is needed, because breaks in the selection chain prevents this from being transformed.
- * This is used to add the transform which would have been added
- * if there weren't breaks in the parent/child chain.
- */
- OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM = 2,
-};
-
-struct XFormObjectSkipChild {
- float obmat_orig[4][4];
- float parent_obmat_orig[4][4];
- float parent_obmat_inv_orig[4][4];
- float parent_recurse_obmat_orig[4][4];
- float parentinv_orig[4][4];
- Object *ob_parent_recurse;
- int mode;
-};
-
-static void trans_obchild_in_obmode_ensure_object(TransDataObject *tdo,
- Object *ob,
- Object *ob_parent_recurse,
- int mode)
-{
- if (tdo->obchild_in_obmode_map == NULL) {
- tdo->obchild_in_obmode_map = BLI_ghash_ptr_new(__func__);
- }
-
- void **xf_p;
- if (!BLI_ghash_ensure_p(tdo->obchild_in_obmode_map, ob, &xf_p)) {
- struct XFormObjectSkipChild *xf = MEM_mallocN(sizeof(*xf), __func__);
- copy_m4_m4(xf->parentinv_orig, ob->parentinv);
- copy_m4_m4(xf->obmat_orig, ob->obmat);
- copy_m4_m4(xf->parent_obmat_orig, ob->parent->obmat);
- invert_m4_m4(xf->parent_obmat_inv_orig, ob->parent->obmat);
- if (ob_parent_recurse) {
- copy_m4_m4(xf->parent_recurse_obmat_orig, ob_parent_recurse->obmat);
- }
- xf->mode = mode;
- xf->ob_parent_recurse = ob_parent_recurse;
- *xf_p = xf;
- }
-}
-
void trans_obchild_in_obmode_update_all(TransInfo *t)
{
TransDataObject *tdo = t->custom.type.data;
- if (tdo->obchild_in_obmode_map == NULL) {
+ if (tdo->xcs == NULL) {
return;
}
struct Main *bmain = CTX_data_main(t->context);
- BKE_scene_graph_evaluated_ensure(t->depsgraph, bmain);
-
- GHashIterator gh_iter;
- GHASH_ITER (gh_iter, tdo->obchild_in_obmode_map) {
- Object *ob = BLI_ghashIterator_getKey(&gh_iter);
- struct XFormObjectSkipChild *xf = BLI_ghashIterator_getValue(&gh_iter);
-
- /* The following blocks below assign 'dmat'. */
- float dmat[4][4];
-
- if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM) {
- /* Parent is transformed, this isn't so compensate. */
- Object *ob_parent_eval = DEG_get_evaluated_object(t->depsgraph, ob->parent);
- mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, ob_parent_eval->obmat);
- invert_m4(dmat);
- }
- else if (xf->mode == OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT) {
- /* Calculate parent matrix (from the root transform). */
- Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
- xf->ob_parent_recurse);
- float parent_recurse_obmat_inv[4][4];
- invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
- mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
- invert_m4(dmat);
- float parent_obmat_calc[4][4];
- mul_m4_m4m4(parent_obmat_calc, dmat, xf->parent_obmat_orig);
-
- /* Apply to the parent inverse matrix. */
- mul_m4_m4m4(dmat, xf->parent_obmat_inv_orig, parent_obmat_calc);
- invert_m4(dmat);
- }
- else {
- BLI_assert(xf->mode == OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
- /* Transform this - without transform data. */
- Object *ob_parent_recurse_eval = DEG_get_evaluated_object(t->depsgraph,
- xf->ob_parent_recurse);
- float parent_recurse_obmat_inv[4][4];
- invert_m4_m4(parent_recurse_obmat_inv, ob_parent_recurse_eval->obmat);
- mul_m4_m4m4(dmat, xf->parent_recurse_obmat_orig, parent_recurse_obmat_inv);
- invert_m4(dmat);
- float obmat_calc[4][4];
- mul_m4_m4m4(obmat_calc, dmat, xf->obmat_orig);
- /* obmat_calc is just obmat. */
-
- /* Get the matrices relative to the parent. */
- float obmat_parent_relative_orig[4][4];
- float obmat_parent_relative_calc[4][4];
- float obmat_parent_relative_inv_orig[4][4];
-
- mul_m4_m4m4(obmat_parent_relative_orig, xf->parent_obmat_inv_orig, xf->obmat_orig);
- mul_m4_m4m4(obmat_parent_relative_calc, xf->parent_obmat_inv_orig, obmat_calc);
- invert_m4_m4(obmat_parent_relative_inv_orig, obmat_parent_relative_orig);
-
- /* Apply to the parent inverse matrix. */
- mul_m4_m4m4(dmat, obmat_parent_relative_calc, obmat_parent_relative_inv_orig);
- }
-
- mul_m4_m4m4(ob->parentinv, dmat, xf->parentinv_orig);
-
- DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
- }
-}
-
-static void trans_obchild_in_obmode_free_all(TransDataObject *tdo)
-{
- if (tdo->obchild_in_obmode_map != NULL) {
- BLI_ghash_free(tdo->obchild_in_obmode_map, NULL, MEM_freeN);
- }
+ ED_object_xform_skip_child_container_update_all(tdo->xcs, bmain, t->depsgraph);
}
/** \} */
@@ -320,7 +197,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
/* NOTE: This is not really following copy-on-write design and we should not
* be re-evaluating the evaluated object. But as the comment above mentioned
* this is part of a hack.
- * More proper solution would be to make a shallow copy of the object and
+ * More proper solution would be to make a shallow copy of the object and
* evaluate that, and access matrix of that evaluated copy of the object.
* Might be more tricky than it sounds, if some logic later on accesses the
* object matrix via td->ob->obmat. */
@@ -413,7 +290,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer)
{
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->object->id.tag &= ~LIB_TAG_DOIT;
}
}
@@ -447,7 +324,7 @@ static void trans_object_base_deps_flag_finish(const TransInfo *t, ViewLayer *vi
{
if ((t->options & CTX_OBMODE_XFORM_OBDATA) == 0) {
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->object->id.tag & LIB_TAG_DOIT) {
base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO;
}
@@ -478,7 +355,7 @@ static void set_trans_object_base_flags(TransInfo *t)
/* Clear all flags we need. It will be used to detect dependencies. */
trans_object_base_deps_flag_prepare(view_layer);
/* Traverse all bases and set all possible flags. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
base->flag_legacy &= ~(BA_WAS_SEL | BA_TRANSFORM_LOCKED_IN_PLACE);
if (BASE_SELECTED_EDITABLE(v3d, base)) {
Object *ob = base->object;
@@ -545,7 +422,7 @@ static int count_proportional_objects(TransInfo *t)
if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
(t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) {
/* Mark all parents. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (BASE_SELECTED_EDITABLE(v3d, base) && BASE_SELECTABLE(v3d, base)) {
Object *parent = base->object->parent;
/* flag all parents */
@@ -556,7 +433,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Mark all children. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
/* all base not already selected or marked that is editable */
if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 &&
(base->flag & BASE_SELECTED) == 0 &&
@@ -566,7 +443,7 @@ static int count_proportional_objects(TransInfo *t)
}
}
/* Flush changed flags to all dependencies. */
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* If base is not selected, not a parent of selection or not a child of
* selection and it is editable and selectable.
@@ -715,7 +592,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
View3D *v3d = t->view;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
/* if base is not selected, not a parent of selection
@@ -746,6 +623,8 @@ void createTransObject(bContext *C, TransInfo *t)
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
+ tdo->xcs = ED_object_xform_skip_child_container_create();
+
#define BASE_XFORM_INDIRECT(base) \
((base->flag_legacy & BA_WAS_SEL) && (base->flag & BASE_SELECTED) == 0)
@@ -760,7 +639,7 @@ void createTransObject(bContext *C, TransInfo *t)
ViewLayer *view_layer = t->view_layer;
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (ob->parent != NULL) {
if (ob->parent && !BLI_gset_haskey(objects_in_transdata, ob->parent) &&
@@ -778,8 +657,8 @@ void createTransObject(bContext *C, TransInfo *t)
}
if (ob_parent_recurse) {
- trans_obchild_in_obmode_ensure_object(
- tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_APPLY_TRANSFORM);
+ ED_object_xform_skip_child_container_item_ensure(
+ tdo->xcs, ob, ob_parent_recurse, XFORM_OB_SKIP_CHILD_PARENT_APPLY);
BLI_ghash_insert(objects_parent_root, ob, ob_parent_recurse);
base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
}
@@ -790,7 +669,7 @@ void createTransObject(bContext *C, TransInfo *t)
}
}
- for (Base *base = view_layer->object_bases.first; base; base = base->next) {
+ LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
Object *ob = base->object;
if (BASE_XFORM_INDIRECT(base) || BLI_gset_haskey(objects_in_transdata, ob)) {
@@ -801,14 +680,15 @@ void createTransObject(bContext *C, TransInfo *t)
if (base_parent) {
if (BASE_XFORM_INDIRECT(base_parent) ||
BLI_gset_haskey(objects_in_transdata, ob->parent)) {
- trans_obchild_in_obmode_ensure_object(tdo, ob, NULL, OB_SKIP_CHILD_PARENT_IS_XFORM);
+ ED_object_xform_skip_child_container_item_ensure(
+ tdo->xcs, ob, NULL, XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM);
base->flag_legacy |= BA_TRANSFORM_LOCKED_IN_PLACE;
}
else {
Object *ob_parent_recurse = BLI_ghash_lookup(objects_parent_root, ob->parent);
if (ob_parent_recurse) {
- trans_obchild_in_obmode_ensure_object(
- tdo, ob, ob_parent_recurse, OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT);
+ ED_object_xform_skip_child_container_item_ensure(
+ tdo->xcs, ob, ob_parent_recurse, XFORM_OB_SKIP_CHILD_PARENT_IS_XFORM_INDIRECT);
}
}
}
diff --git a/source/blender/editors/transform/transform_convert_paintcurve.c b/source/blender/editors/transform/transform_convert_paintcurve.c
index 6d46a94214e..4dbe57fc143 100644
--- a/source/blender/editors/transform/transform_convert_paintcurve.c
+++ b/source/blender/editors/transform/transform_convert_paintcurve.c
@@ -29,7 +29,6 @@
#include "BKE_context.h"
#include "BKE_paint.h"
-#include "BKE_report.h"
#include "transform.h"
#include "transform_convert.h"
diff --git a/source/blender/editors/transform/transform_convert_particle.c b/source/blender/editors/transform/transform_convert_particle.c
index 2a961da018b..4e1fc6ae1fa 100644
--- a/source/blender/editors/transform/transform_convert_particle.c
+++ b/source/blender/editors/transform/transform_convert_particle.c
@@ -21,15 +21,14 @@
* \ingroup edtransform
*/
-#include "DNA_particle_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_report.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
diff --git a/source/blender/editors/transform/transform_convert_sculpt.c b/source/blender/editors/transform/transform_convert_sculpt.c
index 6b584f806b8..55dc36e9693 100644
--- a/source/blender/editors/transform/transform_convert_sculpt.c
+++ b/source/blender/editors/transform/transform_convert_sculpt.c
@@ -21,16 +21,13 @@
* \ingroup edtransform
*/
-#include "DNA_space_types.h"
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_report.h"
-#include "BKE_scene.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "transform.h"
#include "transform_convert.h"
diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c
index 4baf0e8a3cb..0175bf6e673 100644
--- a/source/blender/editors/transform/transform_convert_sequencer.c
+++ b/source/blender/editors/transform/transform_convert_sequencer.c
@@ -28,8 +28,8 @@
#include "BLI_math.h"
#include "BKE_context.h"
-#include "BKE_sequencer.h"
#include "BKE_report.h"
+#include "BKE_sequencer.h"
#include "UI_view2d.h"
@@ -49,7 +49,7 @@
* seq->depth must be set before running this function so we know if the strips
* are root level or not
*/
-static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count, int *flag)
+static void SeqTransInfo(TransInfo *t, Sequence *seq, int *r_recursive, int *r_count, int *r_flag)
{
/* for extend we need to do some tricks */
if (t->mode == TFM_TIME_EXTEND) {
@@ -62,51 +62,51 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count
int right = BKE_sequence_tx_get_final_right(seq, true);
if (seq->depth == 0 && ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK))) {
- *recursive = false;
- *count = 0;
- *flag = 0;
+ *r_recursive = false;
+ *r_count = 0;
+ *r_flag = 0;
}
else if (seq->type == SEQ_TYPE_META) {
/* for meta's we only ever need to extend their children, no matter what depth
* just check the meta's are in the bounds */
if (t->frame_side == 'R' && right <= cfra) {
- *recursive = false;
+ *r_recursive = false;
}
else if (t->frame_side == 'L' && left >= cfra) {
- *recursive = false;
+ *r_recursive = false;
}
else {
- *recursive = true;
+ *r_recursive = true;
}
- *count = 1;
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *r_count = 1;
+ *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
}
else {
- *recursive = false; /* not a meta, so no thinking here */
- *count = 1; /* unless its set to 0, extend will never set 2 handles at once */
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *r_recursive = false; /* not a meta, so no thinking here */
+ *r_count = 1; /* unless its set to 0, extend will never set 2 handles at once */
+ *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
if (t->frame_side == 'R') {
if (right <= cfra) {
- *count = *flag = 0;
+ *r_count = *r_flag = 0;
} /* ignore */
else if (left > cfra) {
} /* keep the selection */
else {
- *flag |= SEQ_RIGHTSEL;
+ *r_flag |= SEQ_RIGHTSEL;
}
}
else {
if (left >= cfra) {
- *count = *flag = 0;
+ *r_count = *r_flag = 0;
} /* ignore */
else if (right < cfra) {
} /* keep the selection */
else {
- *flag |= SEQ_LEFTSEL;
+ *r_flag |= SEQ_LEFTSEL;
}
}
}
@@ -123,28 +123,28 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count
/* Non nested strips (resect selection and handles) */
if ((seq->flag & SELECT) == 0 || (seq->flag & SEQ_LOCK)) {
- *recursive = false;
- *count = 0;
- *flag = 0;
+ *r_recursive = false;
+ *r_count = 0;
+ *r_flag = 0;
}
else {
if ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == (SEQ_LEFTSEL | SEQ_RIGHTSEL)) {
- *flag = seq->flag;
- *count = 2; /* we need 2 transdata's */
+ *r_flag = seq->flag;
+ *r_count = 2; /* we need 2 transdata's */
}
else {
- *flag = seq->flag;
- *count = 1; /* selected or with a handle selected */
+ *r_flag = seq->flag;
+ *r_count = 1; /* selected or with a handle selected */
}
/* Recursive */
if ((seq->type == SEQ_TYPE_META) && ((seq->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) == 0)) {
/* if any handles are selected, don't recurse */
- *recursive = true;
+ *r_recursive = true;
}
else {
- *recursive = false;
+ *r_recursive = false;
}
}
}
@@ -152,23 +152,23 @@ static void SeqTransInfo(TransInfo *t, Sequence *seq, int *recursive, int *count
/* Nested, different rules apply */
#ifdef SEQ_TX_NESTED_METAS
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = (seq->type == SEQ_TYPE_META);
+ *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *r_count = 1; /* ignore the selection for nested */
+ *r_recursive = (seq->type == SEQ_TYPE_META);
#else
if (seq->type == SEQ_TYPE_META) {
/* Meta's can only directly be moved between channels since they
* don't have their start and length set directly (children affect that)
* since this Meta is nested we don't need any of its data in fact.
* BKE_sequence_calc() will update its settings when run on the top-level meta. */
- *flag = 0;
- *count = 0;
- *recursive = true;
+ *r_flag = 0;
+ *r_count = 0;
+ *r_recursive = true;
}
else {
- *flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
- *count = 1; /* ignore the selection for nested */
- *recursive = false;
+ *r_flag = (seq->flag | SELECT) & ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
+ *r_count = 1; /* ignore the selection for nested */
+ *r_recursive = false;
}
#endif
}
@@ -381,7 +381,7 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
}
if (overlap) {
- const bool use_sync_markers = (((SpaceSeq *)t->sa->spacedata.first)->flag &
+ const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag &
SEQ_MARKER_TRANS) != 0;
ListBase *markers = &t->scene->markers;
@@ -522,18 +522,16 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c
DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
}
-void createTransSeqData(bContext *C, TransInfo *t)
+void createTransSeqData(TransInfo *t)
{
#define XXX_DURIAN_ANIM_TX_HACK
- View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = t->scene;
Editing *ed = BKE_sequencer_editing_get(t->scene, false);
TransData *td = NULL;
TransData2D *td2d = NULL;
TransDataSeq *tdsq = NULL;
TransSeq *ts = NULL;
- int xmouse;
int count = 0;
@@ -545,18 +543,7 @@ void createTransSeqData(bContext *C, TransInfo *t)
}
tc->custom.type.free_cb = freeSeqData;
-
- xmouse = (int)UI_view2d_region_to_view_x(v2d, t->mouse.imval[0]);
-
- /* which side of the current frame should be allowed */
- if (t->mode == TFM_TIME_EXTEND) {
- /* only side on which mouse is gets transformed */
- t->frame_side = (xmouse > CFRA) ? 'R' : 'L';
- }
- else {
- /* normal transform - both sides of current frame are considered */
- t->frame_side = 'B';
- }
+ t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
#ifdef XXX_DURIAN_ANIM_TX_HACK
{
@@ -598,9 +585,12 @@ void createTransSeqData(bContext *C, TransInfo *t)
SeqToTransData_Recursive(t, ed->seqbasep, td, td2d, tdsq);
SeqTransDataBounds(t, ed->seqbasep, ts);
- /* set the snap mode based on how close the mouse is at the end/start points */
- if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
- ts->snap_left = true;
+ if (t->flag & T_MODAL) {
+ /* set the snap mode based on how close the mouse is at the end/start points */
+ int xmouse = (int)UI_view2d_region_to_view_x((View2D *)t->view, t->mouse.imval[0]);
+ if (abs(xmouse - ts->max) > abs(xmouse - ts->min)) {
+ ts->snap_left = true;
+ }
}
#undef XXX_DURIAN_ANIM_TX_HACK
diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c
index b68b79adbd8..6704567a76b 100644
--- a/source/blender/editors/transform/transform_convert_tracking.c
+++ b/source/blender/editors/transform/transform_convert_tracking.c
@@ -518,7 +518,7 @@ static void createTransTrackingCurvesData(bContext *C, TransInfo *t)
void createTransTrackingData(bContext *C, TransInfo *t)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
SpaceClip *sc = CTX_wm_space_clip(C);
MovieClip *clip = ED_space_clip_get_clip(sc);
int width, height;
@@ -537,7 +537,7 @@ void createTransTrackingData(bContext *C, TransInfo *t)
return;
}
- if (ar->regiontype == RGN_TYPE_PREVIEW) {
+ if (region->regiontype == RGN_TYPE_PREVIEW) {
/* transformation was called from graph editor */
createTransTrackingCurvesData(C, t);
}
@@ -549,7 +549,7 @@ void createTransTrackingData(bContext *C, TransInfo *t)
void cancelTransTracking(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
int i, framenr = ED_space_clip_get_clip_frame_number(sc);
TransDataTracking *tdt_array = tc->custom.type.data;
diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c
index dc2ebdca56a..95ca5ae0c30 100644
--- a/source/blender/editors/transform/transform_draw_cursors.c
+++ b/source/blender/editors/transform/transform_draw_cursors.c
@@ -148,9 +148,9 @@ static void drawArc(float angle_start, float angle_end, int segments, float size
*/
bool transform_draw_cursor_poll(bContext *C)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
- if (ar && ar->regiontype == RGN_TYPE_WINDOW) {
+ if (region && region->regiontype == RGN_TYPE_WINDOW) {
return 1;
}
return 0;
@@ -181,8 +181,8 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
projectFloatViewEx(t, t->center_global, cent, V3D_PROJ_TEST_CLIP_ZERO);
/* Offset the values for the area region. */
const float offset[2] = {
- t->ar->winrct.xmin,
- t->ar->winrct.ymin,
+ t->region->winrct.xmin,
+ t->region->winrct.ymin,
};
for (int i = 0; i < 2; i++) {
@@ -313,7 +313,7 @@ void transform_draw_cursor_draw(bContext *UNUSED(C), int x, int y, void *customd
break;
}
case HLP_TRACKBALL: {
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
UI_GetThemeColor3ubv(TH_GRID, col);
GPU_matrix_translate_3fv(mval);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 5595c3a0e38..4472facf183 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -21,8 +21,8 @@
* \ingroup edtransform
*/
-#include <string.h>
#include <math.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -34,20 +34,21 @@
#include "DNA_constraint_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
+#include "DNA_mask_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_movieclip_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_mesh_types.h"
#include "DNA_view3d_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_movieclip_types.h"
-#include "DNA_mask_types.h"
-#include "DNA_meta_types.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
+#include "BLI_math.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
@@ -63,16 +64,16 @@
#include "BIK_api.h"
#include "BKE_action.h"
-#include "BKE_animsys.h"
+#include "BKE_anim_data.h"
#include "BKE_armature.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
-#include "BKE_gpencil.h"
+#include "BKE_gpencil_geom.h"
#include "BKE_lattice.h"
#include "BKE_layer.h"
-#include "BKE_library.h"
+#include "BKE_lib_id.h"
#include "BKE_mask.h"
#include "BKE_nla.h"
#include "BKE_paint.h"
@@ -86,24 +87,24 @@
#include "ED_anim_api.h"
#include "ED_armature.h"
+#include "ED_clip.h"
+#include "ED_curve.h" /* for curve_editnurbs */
+#include "ED_gpencil.h"
#include "ED_image.h"
#include "ED_keyframing.h"
#include "ED_markers.h"
#include "ED_mesh.h"
#include "ED_object.h"
#include "ED_particle.h"
+#include "ED_screen.h"
#include "ED_screen_types.h"
+#include "ED_sculpt.h"
#include "ED_space_api.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
-#include "ED_curve.h" /* for curve_editnurbs */
-#include "ED_clip.h"
-#include "ED_screen.h"
-#include "ED_gpencil.h"
-#include "ED_sculpt.h"
-#include "WM_types.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "RE_engine.h"
@@ -112,6 +113,7 @@
#include "transform.h"
#include "transform_convert.h"
+#include "transform_mode.h"
#include "transform_snap.h"
/* ************************** Functions *************************** */
@@ -335,7 +337,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
static bool fcu_test_selected(FCurve *fcu)
{
BezTriple *bezt = fcu->bezt;
- unsigned int i;
+ uint i;
if (bezt == NULL) { /* ignore baked */
return 0;
@@ -354,7 +356,7 @@ static bool fcu_test_selected(FCurve *fcu)
static void recalcData_actedit(TransInfo *t)
{
ViewLayer *view_layer = t->view_layer;
- SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
bAnimContext ac = {NULL};
ListBase anim_data = {NULL, NULL};
@@ -367,11 +369,11 @@ static void recalcData_actedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
- ac.ar = t->ar;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
- ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
+ ac.area = t->area;
+ ac.region = t->region;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
+ ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -404,7 +406,7 @@ static void recalcData_actedit(TransInfo *t)
/* helper for recalcData() - for Graph Editor transforms */
static void recalcData_graphedit(TransInfo *t)
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
ViewLayer *view_layer = t->view_layer;
ListBase anim_data = {NULL, NULL};
@@ -420,11 +422,11 @@ static void recalcData_graphedit(TransInfo *t)
ac.scene = t->scene;
ac.view_layer = t->view_layer;
ac.obact = OBACT(view_layer);
- ac.sa = t->sa;
- ac.ar = t->ar;
- ac.sl = (t->sa) ? t->sa->spacedata.first : NULL;
- ac.spacetype = (t->sa) ? t->sa->spacetype : 0;
- ac.regiontype = (t->ar) ? t->ar->regiontype : 0;
+ ac.area = t->area;
+ ac.region = t->region;
+ ac.sl = (t->area) ? t->area->spacedata.first : NULL;
+ ac.spacetype = (t->area) ? t->area->spacetype : 0;
+ ac.regiontype = (t->region) ? t->region->regiontype : 0;
ANIM_animdata_context_getdata(&ac);
@@ -472,7 +474,7 @@ static void recalcData_graphedit(TransInfo *t)
/* helper for recalcData() - for NLA Editor transforms */
static void recalcData_nla(TransInfo *t)
{
- SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
Scene *scene = t->scene;
double secf = FPS;
int i;
@@ -716,7 +718,7 @@ static void recalcData_image(TransInfo *t)
flushTransPaintCurve(t);
}
else if ((t->flag & T_EDIT) && t->obedit_type == OB_MESH) {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
flushTransUVs(t);
if (sima->flag & SI_LIVE_UNWRAP) {
@@ -734,7 +736,7 @@ static void recalcData_image(TransInfo *t)
/* helper for recalcData() - for Movie Clip transforms */
static void recalcData_spaceclip(TransInfo *t)
{
- SpaceClip *sc = t->sa->spacedata.first;
+ SpaceClip *sc = t->area->spacedata.first;
if (ED_space_clip_check_show_trackedit(sc)) {
MovieClip *clip = ED_space_clip_get_clip(sc);
@@ -782,69 +784,6 @@ static void recalcData_spaceclip(TransInfo *t)
}
}
-/**
- * if pose bone (partial) selected, copy data.
- * context; posemode armature, with mirror editing enabled.
- *
- * \param pid: Optional, apply relative transform when set (has no effect on mirrored bones).
- */
-static void pose_transform_mirror_update(TransInfo *t,
- TransDataContainer *tc,
- Object *ob,
- PoseInitData_Mirror *pid)
-{
- float flip_mtx[4][4];
- unit_m4(flip_mtx);
- flip_mtx[0][0] = -1;
-
- TransData *td = tc->data;
- for (int i = tc->data_len; i--; td++) {
- bPoseChannel *pchan_orig = td->extra;
- BLI_assert(pchan_orig->bone->flag & BONE_TRANSFORM);
- /* No layer check, correct mirror is more important. */
- bPoseChannel *pchan = BKE_pose_channel_get_mirrored(ob->pose, pchan_orig->name);
- if (pchan == NULL) {
- continue;
- }
-
- /* Also do bbone scaling. */
- pchan->bone->xwidth = pchan_orig->bone->xwidth;
- pchan->bone->zwidth = pchan_orig->bone->zwidth;
-
- /* We assume X-axis flipping for now. */
- pchan->curve_in_x = pchan_orig->curve_in_x * -1;
- pchan->curve_out_x = pchan_orig->curve_out_x * -1;
- pchan->roll1 = pchan_orig->roll1 * -1; // XXX?
- pchan->roll2 = pchan_orig->roll2 * -1; // XXX?
-
- float pchan_mtx_final[4][4];
- BKE_pchan_to_mat4(pchan_orig, pchan_mtx_final);
- mul_m4_m4m4(pchan_mtx_final, pchan_mtx_final, flip_mtx);
- mul_m4_m4m4(pchan_mtx_final, flip_mtx, pchan_mtx_final);
- if (pid) {
- mul_m4_m4m4(pchan_mtx_final, pid->offset_mtx, pchan_mtx_final);
- }
- BKE_pchan_apply_mat4(pchan, pchan_mtx_final, false);
-
- /* In this case we can do target-less IK grabbing. */
- if (t->mode == TFM_TRANSLATION) {
- bKinematicConstraint *data = has_targetless_ik(pchan);
- if (data == NULL) {
- continue;
- }
- mul_v3_m4v3(data->grabtarget, flip_mtx, td->loc);
- if (pid) {
- /* TODO(germano): Realitve Mirror support */
- }
- data->flag |= CONSTRAINT_IK_AUTO;
- }
-
- if (pid) {
- pid++;
- }
- }
-}
-
/* helper for recalcData() - for object transforms, typically in the 3D view */
static void recalcData_objects(TransInfo *t)
{
@@ -1057,7 +996,7 @@ static void recalcData_objects(TransInfo *t)
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
bPose *pose = ob->pose;
if (arm->flag & ARM_MIRROR_EDIT || pose->flag & POSE_MIRROR_EDIT) {
- pose_transform_mirror_update(t, tc, ob, NULL);
+ pose_transform_mirror_update(t, tc, ob);
}
}
}
@@ -1071,11 +1010,7 @@ static void recalcData_objects(TransInfo *t)
if (pose->flag & POSE_MIRROR_EDIT) {
if (t->state != TRANS_CANCEL) {
- PoseInitData_Mirror *pid = NULL;
- if (pose->flag & POSE_MIRROR_RELATIVE) {
- pid = tc->custom.type.data;
- }
- pose_transform_mirror_update(t, tc, ob, pid);
+ pose_transform_mirror_update(t, tc, ob);
}
else {
restoreMirrorPoseBones(tc);
@@ -1168,7 +1103,7 @@ static void recalcData_objects(TransInfo *t)
if (motionpath_update) {
/* Update motion paths once for all transformed objects. */
- ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED);
+ ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME);
}
if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) {
@@ -1215,14 +1150,19 @@ static void recalcData_sequencer(TransInfo *t)
static void recalcData_gpencil_strokes(TransInfo *t)
{
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ GHash *strokes = BLI_ghash_ptr_new(__func__);
TransData *td = tc->data;
for (int i = 0; i < tc->data_len; i++, td++) {
bGPDstroke *gps = td->extra;
- if (gps != NULL) {
- gps->flag |= GP_STROKE_RECALC_GEOMETRY;
+
+ if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) {
+ BLI_ghash_insert(strokes, gps, gps);
+ /* Calc geometry data. */
+ BKE_gpencil_stroke_geometry_update(gps);
}
}
+ BLI_ghash_free(strokes, NULL, NULL);
}
static void recalcData_sculpt(TransInfo *t)
@@ -1247,7 +1187,6 @@ void recalcData(TransInfo *t)
flushTransPaintCurve(t);
}
else if (t->options & CTX_GPENCIL_STROKES) {
- /* set recalc triangle cache flag */
recalcData_gpencil_strokes(t);
}
else if (t->options & CTX_SCULPT) {
@@ -1282,7 +1221,7 @@ void recalcData(TransInfo *t)
void drawLine(TransInfo *t, const float center[3], const float dir[3], char axis, short options)
{
float v1[3], v2[3], v3[3];
- unsigned char col[3], col2[3];
+ uchar col[3], col2[3];
if (t->spacetype == SPACE_VIEW3D) {
View3D *v3d = t->view;
@@ -1434,8 +1373,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
Object *obact = OBACT(view_layer);
const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT;
ToolSettings *ts = CTX_data_tool_settings(C);
- ARegion *ar = CTX_wm_region(C);
- ScrArea *sa = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ ScrArea *area = CTX_wm_area(C);
bGPdata *gpd = CTX_data_gpencil_data(C);
PropertyRNA *prop;
@@ -1443,8 +1382,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->depsgraph = CTX_data_depsgraph_pointer(C);
t->scene = sce;
t->view_layer = view_layer;
- t->sa = sa;
- t->ar = ar;
+ t->area = area;
+ t->region = region;
t->settings = ts;
t->reports = op ? op->reports : NULL;
@@ -1468,20 +1407,16 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->redraw = TREDRAW_HARD; /* redraw first time */
+ int mval[2];
if (event) {
- t->mouse.imval[0] = event->mval[0];
- t->mouse.imval[1] = event->mval[1];
+ copy_v2_v2_int(mval, event->mval);
}
else {
- t->mouse.imval[0] = 0;
- t->mouse.imval[1] = 0;
+ zero_v2_int(mval);
}
-
- t->con.imval[0] = t->mouse.imval[0];
- t->con.imval[1] = t->mouse.imval[1];
-
- t->mval[0] = t->mouse.imval[0];
- t->mval[1] = t->mouse.imval[1];
+ copy_v2_v2_int(t->mval, mval);
+ copy_v2_v2_int(t->mouse.imval, mval);
+ copy_v2_v2_int(t->con.imval, mval);
t->transform = NULL;
t->handleEvent = NULL;
@@ -1495,11 +1430,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
unit_m3(t->mat);
- unit_m3(t->orient_matrix);
- negate_m3(t->orient_matrix);
- /* Leave 't->orient_matrix_is_set' to false,
- * so we overwrite it when we have a useful value. */
-
/* Default to rotate on the Z axis. */
t->orient_axis = 2;
t->orient_axis_ortho = 1;
@@ -1529,17 +1459,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
/* Assign the space type, some exceptions for running in different mode */
- if (sa == NULL) {
+ if (area == NULL) {
/* background mode */
t->spacetype = SPACE_EMPTY;
}
- else if ((ar == NULL) && (sa->spacetype == SPACE_VIEW3D)) {
+ else if ((region == NULL) && (area->spacetype == SPACE_VIEW3D)) {
/* running in the text editor */
t->spacetype = SPACE_EMPTY;
}
else {
/* normal operation */
- t->spacetype = sa->spacetype;
+ t->spacetype = area->spacetype;
}
/* handle T_ALT_TRANSFORM initialization, we may use for different operators */
@@ -1555,7 +1485,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
bScreen *animscreen = ED_screen_animation_playing(CTX_wm_manager(C));
t->view = v3d;
@@ -1577,22 +1507,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CURSOR;
}
- TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
- t->orientation.unset = V3D_ORIENT_GLOBAL;
- t->orientation.user = orient_slot->type;
- t->orientation.custom = BKE_scene_transform_orientation_find(t->scene,
- orient_slot->index_custom);
-
- t->orientation.index = 0;
- ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL);
-
- /* Make second orientation local if both are global. */
- if (t->orientation.user == V3D_ORIENT_GLOBAL) {
- t->orientation.user_alt = V3D_ORIENT_LOCAL;
- t->orientation.types[0] = &t->orientation.user_alt;
- SWAP(short *, t->orientation.types[0], t->orientation.types[1]);
- }
-
/* exceptional case */
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
@@ -1628,9 +1542,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
// XXX for now, get View2D from the active region
- t->view = &ar->v2d;
+ t->view = &region->v2d;
t->around = sima->around;
if (ED_space_image_show_uvedit(sima, OBACT(t->view_layer))) {
@@ -1649,17 +1563,17 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
else if (t->spacetype == SPACE_NODE) {
// XXX for now, get View2D from the active region
- t->view = &ar->v2d;
+ t->view = &region->v2d;
t->around = V3D_AROUND_CENTER_BOUNDS;
}
else if (t->spacetype == SPACE_GRAPH) {
- SpaceGraph *sipo = sa->spacedata.first;
- t->view = &ar->v2d;
+ SpaceGraph *sipo = area->spacedata.first;
+ t->view = &region->v2d;
t->around = sipo->around;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *sclip = sa->spacedata.first;
- t->view = &ar->v2d;
+ SpaceClip *sclip = area->spacedata.first;
+ t->view = &region->v2d;
t->around = sclip->around;
if (ED_space_clip_check_show_trackedit(sclip)) {
@@ -1670,9 +1584,9 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
}
}
else {
- if (ar) {
+ if (region) {
// XXX for now, get View2D from the active region
- t->view = &ar->v2d;
+ t->view = &region->v2d;
// XXX for now, the center point is the midpoint of the data
}
else {
@@ -1681,49 +1595,138 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->around = V3D_AROUND_CENTER_BOUNDS;
}
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
- t->orient_axis = RNA_property_enum_get(op->ptr, prop);
- }
- if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
- t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
- }
+ BLI_assert(is_zero_v4(t->values_modal_offset));
+ bool t_values_set_is_array = false;
+ if (op && (prop = RNA_struct_find_property(op->ptr, "value")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */
+ if (RNA_property_array_check(prop)) {
+ RNA_float_get_array(op->ptr, "value", values);
+ t_values_set_is_array = true;
+ }
+ else {
+ values[0] = RNA_float_get(op->ptr, "value");
+ }
- if (op &&
- ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
- RNA_property_is_set(op->ptr, prop)) &&
- ((t->flag & T_MODAL) ||
- /* When using redo, don't use the custom constraint matrix
- * if the user selects a different orientation. */
- (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) {
- RNA_property_float_get_array(op->ptr, prop, &t->spacemtx[0][0]);
- /* Some transform modes use this to operate on an axis. */
- t->orient_matrix_is_set = true;
- copy_m3_m3(t->orient_matrix, t->spacemtx);
- t->orient_matrix_is_set = true;
- t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX;
- t->orientation.custom = 0;
+ copy_v4_v4(t->values, values);
if (t->flag & T_MODAL) {
- RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type"));
+ /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */
+ copy_v4_v4(t->values_modal_offset, values);
+ }
+ else {
+ copy_v4_v4(t->values, values);
+ t->flag |= T_INPUT_IS_VALUES_FINAL;
+ }
+ }
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
+ bool constraint_axis[3] = {false, false, false};
+ if (RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
+ }
+
+ if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) {
+ /* For operators whose `t->values` is array, set contrain so that the
+ * orientation is more intuitive in the Redo Panel. */
+ for (int i = 3; i--;) {
+ constraint_axis[i] |= t->values[i] != 0.0f;
+ }
+ }
+
+ if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
+ t->con.mode |= CON_APPLY;
+
+ if (constraint_axis[0]) {
+ t->con.mode |= CON_AXIS0;
+ }
+ if (constraint_axis[1]) {
+ t->con.mode |= CON_AXIS1;
+ }
+ if (constraint_axis[2]) {
+ t->con.mode |= CON_AXIS2;
+ }
}
}
- else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
- RNA_property_is_set(op->ptr, prop))) {
- short orientation = RNA_property_enum_get(op->ptr, prop);
+
+ {
+ TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT];
TransformOrientation *custom_orientation = NULL;
+ short orient_type_set = -1;
+ short orient_type_matrix_set = -1;
+ short orient_type_scene = orient_slot->type;
+ if (orient_type_scene == V3D_ORIENT_CUSTOM) {
+ const int index_custom = orient_slot->index_custom;
+ custom_orientation = BKE_scene_transform_orientation_find(t->scene, index_custom);
+ orient_type_scene += index_custom;
+ }
+
+ short orient_type_default = V3D_ORIENT_GLOBAL;
+ short orient_type_constraint[2];
+
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) {
+ t->orient_axis = RNA_property_enum_get(op->ptr, prop);
- if (orientation >= V3D_ORIENT_CUSTOM) {
- if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
- orientation = V3D_ORIENT_GLOBAL;
+ /* For transfor modes that require "orient_axis" use
+ * `V3D_ORIENT_VIEW` as default. */
+ orient_type_default = V3D_ORIENT_VIEW;
+ }
+ if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) {
+ t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop);
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ orient_type_set = RNA_property_enum_get(op->ptr, prop);
+ if (orient_type_set >= V3D_ORIENT_CUSTOM) {
+ if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) {
+ orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+ else {
+ custom_orientation = BKE_scene_transform_orientation_find(
+ t->scene, orient_type_default - V3D_ORIENT_CUSTOM);
+ }
+ }
+
+ /* Change the default orientation to be used when redoing. */
+ orient_type_default = orient_type_set;
+ orient_type_constraint[0] = orient_type_set;
+ orient_type_constraint[1] = orient_type_scene;
+ }
+ else {
+ orient_type_constraint[0] = orient_type_scene;
+ orient_type_constraint[1] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL :
+ V3D_ORIENT_LOCAL;
+ }
+
+ if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) &&
+ RNA_property_is_set(op->ptr, prop))) {
+ RNA_property_float_get_array(op->ptr, prop, &t->orientation.custom_matrix[0][0]);
+
+ if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop);
+ }
+ else if (orient_type_set != -1) {
+ orient_type_matrix_set = orient_type_set;
}
else {
- custom_orientation = BKE_scene_transform_orientation_find(t->scene,
- orientation - V3D_ORIENT_CUSTOM);
- orientation = V3D_ORIENT_CUSTOM;
+ orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL;
+ }
+
+ if (orient_type_matrix_set == orient_type_set) {
+ /* Constraints are forced to use the custom matrix when redoing. */
+ orient_type_default = V3D_ORIENT_CUSTOM_MATRIX;
}
}
- t->orientation.user = orientation;
+ t->orientation.types[0] = orient_type_default;
+ t->orientation.types[1] = orient_type_constraint[0];
+ t->orientation.types[2] = orient_type_constraint[1];
t->orientation.custom = custom_orientation;
+
+ if (t->con.mode & CON_APPLY) {
+ t->orientation.index = 1;
+ }
}
if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) &&
@@ -1828,6 +1831,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->options |= CTX_NO_PET;
}
+ if (t->obedit_type == OB_MESH) {
+ if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) &&
+ RNA_property_is_set(op->ptr, prop)) {
+ if (RNA_property_boolean_get(op->ptr, prop)) {
+ t->flag |= T_AUTOMERGE | T_AUTOSPLIT;
+ }
+ }
+ else {
+ char automerge = t->scene->toolsettings->automerge;
+ if (automerge & AUTO_MERGE) {
+ t->flag |= T_AUTOMERGE;
+ if (automerge & AUTO_MERGE_AND_SPLIT) {
+ t->flag |= T_AUTOSPLIT;
+ }
+ }
+ }
+ }
+
// Mirror is not supported with PET, turn it off.
#if 0
if (t->flag & T_PROP_EDIT) {
@@ -1889,13 +1910,13 @@ void freeTransCustomDataForMode(TransInfo *t)
void postTrans(bContext *C, TransInfo *t)
{
if (t->draw_handle_view) {
- ED_region_draw_cb_exit(t->ar->type, t->draw_handle_view);
+ ED_region_draw_cb_exit(t->region->type, t->draw_handle_view);
}
if (t->draw_handle_apply) {
- ED_region_draw_cb_exit(t->ar->type, t->draw_handle_apply);
+ ED_region_draw_cb_exit(t->region->type, t->draw_handle_apply);
}
if (t->draw_handle_pixel) {
- ED_region_draw_cb_exit(t->ar->type, t->draw_handle_pixel);
+ ED_region_draw_cb_exit(t->region->type, t->draw_handle_pixel);
}
if (t->draw_handle_cursor) {
WM_paint_cursor_end(CTX_wm_manager(C), t->draw_handle_cursor);
@@ -1941,14 +1962,14 @@ void postTrans(bContext *C, TransInfo *t)
/* pass */
}
else {
- SpaceImage *sima = t->sa->spacedata.first;
+ SpaceImage *sima = t->area->spacedata.first;
if (sima->flag & SI_LIVE_UNWRAP) {
ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
}
}
}
else if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = t->sa->spacedata.first;
+ View3D *v3d = t->area->spacedata.first;
/* restore gizmo */
if (t->flag & T_MODAL) {
v3d->gizmo_flag = t->gizmo_flag;
@@ -2074,10 +2095,10 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
/* If edit or pose mode, move cursor in local space */
if (t->options & CTX_PAINT_CURVE) {
- if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) !=
+ if (ED_view3d_project_float_global(t->region, cursor, r_center, V3D_PROJ_TEST_NOP) !=
V3D_PROJ_RET_OK) {
- r_center[0] = t->ar->winx / 2.0f;
- r_center[1] = t->ar->winy / 2.0f;
+ r_center[0] = t->region->winx / 2.0f;
+ r_center[1] = t->region->winy / 2.0f;
}
r_center[2] = 0.0f;
}
@@ -2088,11 +2109,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
const float *cursor = NULL;
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
cursor = sima->cursor;
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
cursor = space_clip->cursor;
}
@@ -2101,11 +2122,11 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
float co[2];
if (t->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
+ SpaceImage *sima = (SpaceImage *)t->area->spacedata.first;
BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
}
else if (t->spacetype == SPACE_CLIP) {
- SpaceClip *space_clip = (SpaceClip *)t->sa->spacedata.first;
+ SpaceClip *space_clip = (SpaceClip *)t->area->spacedata.first;
BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
}
else {
@@ -2117,8 +2138,8 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
}
else if (t->options & CTX_PAINT_CURVE) {
if (t->spacetype == SPACE_IMAGE) {
- r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]);
- r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]);
+ r_center[0] = UI_view2d_view_to_region_x(&t->region->v2d, cursor[0]);
+ r_center[1] = UI_view2d_view_to_region_y(&t->region->v2d, cursor[1]);
}
}
else {
@@ -2130,7 +2151,7 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
void calculateCenterCursorGraph2D(TransInfo *t, float r_center[2])
{
- SpaceGraph *sipo = (SpaceGraph *)t->sa->spacedata.first;
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
Scene *scene = t->scene;
/* cursor is combination of current frame, and graph-editor cursor value */
@@ -2300,7 +2321,7 @@ void calculateCenter(TransInfo *t)
/* for panning from cameraview */
if ((t->flag & T_OBJECT) && (t->flag & T_OVERRIDE_CENTER) == 0) {
- if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
+ if (t->spacetype == SPACE_VIEW3D && t->region && t->region->regiontype == RGN_TYPE_WINDOW) {
if (t->flag & T_CAMERA) {
float axis[3];
@@ -2333,8 +2354,8 @@ void calculateCenter(TransInfo *t)
* We need special case here as well, since ED_view3d_calc_zfac will crash when called
* for a region different from RGN_TYPE_WINDOW.
*/
- if (t->ar->regiontype == RGN_TYPE_WINDOW) {
- t->zfac = ED_view3d_calc_zfac(t->ar->regiondata, t->center_global, NULL);
+ if (t->region->regiontype == RGN_TYPE_WINDOW) {
+ t->zfac = ED_view3d_calc_zfac(t->region->regiondata, t->center_global, NULL);
}
else {
t->zfac = 0.0f;
diff --git a/source/blender/editors/transform/transform_gizmo_2d.c b/source/blender/editors/transform/transform_gizmo_2d.c
index 793552865a6..50317d8b395 100644
--- a/source/blender/editors/transform/transform_gizmo_2d.c
+++ b/source/blender/editors/transform/transform_gizmo_2d.c
@@ -42,15 +42,15 @@
#include "UI_view2d.h"
#include "WM_api.h"
+#include "WM_message.h"
#include "WM_types.h"
#include "wm.h" /* XXX */
-#include "WM_message.h"
+#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "ED_image.h"
#include "ED_screen.h"
#include "ED_uvedit.h"
-#include "ED_gizmo_library.h"
#include "transform.h" /* own include */
@@ -68,10 +68,10 @@ static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- switch (sa->spacetype) {
+ ScrArea *area = CTX_wm_area(C);
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
if (!ED_space_image_show_uvedit(sima, obedit)) {
return false;
@@ -86,18 +86,18 @@ static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
/* Additional args. */
bScreen *screen,
- ScrArea *sa,
- ARegion *ar)
+ ScrArea *area,
+ ARegion *region)
{
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
- .owner = ar,
+ .owner = region,
.user_data = gzgroup->parent_gzmap,
.notify = WM_gizmo_do_msg_notify_tag_refresh,
};
- switch (sa->spacetype) {
+ switch (area->spacetype) {
case SPACE_IMAGE: {
- SpaceImage *sima = sa->spacedata.first;
+ SpaceImage *sima = area->spacedata.first;
PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr);
{
@@ -214,10 +214,10 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
r_max = max_buf;
}
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool changed = false;
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Image *ima = ED_space_image(sima);
@@ -241,11 +241,11 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
{
- ScrArea *sa = CTX_wm_area(C);
+ ScrArea *area = CTX_wm_area(C);
bool has_select = false;
zero_v2(r_center);
- if (sa->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
+ if (area->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = area->spacedata.first;
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
@@ -256,9 +256,9 @@ static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
/**
* Convert origin (or any other point) from view to region space.
*/
-BLI_INLINE void gizmo2d_origin_to_region(ARegion *ar, float *r_origin)
+BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
{
- UI_view2d_view_to_region_fl(&ar->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
+ UI_view2d_view_to_region_fl(&region->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
}
/**
@@ -269,14 +269,14 @@ static int gizmo2d_modal(bContext *C,
const wmEvent *UNUSED(event),
eWM_GizmoFlagTweak UNUSED(tweak_flag))
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
float origin[3];
gizmo2d_calc_center(C, origin);
- gizmo2d_origin_to_region(ar, origin);
+ gizmo2d_origin_to_region(region, origin);
WM_gizmo_set_matrix_location(widget, origin);
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_editor_overlays(region);
return OPERATOR_RUNNING_MODAL;
}
@@ -300,7 +300,7 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
/* set up widget data */
RNA_float_set(gz->ptr, "length", 0.8f);
float axis[3] = {0.0f};
- axis[(i + 1) % 2] = 1.0f;
+ axis[i] = 1.0f;
WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
float offset[3] = {0, 0, 0};
@@ -315,6 +315,11 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
WM_gizmo_set_scale(gz, 1.0f);
}
else {
+ float color[4], color_hi[4];
+ UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
+ copy_v4_v4(color_hi, color);
+ color[3] *= 0.6f;
+
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
@@ -322,7 +327,8 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
- WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
WM_gizmo_set_scale(gz, 0.2f);
}
@@ -330,8 +336,8 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
/* Assign operator. */
PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, NULL);
if (i < 2) {
- bool constraint[3] = {0};
- constraint[(i + 1) % 2] = 1;
+ bool constraint[3] = {false};
+ constraint[i] = true;
if (RNA_struct_find_property(ptr, "constraint_axis")) {
RNA_boolean_set_array(ptr, "constraint_axis", constraint);
}
@@ -480,19 +486,19 @@ static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
GizmoGroup2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
- gizmo2d_origin_to_region(ar, origin);
+ gizmo2d_origin_to_region(region, origin);
for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
wmGizmo *gz = ggd->translate_xy[i];
WM_gizmo_set_matrix_location(gz, origin);
}
- UI_view2d_view_to_region_m4(&ar->v2d, ggd->cage->matrix_space);
+ UI_view2d_view_to_region_m4(&region->v2d, ggd->cage->matrix_space);
WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]);
ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
@@ -503,9 +509,9 @@ static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
@@ -575,7 +581,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
GizmoGroup_Resize2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
@@ -589,7 +595,7 @@ static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup
}
}
- gizmo2d_origin_to_region(ar, origin);
+ gizmo2d_origin_to_region(region, origin);
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
wmGizmo *gz = ggd->gizmo_xy[i];
@@ -629,6 +635,11 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
WM_gizmo_set_scale(gz, 1.0f);
}
else {
+ float color[4], color_hi[4];
+ UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
+ copy_v4_v4(color_hi, color);
+ color[3] *= 0.6f;
+
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
@@ -636,7 +647,8 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
- WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color_hi);
WM_gizmo_set_scale(gz, 1.2f);
}
@@ -659,9 +671,9 @@ static void gizmo2d_resize_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
@@ -718,7 +730,7 @@ static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
float origin[3] = {UNPACK2(ggd->origin), 0.0f};
@@ -732,7 +744,7 @@ static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup
}
}
- gizmo2d_origin_to_region(ar, origin);
+ gizmo2d_origin_to_region(region, origin);
wmGizmo *gz = ggd->gizmo;
WM_gizmo_set_matrix_location(gz, origin);
@@ -754,6 +766,9 @@ static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
WM_gizmo_set_scale(gz, 1.2f);
{
+ float color[4];
+ UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
+
PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
@@ -761,7 +776,8 @@ static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
/* Make the center low alpha. */
WM_gizmo_set_line_width(gz, 2.0f);
RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
- WM_gizmo_set_color(gz, (const float[4]){1, 1, 1, 0.6});
+ WM_gizmo_set_color(gz, color);
+ WM_gizmo_set_color_highlight(gz, color);
}
/* Assign operator. */
@@ -775,9 +791,9 @@ static void gizmo2d_rotate_message_subscribe(const struct bContext *C,
struct wmMsgBus *mbus)
{
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, sa, ar);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
}
void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index b3c1fbd3aad..b575030778f 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -22,58 +22,58 @@
* Used for 3D View
*/
+#include <float.h>
+#include <math.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
-#include <float.h>
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_lattice_types.h"
#include "DNA_meta_types.h"
-#include "DNA_screen_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
#include "BLI_array_utils.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
-#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BLI_utildefines.h"
#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
+#include "BKE_gpencil.h"
+#include "BKE_lattice.h"
#include "BKE_layer.h"
+#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
-#include "BKE_editmesh.h"
-#include "BKE_lattice.h"
-#include "BKE_gpencil.h"
#include "BKE_scene.h"
#include "BKE_workspace.h"
-#include "BKE_object.h"
-#include "BKE_paint.h"
#include "DEG_depsgraph.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
+#include "WM_types.h"
#include "wm.h"
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
+#include "ED_gpencil.h"
#include "ED_object.h"
#include "ED_particle.h"
-#include "ED_view3d.h"
-#include "ED_gpencil.h"
#include "ED_screen.h"
-#include "ED_gizmo_library.h"
-#include "ED_gizmo_utils.h"
+#include "ED_view3d.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -347,7 +347,7 @@ static void gizmo_get_axis_color(const int axis_idx,
if (axis_idx >= MAN_AXIS_RANGE_ROT_START && axis_idx < MAN_AXIS_RANGE_ROT_END) {
/* Never fade rotation rings. */
/* trackball rotation axis is a special case, we only draw a slight overlay */
- alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.1f : 1.0f;
+ alpha_fac = (axis_idx == MAN_AXIS_ROT_T) ? 0.05f : 1.0f;
}
else {
bool is_plane = false;
@@ -397,7 +397,7 @@ static void gizmo_get_axis_color(const int axis_idx,
case MAN_AXIS_ROT_C:
case MAN_AXIS_SCALE_C:
case MAN_AXIS_ROT_T:
- copy_v4_fl(r_col, 1.0f);
+ UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, r_col);
break;
}
@@ -637,11 +637,11 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3])
{
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *obedit = CTX_data_edit_object(C);
- RegionView3D *rv3d = ar->regiondata;
+ RegionView3D *rv3d = region->regiondata;
Object *ob = OBACT(view_layer);
const short orientation_type = scene->orientation_slots[SCE_ORIENT_DEFAULT].type;
const short orientation_index_custom = scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom;
@@ -713,7 +713,9 @@ void ED_transform_calc_orientation_from_type_ex(const bContext *C,
ok = true;
break;
}
- case V3D_ORIENT_CUSTOM: {
+ case V3D_ORIENT_CUSTOM:
+ default: {
+ BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM);
TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find(
scene, orientation_index_custom);
if (applyTransformOrientation(custom_orientation, r_mat, NULL)) {
@@ -734,16 +736,16 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds)
{
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
/* TODO(sergey): This function is used from operator's modal() and from gizmo's refresh().
* Is it fine to possibly evaluate dependency graph here? */
Depsgraph *depsgraph = CTX_data_expect_evaluated_depsgraph(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
- View3D *v3d = sa->spacedata.first;
+ View3D *v3d = area->spacedata.first;
Object *obedit = CTX_data_edit_object(C);
- RegionView3D *rv3d = ar->regiondata;
+ RegionView3D *rv3d = region->regiondata;
Base *base;
Object *ob = OBACT(view_layer);
bGPdata *gpd = CTX_data_gpencil_data(C);
@@ -792,15 +794,15 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (is_gp_edit) {
float diff_mat[4][4];
const bool use_mat_local = true;
- for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
/* only editable and visible layers are considered */
- if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
/* calculate difference matrix */
- ED_gpencil_parent_location(depsgraph, ob, gpd, gpl, diff_mat);
+ BKE_gpencil_parent_matrix_get(depsgraph, ob, gpl, diff_mat);
- for (bGPDstroke *gps = gpl->actframe->strokes.first; gps; gps = gps->next) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpl->actframe->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
@@ -883,7 +885,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
if (use_mat_local) {
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (EditBone *ebo = arm->edbo->first; ebo; ebo = ebo->next) {
+ LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) {
if (EBONE_VISIBLE(arm, ebo)) {
if (ebo->flag & BONE_TIPSEL) {
calc_tw_center_with_matrix(tbounds, ebo->tail, use_mat_local, mat_local);
@@ -977,7 +979,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
mul_m4_m4m4(mat_local, obedit->imat, ob_iter->obmat);
}
- for (MetaElem *ml = mb->editelems->first; ml; ml = ml->next) {
+ LISTBASE_FOREACH (MetaElem *, ml, mb->editelems) {
if (ml->flag & SELECT) {
calc_tw_center_with_matrix(tbounds, &ml->x, use_mat_local, mat_local);
totsel++;
@@ -1033,7 +1035,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C,
/* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */
const int mode = TFM_ROTATION;
- const int totsel_iter = count_set_pose_transflags(
+ const int totsel_iter = transform_convert_pose_transflags_update(
ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL);
if (totsel_iter) {
@@ -1244,13 +1246,13 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
struct wmMsgBus *mbus,
Scene *scene,
bScreen *screen,
- ScrArea *sa,
- ARegion *ar,
+ ScrArea *area,
+ ARegion *region,
const void *type_fn)
{
/* Subscribe to view properties */
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
- .owner = ar,
+ .owner = region,
.user_data = gzgroup->parent_gzmap,
.notify = WM_gizmo_do_msg_notify_tag_refresh,
};
@@ -1334,7 +1336,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
}
PointerRNA view3d_ptr;
- RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &view3d_ptr);
+ RNA_pointer_create(&screen->id, &RNA_SpaceView3D, area->spacedata.first, &view3d_ptr);
if (type_fn == VIEW3D_GGT_xform_gizmo) {
GizmoGroup *ggd = gzgroup->customdata;
@@ -1369,7 +1371,7 @@ static void gizmo_xform_message_subscribe(wmGizmoGroup *gzgroup,
void drawDial3d(const TransInfo *t)
{
if (t->mode == TFM_ROTATION && t->spacetype == SPACE_VIEW3D) {
- wmGizmo *gz = wm_gizmomap_modal_get(t->ar->gizmo_map);
+ wmGizmo *gz = wm_gizmomap_modal_get(t->region->gizmo_map);
if (gz == NULL) {
/* We only draw Dial3d if the operator has been called by a gizmo. */
return;
@@ -1402,7 +1404,7 @@ void drawDial3d(const TransInfo *t)
}
else {
axis_idx = MAN_AXIS_ROT_C;
- negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]);
+ negate_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]);
scale *= 1.2f;
line_with -= 1.0f;
}
@@ -1411,7 +1413,7 @@ void drawDial3d(const TransInfo *t)
mat_basis[2][3] = -dot_v3v3(mat_basis[2], mat_basis[3]);
if (ED_view3d_win_to_3d_on_plane(
- t->ar, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) {
+ t->region, mat_basis[2], (float[2]){UNPACK2(t->mouse.imval)}, false, mat_basis[1])) {
sub_v3_v3(mat_basis[1], mat_basis[3]);
normalize_v3(mat_basis[1]);
cross_v3_v3v3(mat_basis[0], mat_basis[1], mat_basis[2]);
@@ -1428,7 +1430,7 @@ void drawDial3d(const TransInfo *t)
mat_basis[3][3] = 1.0f;
copy_m4_m4(mat_final, mat_basis);
- scale *= ED_view3d_pixel_size_no_ui_scale(t->ar->regiondata, mat_final[3]);
+ scale *= ED_view3d_pixel_size_no_ui_scale(t->region->regiondata, mat_final[3]);
mul_mat3_m4_fl(mat_final, scale);
if (activeSnap(t) && (!transformModeUseSnap(t) ||
@@ -1554,8 +1556,8 @@ static int gizmo_modal(bContext *C,
return OPERATOR_RUNNING_MODAL;
}
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
struct TransformBounds tbounds;
if (ED_transform_calc_gizmo_stats(C,
@@ -1567,7 +1569,7 @@ static int gizmo_modal(bContext *C,
WM_gizmo_set_matrix_location(widget, rv3d->twmat[3]);
}
- ED_region_tag_redraw(ar);
+ ED_region_tag_redraw_editor_overlays(region);
return OPERATOR_RUNNING_MODAL;
}
@@ -1701,8 +1703,8 @@ static void WIDGETGROUP_gizmo_setup(const bContext *C, wmGizmoGroup *gzgroup)
gzgroup->customdata = ggd;
{
- ScrArea *sa = CTX_wm_area(C);
- const bToolRef *tref = sa->runtime.tool;
+ ScrArea *area = CTX_wm_area(C);
+ const bToolRef *tref = area->runtime.tool;
ggd->twtype = 0;
if (tref && STREQ(tref->idname, "builtin.move")) {
@@ -1737,10 +1739,10 @@ static void WIDGETGROUP_gizmo_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
Scene *scene = CTX_data_scene(C);
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
struct TransformBounds tbounds;
if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
@@ -1844,25 +1846,26 @@ static void WIDGETGROUP_gizmo_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_gizmo);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_gizmo);
}
static void WIDGETGROUP_gizmo_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
{
GizmoGroup *ggd = gzgroup->customdata;
- // ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- // View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
+ // ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ // View3D *v3d = area->spacedata.first;
+ RegionView3D *rv3d = region->regiondata;
float viewinv_m3[3][3];
copy_m3_m4(viewinv_m3, rv3d->viewinv);
float idot[3];
/* when looking through a selected camera, the gizmo can be at the
* exact same position as the view, skip so we don't break selection */
- if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 1e-6f) {
+ if (ggd->all_hidden || fabsf(ED_view3d_pixel_size(rv3d, rv3d->twmat[3])) < 5e-7f) {
MAN_ITER_AXES_BEGIN (axis, axis_idx) {
WM_gizmo_set_flag(axis, WM_GIZMO_HIDDEN, true);
}
@@ -1997,13 +2000,13 @@ static bool WIDGETGROUP_gizmo_poll_generic(View3D *v3d)
static bool WIDGETGROUP_gizmo_poll_context(const struct bContext *C,
struct wmGizmoGroupType *UNUSED(gzgt))
{
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
- const bToolRef *tref = sa->runtime.tool;
+ const bToolRef *tref = area->runtime.tool;
if (v3d->gizmo_flag & V3D_GIZMO_HIDE_CONTEXT) {
return false;
}
@@ -2025,8 +2028,8 @@ static bool WIDGETGROUP_gizmo_poll_tool(const struct bContext *C, struct wmGizmo
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- View3D *v3d = sa->spacedata.first;
+ ScrArea *area = CTX_wm_area(C);
+ View3D *v3d = area->spacedata.first;
if (!WIDGETGROUP_gizmo_poll_generic(v3d)) {
return false;
}
@@ -2168,8 +2171,8 @@ static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmGizmoGroup
static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
Scene *scene = CTX_data_scene(C);
struct XFormCageWidgetGroup *xgzgroup = gzgroup->customdata;
@@ -2247,9 +2250,9 @@ static void WIDGETGROUP_xform_cage_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_cage);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_cage);
}
static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
@@ -2384,8 +2387,8 @@ static void WIDGETGROUP_xform_shear_setup(const bContext *UNUSED(C), wmGizmoGrou
static void WIDGETGROUP_xform_shear_refresh(const bContext *C, wmGizmoGroup *gzgroup)
{
Scene *scene = CTX_data_scene(C);
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = ar->regiondata;
+ ARegion *region = CTX_wm_region(C);
+ RegionView3D *rv3d = region->regiondata;
struct XFormShearWidgetGroup *xgzgroup = gzgroup->customdata;
struct TransformBounds tbounds;
@@ -2460,9 +2463,10 @@ static void WIDGETGROUP_xform_shear_message_subscribe(const bContext *C,
{
Scene *scene = CTX_data_scene(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa = CTX_wm_area(C);
- ARegion *ar = CTX_wm_region(C);
- gizmo_xform_message_subscribe(gzgroup, mbus, scene, screen, sa, ar, VIEW3D_GGT_xform_shear);
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ gizmo_xform_message_subscribe(
+ gzgroup, mbus, scene, screen, area, region, VIEW3D_GGT_xform_shear);
}
static void WIDGETGROUP_xform_shear_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
index fb33471cf3f..e6e74668c2c 100644
--- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c
@@ -18,10 +18,10 @@
* \ingroup edmesh
*/
-#include "BLI_utildefines.h"
#include "BLI_array_utils.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -30,15 +30,15 @@
#include "RNA_define.h"
#include "WM_api.h"
-#include "WM_types.h"
#include "WM_message.h"
#include "WM_toolsystem.h"
+#include "WM_types.h"
+#include "ED_gizmo_library.h"
+#include "ED_gizmo_utils.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_view3d.h"
-#include "ED_gizmo_library.h"
-#include "ED_gizmo_utils.h"
#include "UI_resources.h"
@@ -469,11 +469,11 @@ static void gizmo_mesh_extrude_message_subscribe(const bContext *C,
struct wmMsgBus *mbus)
{
GizmoExtrudeGroup *ggd = gzgroup->customdata;
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
/* Subscribe to view properties */
wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
- .owner = ar,
+ .owner = region,
.user_data = gzgroup->parent_gzmap,
.notify = WM_gizmo_do_msg_notify_tag_refresh,
};
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 8dc403c45d2..078020e932e 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -18,8 +18,8 @@
* \ingroup edtransform
*/
-#include <stdlib.h>
#include <math.h>
+#include <stdlib.h>
#include "DNA_screen_types.h"
@@ -28,20 +28,24 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "WM_types.h"
#include "WM_api.h"
+#include "WM_types.h"
#include "transform.h"
#include "MEM_guardedalloc.h"
-/* ************************** INPUT FROM MOUSE *************************** */
+/* -------------------------------------------------------------------- */
+/** \name Callbacks for #MouseInput.apply
+ * \{ */
+/** Callback for #INPUT_VECTOR */
static void InputVector(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
convertViewVec(t, output, mval[0] - mi->imval[0], mval[1] - mi->imval[1]);
}
+/** Callback for #INPUT_SPRING */
static void InputSpring(TransInfo *UNUSED(t),
MouseInput *mi,
const double mval[2],
@@ -57,6 +61,7 @@ static void InputSpring(TransInfo *UNUSED(t),
output[0] = ratio;
}
+/** Callback for #INPUT_SPRING_FLIP */
static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputSpring(t, mi, mval, output);
@@ -70,12 +75,14 @@ static void InputSpringFlip(TransInfo *t, MouseInput *mi, const double mval[2],
}
}
+/** Callback for #INPUT_SPRING_DELTA */
static void InputSpringDelta(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputSpring(t, mi, mval, output);
output[0] -= 1.0f;
}
+/** Callback for #INPUT_TRACKBALL */
static void InputTrackBall(TransInfo *UNUSED(t),
MouseInput *mi,
const double mval[2],
@@ -88,16 +95,18 @@ static void InputTrackBall(TransInfo *UNUSED(t),
output[1] *= mi->factor;
}
+/** Callback for #INPUT_HORIZONTAL_RATIO */
static void InputHorizontalRatio(TransInfo *t,
MouseInput *mi,
const double mval[2],
float output[3])
{
- const int winx = t->ar ? t->ar->winx : 1;
+ const int winx = t->region ? t->region->winx : 1;
output[0] = ((mval[0] - mi->imval[0]) / winx) * 2.0f;
}
+/** Callback for #INPUT_HORIZONTAL_ABSOLUTE */
static void InputHorizontalAbsolute(TransInfo *t,
MouseInput *mi,
const double mval[2],
@@ -113,12 +122,13 @@ static void InputHorizontalAbsolute(TransInfo *t,
static void InputVerticalRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
- const int winy = t->ar ? t->ar->winy : 1;
+ const int winy = t->region ? t->region->winy : 1;
/* Flip so dragging up increases (matching viewport zoom). */
output[0] = ((mval[1] - mi->imval[1]) / winy) * -2.0f;
}
+/** Callback for #INPUT_VERTICAL_ABSOLUTE */
static void InputVerticalAbsolute(TransInfo *t,
MouseInput *mi,
const double mval[2],
@@ -133,38 +143,7 @@ static void InputVerticalAbsolute(TransInfo *t,
output[0] = dot_v3v3(t->viewinv[1], vec) * -2.0f;
}
-void setCustomPoints(TransInfo *UNUSED(t),
- MouseInput *mi,
- const int mval_start[2],
- const int mval_end[2])
-{
- int *data;
-
- mi->data = MEM_reallocN(mi->data, sizeof(int) * 4);
-
- data = mi->data;
-
- data[0] = mval_start[0];
- data[1] = mval_start[1];
- data[2] = mval_end[0];
- data[3] = mval_end[1];
-}
-
-void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2])
-{
- BLI_ASSERT_UNIT_V2(dir);
- const int win_axis = t->ar ?
- ((abs((int)(t->ar->winx * dir[0])) + abs((int)(t->ar->winy * dir[1]))) /
- 2) :
- 1;
- const int mval_start[2] = {
- mi->imval[0] + dir[0] * win_axis,
- mi->imval[1] + dir[1] * win_axis,
- };
- const int mval_end[2] = {mi->imval[0], mi->imval[1]};
- setCustomPoints(t, mi, mval_start, mval_end);
-}
-
+/** Callback for #INPUT_CUSTOM_RATIO_FLIP */
static void InputCustomRatioFlip(TransInfo *UNUSED(t),
MouseInput *mi,
const double mval[2],
@@ -191,6 +170,7 @@ static void InputCustomRatioFlip(TransInfo *UNUSED(t),
}
}
+/** Callback for #INPUT_CUSTOM_RATIO */
static void InputCustomRatio(TransInfo *t, MouseInput *mi, const double mval[2], float output[3])
{
InputCustomRatioFlip(t, mi, mval, output);
@@ -202,6 +182,7 @@ struct InputAngle_Data {
double mval_prev[2];
};
+/** Callback for #INPUT_ANGLE */
static void InputAngle(TransInfo *UNUSED(t), MouseInput *mi, const double mval[2], float output[3])
{
struct InputAngle_Data *data = mi->data;
@@ -270,6 +251,53 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2],
output[1] = toutput[0];
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Custom 2D Start/End Coordinate API
+ *
+ * - #INPUT_CUSTOM_RATIO
+ * - #INPUT_CUSTOM_RATIO_FLIP
+ * \{ */
+
+void setCustomPoints(TransInfo *UNUSED(t),
+ MouseInput *mi,
+ const int mval_start[2],
+ const int mval_end[2])
+{
+ int *data;
+
+ mi->data = MEM_reallocN(mi->data, sizeof(int) * 4);
+
+ data = mi->data;
+
+ data[0] = mval_start[0];
+ data[1] = mval_start[1];
+ data[2] = mval_end[0];
+ data[3] = mval_end[1];
+}
+
+void setCustomPointsFromDirection(TransInfo *t, MouseInput *mi, const float dir[2])
+{
+ BLI_ASSERT_UNIT_V2(dir);
+ const int win_axis = t->region ? ((abs((int)(t->region->winx * dir[0])) +
+ abs((int)(t->region->winy * dir[1]))) /
+ 2) :
+ 1;
+ const int mval_start[2] = {
+ mi->imval[0] + dir[0] * win_axis,
+ mi->imval[1] + dir[1] * win_axis,
+ };
+ const int mval_end[2] = {mi->imval[0], mi->imval[1]};
+ setCustomPoints(t, mi, mval_start, mval_end);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Setup & Handle Mouse Input
+ * \{ */
+
void initMouseInput(TransInfo *UNUSED(t),
MouseInput *mi,
const float center[2],
@@ -476,8 +504,8 @@ eRedrawFlag handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event)
eRedrawFlag redraw = TREDRAW_NOTHING;
switch (event->type) {
- case LEFTSHIFTKEY:
- case RIGHTSHIFTKEY:
+ case EVT_LEFTSHIFTKEY:
+ case EVT_RIGHTSHIFTKEY:
if (event->val == KM_PRESS) {
t->modifiers |= MOD_PRECISION;
/* shift is modifier for higher precision transforn */
@@ -494,3 +522,5 @@ eRedrawFlag handleMouseInput(TransInfo *t, MouseInput *mi, const wmEvent *event)
return redraw;
}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c
new file mode 100644
index 00000000000..4c14c3aebd7
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode.c
@@ -0,0 +1,1264 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_constraint.h"
+#include "BKE_context.h"
+#include "BKE_nla.h"
+
+#include "RNA_access.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_snap.h"
+
+/* Own include. */
+#include "transform_mode.h"
+
+bool transdata_check_local_center(TransInfo *t, short around)
+{
+ return ((around == V3D_AROUND_LOCAL_ORIGINS) &&
+ ((t->flag & (T_OBJECT | T_POSE)) ||
+ /* implicit: (t->flag & T_EDIT) */
+ (ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) ||
+ (t->spacetype == SPACE_GRAPH) ||
+ (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Locks
+ * \{ */
+
+void protectedTransBits(short protectflag, float vec[3])
+{
+ 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;
+ }
+}
+
+/* this function only does the delta rotation */
+static void protectedQuaternionBits(short protectflag, float quat[4], const float oldquat[4])
+{
+ /* check that protection flags are set */
+ if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
+ return;
+ }
+
+ if (protectflag & OB_LOCK_ROT4D) {
+ /* quaternions getting limited as 4D entities that they are... */
+ if (protectflag & OB_LOCK_ROTW) {
+ quat[0] = oldquat[0];
+ }
+ if (protectflag & OB_LOCK_ROTX) {
+ quat[1] = oldquat[1];
+ }
+ if (protectflag & OB_LOCK_ROTY) {
+ quat[2] = oldquat[2];
+ }
+ if (protectflag & OB_LOCK_ROTZ) {
+ quat[3] = oldquat[3];
+ }
+ }
+ else {
+ /* quaternions get limited with euler... (compatibility mode) */
+ float eul[3], oldeul[3], nquat[4], noldquat[4];
+ float qlen;
+
+ qlen = normalize_qt_qt(nquat, quat);
+ normalize_qt_qt(noldquat, oldquat);
+
+ quat_to_eul(eul, nquat);
+ quat_to_eul(oldeul, noldquat);
+
+ 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];
+ }
+
+ eul_to_quat(quat, eul);
+
+ /* restore original quat size */
+ mul_qt_fl(quat, qlen);
+
+ /* quaternions flip w sign to accumulate rotations correctly */
+ if ((nquat[0] < 0.0f && quat[0] > 0.0f) || (nquat[0] > 0.0f && quat[0] < 0.0f)) {
+ mul_qt_fl(quat, -1.0f);
+ }
+ }
+}
+
+static void protectedRotateBits(short protectflag, float eul[3], const float oldeul[3])
+{
+ 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];
+ }
+}
+
+/* this function only does the delta rotation */
+/* axis-angle is usually internally stored as quats... */
+static void protectedAxisAngleBits(
+ short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle)
+{
+ /* check that protection flags are set */
+ if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0) {
+ return;
+ }
+
+ if (protectflag & OB_LOCK_ROT4D) {
+ /* axis-angle getting limited as 4D entities that they are... */
+ if (protectflag & OB_LOCK_ROTW) {
+ *angle = oldAngle;
+ }
+ if (protectflag & OB_LOCK_ROTX) {
+ axis[0] = oldAxis[0];
+ }
+ if (protectflag & OB_LOCK_ROTY) {
+ axis[1] = oldAxis[1];
+ }
+ if (protectflag & OB_LOCK_ROTZ) {
+ axis[2] = oldAxis[2];
+ }
+ }
+ else {
+ /* axis-angle get limited with euler... */
+ float eul[3], oldeul[3];
+
+ axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
+ axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
+
+ 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];
+ }
+
+ eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
+
+ /* When converting to axis-angle,
+ * we need a special exception for the case when there is no axis. */
+ if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
+ /* for now, rotate around y-axis then (so that it simply becomes the roll) */
+ axis[1] = 1.0f;
+ }
+ }
+}
+
+static void protectedSizeBits(short protectflag, float size[3])
+{
+ 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;
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Limits
+ * \{ */
+
+void constraintTransLim(TransInfo *t, TransData *td)
+{
+ if (td->con) {
+ const bConstraintTypeInfo *ctiLoc = BKE_constraint_typeinfo_from_type(
+ CONSTRAINT_TYPE_LOCLIMIT);
+ const bConstraintTypeInfo *ctiDist = BKE_constraint_typeinfo_from_type(
+ CONSTRAINT_TYPE_DISTLIMIT);
+
+ bConstraintOb cob = {NULL};
+ bConstraint *con;
+ float ctime = (float)(t->scene->r.cfra);
+
+ /* Make a temporary bConstraintOb for using these limit constraints
+ * - they only care that cob->matrix is correctly set ;-)
+ * - current space should be local
+ */
+ unit_m4(cob.matrix);
+ copy_v3_v3(cob.matrix[3], td->loc);
+
+ /* Evaluate valid constraints */
+ for (con = td->con; con; con = con->next) {
+ const bConstraintTypeInfo *cti = NULL;
+ ListBase targets = {NULL, NULL};
+
+ /* only consider constraint if enabled */
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
+ 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 = (bLocLimitConstraint *)con->data;
+
+ if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
+ continue;
+ }
+ cti = ctiLoc;
+ }
+ else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
+ bDistLimitConstraint *data = (bDistLimitConstraint *)con->data;
+
+ if ((data->flag & LIMITDIST_TRANSFORM) == 0) {
+ continue;
+ }
+ cti = ctiDist;
+ }
+
+ if (cti) {
+ /* do space conversions */
+ if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+ /* just multiply by td->mtx (this should be ok) */
+ mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
+ }
+ else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
+ /* skip... incompatible spacetype */
+ continue;
+ }
+
+ /* get constraint targets if needed */
+ BKE_constraint_targets_for_solving_get(t->depsgraph, con, &cob, &targets, ctime);
+
+ /* do constraint */
+ cti->evaluate_constraint(con, &cob, &targets);
+
+ /* convert spaces again */
+ if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+ /* just multiply by td->smtx (this should be ok) */
+ mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
+ }
+
+ /* free targets list */
+ BLI_freelistN(&targets);
+ }
+ }
+
+ /* copy results from cob->matrix */
+ copy_v3_v3(td->loc, cob.matrix[3]);
+ }
+}
+
+static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
+{
+ /* Make a temporary bConstraintOb for use by limit constraints
+ * - they only care that cob->matrix is correctly set ;-)
+ * - current space should be local
+ */
+ memset(cob, 0, sizeof(bConstraintOb));
+ if (td->ext) {
+ if (td->ext->rotOrder == ROT_MODE_QUAT) {
+ /* quats */
+ /* objects and bones do normalization first too, otherwise
+ * we don't necessarily end up with a rotation matrix, and
+ * then conversion back to quat gives a different result */
+ float quat[4];
+ normalize_qt_qt(quat, td->ext->quat);
+ quat_to_mat4(cob->matrix, quat);
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+ /* axis angle */
+ axis_angle_to_mat4(cob->matrix, td->ext->rotAxis, *td->ext->rotAngle);
+ }
+ else {
+ /* eulers */
+ eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
+ }
+ }
+}
+
+static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
+{
+ if (td->con) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_ROTLIMIT);
+ bConstraintOb cob;
+ bConstraint *con;
+ bool do_limit = false;
+
+ /* Evaluate valid constraints */
+ for (con = td->con; con; con = con->next) {
+ /* only consider constraint if enabled */
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
+ continue;
+ }
+ if (con->enforce == 0.0f) {
+ continue;
+ }
+
+ /* we're only interested in Limit-Rotation constraints */
+ if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
+ bRotLimitConstraint *data = (bRotLimitConstraint *)con->data;
+
+ /* only use it if it's tagged for this purpose */
+ if ((data->flag2 & LIMIT_TRANSFORM) == 0) {
+ continue;
+ }
+
+ /* skip incompatible spacetypes */
+ if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL)) {
+ continue;
+ }
+
+ /* only do conversion if necessary, to preserve quats and eulers */
+ if (do_limit == false) {
+ constraintob_from_transdata(&cob, td);
+ do_limit = true;
+ }
+
+ /* do space conversions */
+ if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+ /* just multiply by td->mtx (this should be ok) */
+ mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
+ }
+
+ /* do constraint */
+ cti->evaluate_constraint(con, &cob, NULL);
+
+ /* convert spaces again */
+ if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+ /* just multiply by td->smtx (this should be ok) */
+ mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
+ }
+ }
+ }
+
+ if (do_limit) {
+ /* copy results from cob->matrix */
+ if (td->ext->rotOrder == ROT_MODE_QUAT) {
+ /* quats */
+ mat4_to_quat(td->ext->quat, cob.matrix);
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+ /* axis angle */
+ mat4_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, cob.matrix);
+ }
+ else {
+ /* eulers */
+ mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
+ }
+ }
+ }
+}
+
+static void constraintSizeLim(TransInfo *t, TransData *td)
+{
+ if (td->con && td->ext) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_from_type(CONSTRAINT_TYPE_SIZELIMIT);
+ bConstraintOb cob = {NULL};
+ bConstraint *con;
+ float size_sign[3], size_abs[3];
+ int i;
+
+ /* Make a temporary bConstraintOb for using these limit constraints
+ * - they only care that cob->matrix is correctly set ;-)
+ * - current space should be local
+ */
+ 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;
+ }
+
+ /* separate out sign to apply back later */
+ for (i = 0; i < 3; i++) {
+ size_sign[i] = signf(td->ext->size[i]);
+ size_abs[i] = fabsf(td->ext->size[i]);
+ }
+
+ size_to_mat4(cob.matrix, size_abs);
+ }
+
+ /* Evaluate valid constraints */
+ for (con = td->con; con; con = con->next) {
+ /* only consider constraint if enabled */
+ if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) {
+ 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;
+
+ /* 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) */
+ mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
+ }
+ else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
+ /* skip... incompatible spacetype */
+ continue;
+ }
+
+ /* do constraint */
+ cti->evaluate_constraint(con, &cob, NULL);
+
+ /* convert spaces again */
+ if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
+ /* just multiply by td->smtx (this should be ok) */
+ mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
+ }
+ }
+ }
+
+ /* copy results from cob->matrix */
+ 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;
+ }
+
+ /* extrace scale from matrix and apply back sign */
+ mat4_to_size(td->ext->size, cob.matrix);
+ mul_v3_v3(td->ext->size, size_sign);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* Transform (Rotation Utils) */
+
+/** \name Transform Rotation Utils
+ * \{ */
+/* Used by Transform Rotation and Transform Normal Rotation */
+void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final)
+{
+ size_t ofs = 0;
+
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Rot: %.2f%s %s"),
+ RAD2DEGF(final),
+ t->con.text,
+ t->proptext);
+ }
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ }
+}
+
+void postInputRotation(TransInfo *t, float values[3])
+{
+ float axis_final[3];
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, values);
+ }
+}
+
+/**
+ * Applies values of rotation to `td->loc` and `td->ext->quat`
+ * based on a rotation matrix (mat) and a pivot (center).
+ *
+ * Protected axis and other transform settings are taken into account.
+ */
+void ElementRotation_ex(TransInfo *t,
+ TransDataContainer *tc,
+ TransData *td,
+ const float mat[3][3],
+ const float *center)
+{
+ float vec[3], totmat[3][3], smat[3][3];
+ float eul[3], fmat[3][3], quat[4];
+
+ if (t->flag & T_POINTS) {
+ mul_m3_m3m3(totmat, mat, td->mtx);
+ mul_m3_m3m3(smat, td->smtx, totmat);
+
+ /* apply gpencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ float sx = smat[0][0];
+ float sy = smat[1][1];
+ float sz = smat[2][2];
+
+ mul_m3_fl(smat, gps->runtime.multi_frame_falloff);
+ /* fix scale */
+ smat[0][0] = sx;
+ smat[1][1] = sy;
+ smat[2][2] = sz;
+ }
+
+ sub_v3_v3v3(vec, td->iloc, center);
+ mul_m3_v3(smat, vec);
+
+ add_v3_v3v3(td->loc, vec, center);
+
+ sub_v3_v3v3(vec, td->loc, td->iloc);
+ protectedTransBits(td->protectflag, vec);
+ add_v3_v3v3(td->loc, td->iloc, vec);
+
+ if (td->flag & TD_USEQUAT) {
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
+ mat3_to_quat(quat, fmat); // Actual transform
+
+ if (td->ext->quat) {
+ mul_qt_qtqt(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) {
+ // Extract and invert armature object matrix
+
+ if ((td->flag & TD_NO_LOC) == 0) {
+ sub_v3_v3v3(vec, td->center, center);
+
+ mul_m3_v3(tc->mat3, vec); // To Global space
+ mul_m3_v3(mat, vec); // Applying rotation
+ mul_m3_v3(tc->imat3, vec); // To Local space
+
+ add_v3_v3(vec, center);
+ /* vec now is the location where the object has to be */
+
+ sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location
+
+ /* special exception, see TD_PBONE_LOCAL_MTX definition comments */
+ if (td->flag & TD_PBONE_LOCAL_MTX_P) {
+ /* do nothing */
+ }
+ else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
+ mul_m3_v3(tc->mat3, vec); // To Global space
+ mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location)
+ }
+ else {
+ mul_m3_v3(tc->mat3, vec); // To Global space
+ mul_m3_v3(td->smtx, vec); // To Pose space
+ }
+
+ protectedTransBits(td->protectflag, vec);
+
+ add_v3_v3v3(td->loc, td->iloc, vec);
+
+ constraintTransLim(t, td);
+ }
+
+ /* rotation */
+ /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
+ * and ElementRotation() might be called in Translation context (with align snapping),
+ * we need to be sure to actually use the *rotation* matrix here...
+ * So no other way than storing it in some dedicated members of td->ext! */
+ if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */
+ /* euler or quaternion/axis-angle? */
+ if (td->ext->rotOrder == ROT_MODE_QUAT) {
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
+
+ mat3_to_quat(quat, fmat); /* Actual transform */
+
+ mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
+ /* this function works on end result */
+ protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+ /* calculate effect based on quats */
+ float iquat[4], tquat[4];
+
+ axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
+
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
+ mat3_to_quat(quat, fmat); /* Actual transform */
+ mul_qt_qtqt(tquat, quat, iquat);
+
+ quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
+
+ /* this function works on end result */
+ protectedAxisAngleBits(td->protectflag,
+ td->ext->rotAxis,
+ td->ext->rotAngle,
+ td->ext->irotAxis,
+ td->ext->irotAngle);
+ }
+ else {
+ float eulmat[3][3];
+
+ mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
+ mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
+
+ /* calculate the total rotatation in eulers */
+ copy_v3_v3(eul, td->ext->irot);
+ eulO_to_mat3(eulmat, eul, td->ext->rotOrder);
+
+ /* mat = transform, obmat = bone rotation */
+ mul_m3_m3m3(fmat, smat, eulmat);
+
+ mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
+
+ /* and apply (to end result only) */
+ protectedRotateBits(td->protectflag, eul, td->ext->irot);
+ copy_v3_v3(td->ext->rot, eul);
+ }
+
+ constraintRotLim(t, td);
+ }
+ }
+ else {
+ if ((td->flag & TD_NO_LOC) == 0) {
+ /* translation */
+ sub_v3_v3v3(vec, td->center, center);
+ mul_m3_v3(mat, vec);
+ add_v3_v3(vec, center);
+ /* vec now is the location where the object has to be */
+ sub_v3_v3(vec, td->center);
+ mul_m3_v3(td->smtx, vec);
+
+ protectedTransBits(td->protectflag, vec);
+
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
+
+ constraintTransLim(t, td);
+
+ /* rotation */
+ if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself
+ /* euler or quaternion? */
+ if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
+ /* can be called for texture space translate for example, then opt out */
+ if (td->ext->quat) {
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
+ mat3_to_quat(quat, fmat); // Actual transform
+
+ mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
+ /* this function works on end result */
+ protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
+ }
+ }
+ else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
+ /* calculate effect based on quats */
+ float iquat[4], tquat[4];
+
+ axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
+
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
+ mat3_to_quat(quat, fmat); // Actual transform
+ mul_qt_qtqt(tquat, quat, iquat);
+
+ quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
+
+ /* this function works on end result */
+ protectedAxisAngleBits(td->protectflag,
+ td->ext->rotAxis,
+ td->ext->rotAngle,
+ td->ext->irotAxis,
+ td->ext->irotAngle);
+ }
+ else {
+ float obmat[3][3];
+
+ mul_m3_m3m3(totmat, mat, td->mtx);
+ mul_m3_m3m3(smat, td->smtx, totmat);
+
+ /* calculate the total rotatation in eulers */
+ add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* correct for delta rot */
+ eulO_to_mat3(obmat, eul, td->ext->rotOrder);
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
+
+ /* correct back for delta rot */
+ sub_v3_v3v3(eul, eul, td->ext->drot);
+
+ /* and apply */
+ protectedRotateBits(td->protectflag, eul, td->ext->irot);
+ copy_v3_v3(td->ext->rot, eul);
+ }
+
+ constraintRotLim(t, td);
+ }
+ }
+}
+
+void ElementRotation(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around)
+{
+ const float *center;
+
+ /* local constraint shouldn't alter center */
+ if (transdata_check_local_center(t, around)) {
+ center = td->center;
+ }
+ else {
+ center = tc->center_local;
+ }
+
+ ElementRotation_ex(t, tc, td, mat, center);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Transform (Resize Utils) */
+
+/** \name Transform Resize Utils
+ * \{ */
+void headerResize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+ size_t ofs = 0;
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
+ }
+
+ if (t->con.mode & CON_APPLY) {
+ switch (t->num.idx_max) {
+ case 0:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Scale: %s%s %s"),
+ &tvec[0],
+ t->con.text,
+ t->proptext);
+ break;
+ case 1:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Scale: %s : %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ t->con.text,
+ t->proptext);
+ break;
+ case 2:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Scale: %s : %s : %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ t->con.text,
+ t->proptext);
+ break;
+ }
+ }
+ else {
+ if (t->flag & T_2D_EDIT) {
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Scale X: %s Y: %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ t->con.text,
+ t->proptext);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_("Scale X: %s Y: %s Z: %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ t->con.text,
+ t->proptext);
+ }
+ }
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ }
+}
+
+/**
+ * \a smat is reference matrix only.
+ *
+ * \note this is a tricky area, before making changes see: T29633, T42444
+ */
+static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
+{
+ float rmat[3][3];
+
+ mat3_to_rot_size(rmat, size, mat);
+
+ /* first tried with dotproduct... but the sign flip is crucial */
+ if (dot_v3v3(rmat[0], smat[0]) < 0.0f) {
+ size[0] = -size[0];
+ }
+ if (dot_v3v3(rmat[1], smat[1]) < 0.0f) {
+ size[1] = -size[1];
+ }
+ if (dot_v3v3(rmat[2], smat[2]) < 0.0f) {
+ size[2] = -size[2];
+ }
+}
+
+void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
+{
+ float tmat[3][3], smat[3][3], center[3];
+ float vec[3];
+
+ if (t->flag & T_EDIT) {
+ mul_m3_m3m3(smat, mat, td->mtx);
+ mul_m3_m3m3(tmat, td->smtx, smat);
+ }
+ else {
+ copy_m3_m3(tmat, mat);
+ }
+
+ if (t->con.applySize) {
+ t->con.applySize(t, tc, td, tmat);
+ }
+
+ /* local constraint shouldn't alter center */
+ if (transdata_check_local_center(t, t->around)) {
+ copy_v3_v3(center, td->center);
+ }
+ else if (t->options & CTX_MOVIECLIP) {
+ if (td->flag & TD_INDIVIDUAL_SCALE) {
+ copy_v3_v3(center, td->center);
+ }
+ else {
+ copy_v3_v3(center, tc->center_local);
+ }
+ }
+ else {
+ copy_v3_v3(center, tc->center_local);
+ }
+
+ /* Size checked needed since the 3D cursor only uses rotation fields. */
+ if (td->ext && td->ext->size) {
+ float fsize[3];
+
+ if ((t->options & CTX_SCULPT) || t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
+ float obsizemat[3][3];
+ /* Reorient the size mat to fit the oriented object. */
+ mul_m3_m3m3(obsizemat, tmat, td->axismtx);
+ /* print_m3("obsizemat", obsizemat); */
+ TransMat3ToSize(obsizemat, td->axismtx, fsize);
+ /* print_v3("fsize", fsize); */
+ }
+ else {
+ mat3_to_size(fsize, tmat);
+ }
+
+ protectedSizeBits(td->protectflag, fsize);
+
+ if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't resize objects itself */
+ if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
+ /* scale val and reset size */
+ *td->val = td->ival * (1 + (fsize[0] - 1) * 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] * (1 + (fsize[0] - 1) * td->factor);
+ td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+ td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor);
+ }
+ }
+
+ constraintSizeLim(t, td);
+ }
+
+ /* For individual element center, Editmode need to use iloc */
+ if (t->flag & T_POINTS) {
+ sub_v3_v3v3(vec, td->iloc, center);
+ }
+ else {
+ sub_v3_v3v3(vec, td->center, center);
+ }
+
+ mul_m3_v3(tmat, vec);
+
+ add_v3_v3(vec, center);
+ if (t->flag & T_POINTS) {
+ sub_v3_v3(vec, td->iloc);
+ }
+ else {
+ sub_v3_v3(vec, td->center);
+ }
+
+ /* grease pencil falloff */
+ if (t->options & CTX_GPENCIL_STROKES) {
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
+
+ /* scale stroke thickness */
+ if (td->val) {
+ snapGridIncrement(t, t->values_final);
+ applyNumInput(&t->num, t->values_final);
+
+ float ratio = t->values_final[0];
+ *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff;
+ CLAMP_MIN(*td->val, 0.001f);
+ }
+ }
+ else {
+ mul_v3_fl(vec, td->factor);
+ }
+
+ if (t->flag & (T_OBJECT | T_POSE)) {
+ mul_m3_v3(td->smtx, vec);
+ }
+
+ protectedTransBits(td->protectflag, vec);
+ if (td->loc) {
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
+
+ constraintTransLim(t, td);
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/* Transform (Frame Utils) */
+
+/** \name Transform Frame Utils
+ * \{ */
+
+/* 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
+short getAnimEdit_SnapMode(TransInfo *t)
+{
+ short autosnap = SACTSNAP_OFF;
+
+ if (t->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
+
+ if (saction) {
+ autosnap = saction->autosnap;
+ }
+ }
+ else if (t->spacetype == SPACE_GRAPH) {
+ SpaceGraph *sipo = (SpaceGraph *)t->area->spacedata.first;
+
+ if (sipo) {
+ autosnap = sipo->autosnap;
+ }
+ }
+ else if (t->spacetype == SPACE_NLA) {
+ SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
+
+ if (snla) {
+ autosnap = snla->autosnap;
+ }
+ }
+ else {
+ autosnap = SACTSNAP_OFF;
+ }
+
+ /* toggle autosnap on/off
+ * - when toggling on, prefer nearest frame over 1.0 frame increments
+ */
+ if (t->modifiers & MOD_SNAP_INVERT) {
+ if (autosnap) {
+ autosnap = SACTSNAP_OFF;
+ }
+ else {
+ autosnap = SACTSNAP_FRAME;
+ }
+ }
+
+ return autosnap;
+}
+
+/* This function is used by Animation Editor specific transform functions to do
+ * the Snap Keyframe to Nearest Frame/Marker
+ */
+void doAnimEdit_SnapFrame(
+ TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap)
+{
+ if (autosnap != SACTSNAP_OFF) {
+ float val;
+
+ /* convert frame to nla-action time (if needed) */
+ if (adt && (t->spacetype != SPACE_SEQ)) {
+ val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
+ }
+ else {
+ val = *(td->val);
+ }
+
+ snapFrameTransform(t, autosnap, true, val, &val);
+
+ /* convert frame out of nla-action time */
+ if (adt && (t->spacetype != SPACE_SEQ)) {
+ *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
+ }
+ else {
+ *(td->val) = val;
+ }
+ }
+
+ /* If the handles are to be moved too
+ * (as side-effect of keyframes moving, to keep the general effect)
+ * offset them by the same amount so that the general angles are maintained
+ * (i.e. won't change while handles are free-to-roam and keyframes are snap-locked).
+ */
+ if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
+ td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival;
+ }
+ if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
+ td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival;
+ }
+}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Transform Mode Initialization
+ * \{ */
+
+void transform_mode_init(TransInfo *t, wmOperator *op, const int mode)
+{
+ t->mode = mode;
+
+ switch (mode) {
+ case TFM_TRANSLATION:
+ initTranslation(t);
+ break;
+ case TFM_ROTATION:
+ initRotation(t);
+ break;
+ case TFM_RESIZE:
+ initResize(t);
+ break;
+ case TFM_SKIN_RESIZE:
+ initSkinResize(t);
+ break;
+ case TFM_TOSPHERE:
+ initToSphere(t);
+ break;
+ case TFM_SHEAR:
+ initShear(t);
+ break;
+ case TFM_BEND:
+ initBend(t);
+ break;
+ case TFM_SHRINKFATTEN:
+ initShrinkFatten(t);
+ break;
+ case TFM_TILT:
+ initTilt(t);
+ break;
+ case TFM_CURVE_SHRINKFATTEN:
+ initCurveShrinkFatten(t);
+ break;
+ case TFM_MASK_SHRINKFATTEN:
+ initMaskShrinkFatten(t);
+ break;
+ case TFM_GPENCIL_SHRINKFATTEN:
+ initGPShrinkFatten(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) */
+ /* Note: we have to pick one, use the active object. */
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_OK(t);
+ bArmature *arm = tc->poseobj->data;
+ if (arm->drawtype == ARM_ENVELOPE) {
+ initBoneEnvelope(t);
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ }
+ else {
+ initBoneSize(t);
+ }
+ break;
+ }
+ case TFM_BONE_ENVELOPE:
+ initBoneEnvelope(t);
+ break;
+ case TFM_BONE_ENVELOPE_DIST:
+ initBoneEnvelope(t);
+ t->mode = TFM_BONE_ENVELOPE_DIST;
+ break;
+ case TFM_EDGE_SLIDE:
+ case TFM_VERT_SLIDE: {
+ const bool use_even = (op ? RNA_boolean_get(op->ptr, "use_even") : false);
+ const bool flipped = (op ? RNA_boolean_get(op->ptr, "flipped") : false);
+ const bool use_clamp = (op ? RNA_boolean_get(op->ptr, "use_clamp") : true);
+ if (mode == TFM_EDGE_SLIDE) {
+ const bool use_double_side = (op ? !RNA_boolean_get(op->ptr, "single_side") : true);
+ initEdgeSlide_ex(t, use_double_side, use_even, flipped, use_clamp);
+ }
+ else {
+ initVertSlide_ex(t, use_even, flipped, use_clamp);
+ }
+ 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_DUPLICATE:
+ /* same as TFM_TIME_EXTEND, but we need the mode info for later
+ * so that duplicate-culling will work properly
+ */
+ if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
+ initTranslation(t);
+ }
+ else {
+ initTimeTranslate(t);
+ }
+ break;
+ case TFM_TIME_EXTEND:
+ /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
+ * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
+ * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
+ * depending on which editor this was called from
+ */
+ if (ELEM(t->spacetype, SPACE_GRAPH, SPACE_NLA)) {
+ initTranslation(t);
+ }
+ else {
+ initTimeTranslate(t);
+ }
+ break;
+ case TFM_BAKE_TIME:
+ initBakeTime(t);
+ break;
+ case TFM_MIRROR:
+ initMirror(t);
+ break;
+ case TFM_BWEIGHT:
+ initBevelWeight(t);
+ break;
+ case TFM_ALIGN:
+ initAlign(t);
+ break;
+ case TFM_SEQ_SLIDE:
+ initSeqSlide(t);
+ break;
+ case TFM_NORMAL_ROTATION:
+ initNormalRotation(t);
+ break;
+ case TFM_GPENCIL_OPACITY:
+ initGPOpacity(t);
+ break;
+ }
+
+ /* TODO(germano): Some of these operations change the `t->mode`.
+ * This can be bad for Redo.
+ * BLI_assert(t->mode == mode); */
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h
new file mode 100644
index 00000000000..6180f6d3477
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode.h
@@ -0,0 +1,160 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ * \brief transform modes used by different operators.
+ */
+
+#ifndef __TRANSFORM_MODE_H__
+#define __TRANSFORM_MODE_H__
+
+struct AnimData;
+struct LinkNode;
+struct TransData;
+struct TransDataContainer;
+struct TransInfo;
+struct wmOperator;
+
+/* header of TransDataEdgeSlideVert, TransDataEdgeSlideEdge */
+typedef struct TransDataGenericSlideVert {
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ float co_orig_3d[3];
+} TransDataGenericSlideVert;
+
+/* transform_mode.c */
+bool transdata_check_local_center(TransInfo *t, short around);
+void protectedTransBits(short protectflag, float vec[3]);
+void constraintTransLim(TransInfo *t, TransData *td);
+void postInputRotation(TransInfo *t, float values[3]);
+void headerRotation(TransInfo *t, char *str, float final);
+void ElementRotation_ex(TransInfo *t,
+ TransDataContainer *tc,
+ TransData *td,
+ const float mat[3][3],
+ const float *center);
+void ElementRotation(
+ TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3], const short around);
+void headerResize(TransInfo *t, const float vec[3], char *str);
+void ElementResize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3]);
+short getAnimEdit_SnapMode(TransInfo *t);
+void doAnimEdit_SnapFrame(
+ TransInfo *t, TransData *td, TransData2D *td2d, struct AnimData *adt, short autosnap);
+void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode);
+
+/* transform_mode_align.c */
+void initAlign(TransInfo *t);
+
+/* transform_mode_baketime.c */
+void initBakeTime(TransInfo *t);
+
+/* transform_mode_bbone_resize.c */
+void initBoneSize(TransInfo *t);
+
+/* transform_mode_bend.c */
+void initBend(TransInfo *t);
+
+/* transform_mode_boneenvelope.c */
+void initBoneEnvelope(TransInfo *t);
+
+/* transform_mode_boneroll.c */
+void initBoneRoll(TransInfo *t);
+
+/* transform_mode_curveshrinkfatten.c */
+void initCurveShrinkFatten(TransInfo *t);
+
+/* transform_mode_edge_bevelweight.c */
+void initBevelWeight(TransInfo *t);
+
+/* transform_mode_edge_crease.c */
+void initCrease(TransInfo *t);
+
+/* transform_mode_edge_rotate_normal.c */
+void initNormalRotation(TransInfo *t);
+
+/* transform_mode_edge_seq_slide.c */
+void initSeqSlide(TransInfo *t);
+
+/* transform_mode_edge_slide.c */
+void projectEdgeSlideData(TransInfo *t, bool is_final);
+void drawEdgeSlide(TransInfo *t);
+void doEdgeSlide(TransInfo *t, float perc);
+void initEdgeSlide_ex(
+ TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp);
+void initEdgeSlide(TransInfo *t);
+
+/* transform_mode_gpopacity.c */
+void initGPOpacity(TransInfo *t);
+
+/* transform_mode_gpshrinkfatten.c */
+void initGPShrinkFatten(TransInfo *t);
+
+/* transform_mode_maskshrinkfatten.c */
+void initMaskShrinkFatten(TransInfo *t);
+
+/* transform_mode_mirror.c */
+void initMirror(TransInfo *t);
+
+/* transform_mode_push_pull.c */
+void initPushPull(TransInfo *t);
+
+/* transform_mode_resize.c */
+void initResize(TransInfo *t);
+
+/* transform_mode_rotate.c */
+void initRotation(TransInfo *t);
+
+/* transform_mode_shear.c */
+void initShear(TransInfo *t);
+
+/* transform_mode_shrink_fatten.c */
+void initShrinkFatten(TransInfo *t);
+
+/* transform_mode_skin_resize.c */
+void initSkinResize(TransInfo *t);
+
+/* transform_mode_tilt.c */
+void initTilt(TransInfo *t);
+
+/* transform_mode_timescale.c */
+void initTimeScale(TransInfo *t);
+
+/* transform_mode_timeslide.c */
+void initTimeSlide(TransInfo *t);
+
+/* transform_mode_timetranslate.c */
+void initTimeTranslate(TransInfo *t);
+
+/* transform_mode_tosphere.c */
+void initToSphere(TransInfo *t);
+
+/* transform_mode_trackball.c */
+void initTrackball(TransInfo *t);
+
+/* transform_mode_translate.c */
+void initTranslation(TransInfo *t);
+
+/* transform_mode_vert_slide.c */
+void projectVertSlideData(TransInfo *t, bool is_final);
+void drawVertSlide(TransInfo *t);
+void doVertSlide(TransInfo *t, float perc);
+void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp);
+void initVertSlide(TransInfo *t);
+#endif
diff --git a/source/blender/editors/transform/transform_mode_align.c b/source/blender/editors/transform/transform_mode_align.c
new file mode 100644
index 00000000000..9bce793809b
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_align.c
@@ -0,0 +1,96 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Align) */
+
+/** \name Transform Align
+ * \{ */
+
+static void applyAlign(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float center[3];
+ int i;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ /* saving original center */
+ copy_v3_v3(center, tc->center_local);
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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)) {
+ copy_v3_v3(tc->center_local, td->center);
+ }
+ else {
+ if (t->settings->selectmode & SCE_SELECT_FACE) {
+ copy_v3_v3(tc->center_local, td->center);
+ }
+ }
+
+ invert_m3_m3(invmat, td->axismtx);
+
+ mul_m3_m3m3(mat, t->spacemtx, invmat);
+
+ ElementRotation(t, tc, td, mat, t->around);
+ }
+ /* restoring original center */
+ copy_v3_v3(tc->center_local, center);
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, TIP_("Align"));
+}
+
+void initAlign(TransInfo *t)
+{
+ t->flag |= T_NO_CONSTRAINT;
+
+ t->transform = applyAlign;
+
+ initMouseInputMode(t, &t->mouse, INPUT_NONE);
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_baketime.c b/source/blender/editors/transform/transform_mode_baketime.c
new file mode 100644
index 00000000000..bb8fd0df13d
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_baketime.c
@@ -0,0 +1,140 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Bake-Time) */
+
+/** \name Transform Bake-Time
+ * \{ */
+
+static void applyBakeTime(TransInfo *t, const int mval[2])
+{
+ float time;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ float fac = 0.1f;
+
+ /* XXX, disable precision for now,
+ * this isn't even accessible by the user */
+#if 0
+ if (t->mouse.precision) {
+ /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
+ time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac;
+ time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time);
+ }
+ else
+#endif
+ {
+ time = (float)(t->center2d[0] - mval[0]) * fac;
+ }
+
+ snapGridIncrement(t, &time);
+
+ applyNumInput(&t->num, &time);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ if (time >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Time: +%s %s"), c, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Time: %s %s"), c, t->proptext);
+ }
+ }
+ else {
+ /* default header print */
+ if (time >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Time: +%.3f %s"), time, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Time: %.3f %s"), time, t->proptext);
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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_status_text(t->area, str);
+}
+
+void initBakeTime(TransInfo *t)
+{
+ t->transform = applyBakeTime;
+ initMouseInputMode(t, &t->mouse, INPUT_NONE);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE; /* Don't think this uses units? */
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bbone_resize.c b/source/blender/editors/transform/transform_mode_bbone_resize.c
new file mode 100644
index 00000000000..c81049ac379
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_bbone_resize.c
@@ -0,0 +1,184 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_constraints.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (EditBone (B-bone) width scaling) */
+
+/** \name Transform B-bone width scaling
+ * \{ */
+
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.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) {
+ BLI_snprintf(
+ str, UI_MAX_DRAW_STR, TIP_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
+ }
+ else {
+ BLI_snprintf(str,
+ UI_MAX_DRAW_STR,
+ TIP_("ScaleB: %s : %s : %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ t->con.text,
+ t->proptext);
+ }
+ }
+ else {
+ BLI_snprintf(str,
+ UI_MAX_DRAW_STR,
+ TIP_("ScaleB X: %s Y: %s Z: %s%s %s"),
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ t->con.text,
+ t->proptext);
+ }
+}
+
+static void ElementBoneSize(TransInfo *t, TransDataContainer *tc, TransData *td, float mat[3][3])
+{
+ float tmat[3][3], smat[3][3], oldy;
+ float sizemat[3][3];
+
+ mul_m3_m3m3(smat, mat, td->mtx);
+ mul_m3_m3m3(tmat, td->smtx, smat);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, tc, td, tmat);
+ }
+
+ /* we've tucked the scale in loc */
+ oldy = td->iloc[1];
+ size_to_mat3(sizemat, td->iloc);
+ mul_m3_m3m3(tmat, tmat, sizemat);
+ mat3_to_size(td->loc, tmat);
+ td->loc[1] = oldy;
+}
+
+static void applyBoneSize(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float mat[3][3];
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ if (t->flag & T_INPUT_IS_VALUES_FINAL) {
+ copy_v3_v3(t->values_final, t->values);
+ }
+ else {
+ float ratio = t->values[0];
+
+ copy_v3_fl(t->values_final, ratio);
+
+ snapGridIncrement(t, t->values_final);
+
+ if (applyNumInput(&t->num, t->values_final)) {
+ constraintNumInput(t, t->values_final);
+ }
+ }
+
+ size_to_mat3(mat, t->values_final);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, NULL, mat);
+ }
+
+ copy_m3_m3(t->mat, mat); // used in gizmo
+
+ headerBoneSize(t, t->values_final, str);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ ElementBoneSize(t, tc, td, mat);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initBoneSize(TransInfo *t)
+{
+ t->mode = TFM_BONESIZE;
+ t->transform = applyBoneSize;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+
+ t->idx_max = 2;
+ t->num.idx_max = 2;
+ t->num.val_flag[0] |= NUM_NULL_ONE;
+ t->num.val_flag[1] |= NUM_NULL_ONE;
+ t->num.val_flag[2] |= NUM_NULL_ONE;
+ t->num.flag |= NUM_AFFECT_ALL;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+ t->num.unit_type[1] = B_UNIT_NONE;
+ t->num.unit_type[2] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c
new file mode 100644
index 00000000000..721d226050a
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_bend.c
@@ -0,0 +1,308 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Bend) */
+
+/** \name Transform Bend
+ * \{ */
+
+struct BendCustomData {
+ /* All values are in global space. */
+ float warp_sta[3];
+ float warp_end[3];
+
+ float warp_nor[3];
+ float warp_tan[3];
+
+ /* for applying the mouse distance */
+ float warp_init_dist;
+};
+
+static eRedrawFlag handleEventBend(TransInfo *UNUSED(t), const wmEvent *event)
+{
+ eRedrawFlag status = TREDRAW_NOTHING;
+
+ if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
+ status = TREDRAW_HARD;
+ }
+
+ return status;
+}
+
+static void Bend(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float vec[3];
+ float pivot_global[3];
+ float warp_end_radius_global[3];
+ int i;
+ char str[UI_MAX_DRAW_STR];
+ const struct BendCustomData *data = t->custom.mode.data;
+ const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
+
+ union {
+ struct {
+ float angle, scale;
+ };
+ float vector[2];
+ } values;
+
+ /* amount of radians for bend */
+ copy_v2_v2(values.vector, t->values);
+
+#if 0
+ snapGrid(t, angle_rad);
+#else
+ /* hrmf, snapping radius is using 'angle' steps, need to convert to something else
+ * this isnt essential but nicer to give reasonable snapping values for radius */
+ if (t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) {
+ const float radius_snap = 0.1f;
+ const float snap_hack = (t->snap[1] * data->warp_init_dist) / radius_snap;
+ values.scale *= snap_hack;
+ snapGridIncrement(t, values.vector);
+ values.scale /= snap_hack;
+ }
+#endif
+
+ if (applyNumInput(&t->num, values.vector)) {
+ values.scale = values.scale / data->warp_init_dist;
+ }
+
+ copy_v2_v2(t->values_final, values.vector);
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN * 2];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str,
+ sizeof(str),
+ TIP_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
+ &c[0],
+ &c[NUM_STR_REP_LEN],
+ WM_bool_as_string(is_clamp));
+ }
+ else {
+ /* default header print */
+ BLI_snprintf(str,
+ sizeof(str),
+ TIP_("Bend Angle: %.3f Radius: %.4f, Alt, Clamp %s"),
+ RAD2DEGF(values.angle),
+ values.scale * data->warp_init_dist,
+ WM_bool_as_string(is_clamp));
+ }
+
+ values.angle *= -1.0f;
+ values.scale *= data->warp_init_dist;
+
+ /* calc 'data->warp_end' from 'data->warp_end_init' */
+ copy_v3_v3(warp_end_radius_global, data->warp_end);
+ dist_ensure_v3_v3fl(warp_end_radius_global, data->warp_sta, values.scale);
+ /* done */
+
+ /* calculate pivot */
+ copy_v3_v3(pivot_global, data->warp_sta);
+ if (values.angle > 0.0f) {
+ madd_v3_v3fl(pivot_global,
+ data->warp_tan,
+ -values.scale * shell_angle_to_dist((float)M_PI_2 - values.angle));
+ }
+ else {
+ madd_v3_v3fl(pivot_global,
+ data->warp_tan,
+ +values.scale * shell_angle_to_dist((float)M_PI_2 + values.angle));
+ }
+
+ /* TODO(campbell): xform, compensate object center. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+
+ float warp_sta_local[3];
+ float warp_end_local[3];
+ float warp_end_radius_local[3];
+ float pivot_local[3];
+
+ if (tc->use_local_mat) {
+ sub_v3_v3v3(warp_sta_local, data->warp_sta, tc->mat[3]);
+ sub_v3_v3v3(warp_end_local, data->warp_end, tc->mat[3]);
+ sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
+ sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
+ }
+ else {
+ copy_v3_v3(warp_sta_local, data->warp_sta);
+ copy_v3_v3(warp_end_local, data->warp_end);
+ copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
+ copy_v3_v3(pivot_local, pivot_global);
+ }
+
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float mat[3][3];
+ float delta[3];
+ float fac, fac_scaled;
+
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (UNLIKELY(values.angle == 0.0f)) {
+ copy_v3_v3(td->loc, td->iloc);
+ continue;
+ }
+
+ copy_v3_v3(vec, td->iloc);
+ mul_m3_v3(td->mtx, vec);
+
+ fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
+ if (is_clamp) {
+ CLAMP(fac, 0.0f, 1.0f);
+ }
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* grease pencil multiframe falloff */
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ if (gps != NULL) {
+ fac_scaled = fac * td->factor * gps->runtime.multi_frame_falloff;
+ }
+ else {
+ fac_scaled = fac * td->factor;
+ }
+ }
+ else {
+ fac_scaled = fac * td->factor;
+ }
+
+ axis_angle_normalized_to_mat3(mat, data->warp_nor, values.angle * fac_scaled);
+ interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
+ sub_v3_v3(delta, warp_sta_local);
+
+ /* delta is subtracted, rotation adds back this offset */
+ sub_v3_v3(vec, delta);
+
+ sub_v3_v3(vec, pivot_local);
+ mul_m3_v3(mat, vec);
+ add_v3_v3(vec, pivot_local);
+
+ mul_m3_v3(td->smtx, vec);
+
+ /* rotation */
+ if ((t->flag & T_POINTS) == 0) {
+ ElementRotation(t, tc, td, mat, V3D_AROUND_LOCAL_ORIGINS);
+ }
+
+ /* location */
+ copy_v3_v3(td->loc, vec);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initBend(TransInfo *t)
+{
+ const float mval_fl[2] = {UNPACK2(t->mval)};
+ const float *curs;
+ float tvec[3];
+ struct BendCustomData *data;
+
+ t->mode = TFM_BEND;
+ t->transform = Bend;
+ t->handleEvent = handleEventBend;
+
+ setInputPostFct(&t->mouse, postInputRotation);
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE_SPRING);
+
+ t->idx_max = 1;
+ t->num.idx_max = 1;
+ t->snap[0] = 0.0f;
+ t->snap[1] = SNAP_INCREMENTAL_ANGLE;
+ t->snap[2] = t->snap[1] * 0.2;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+ t->num.unit_type[1] = B_UNIT_LENGTH;
+
+ t->flag |= T_NO_CONSTRAINT;
+
+ // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ calculateCenterCursor(t, t->center_global);
+ }
+ calculateCenterLocal(t, t->center_global);
+
+ t->val = 0.0f;
+
+ data = MEM_callocN(sizeof(*data), __func__);
+
+ curs = t->scene->cursor.location;
+ copy_v3_v3(data->warp_sta, curs);
+ ED_view3d_win_to_3d(
+ (View3D *)t->area->spacedata.first, t->region, curs, mval_fl, data->warp_end);
+
+ copy_v3_v3(data->warp_nor, t->viewinv[2]);
+ normalize_v3(data->warp_nor);
+
+ /* tangent */
+ sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
+ cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
+ normalize_v3(data->warp_tan);
+
+ data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
+
+ t->custom.mode.data = data;
+ t->custom.mode.use_free = true;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_boneenvelope.c b/source/blender/editors/transform/transform_mode_boneenvelope.c
new file mode 100644
index 00000000000..aa20a5ade95
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_boneenvelope.c
@@ -0,0 +1,121 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Bone Envelope) */
+
+/** \name Transform Bone Envelope
+ * \{ */
+
+static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float ratio;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, sizeof(str), TIP_("Envelope: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Envelope: %3f"), ratio);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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_status_text(t->area, str);
+}
+
+void initBoneEnvelope(TransInfo *t)
+{
+ t->mode = TFM_BONE_ENVELOPE;
+ t->transform = applyBoneEnvelope;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_boneroll.c b/source/blender/editors/transform/transform_mode_boneroll.c
new file mode 100644
index 00000000000..0564a946148
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_boneroll.c
@@ -0,0 +1,115 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (EditBone Roll) */
+
+/** \name Transform EditBone Roll
+ * \{ */
+
+static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
+{
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ float final;
+
+ final = t->values[0];
+
+ snapGridIncrement(t, &final);
+
+ applyNumInput(&t->num, &final);
+
+ t->values_final[0] = final;
+
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str, sizeof(str), TIP_("Roll: %s"), &c[0]);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Roll: %.2f"), RAD2DEGF(final));
+ }
+
+ /* set roll values */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ *(td->val) = td->ival - final;
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initBoneRoll(TransInfo *t)
+{
+ t->mode = TFM_BONE_ROLL;
+ t->transform = applyBoneRoll;
+
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_curveshrinkfatten.c b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
new file mode 100644
index 00000000000..057f13ac068
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_curveshrinkfatten.c
@@ -0,0 +1,124 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Curve Shrink/Fatten) */
+
+/** \name Transform Curve Shrink/Fatten
+ * \{ */
+
+static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float ratio;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) {
+ *td->val = 0.001f;
+ }
+ }
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initCurveShrinkFatten(TransInfo *t)
+{
+ t->mode = TFM_CURVE_SHRINKFATTEN;
+ t->transform = applyCurveShrinkFatten;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_bevelweight.c b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
new file mode 100644
index 00000000000..5db7895232c
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_edge_bevelweight.c
@@ -0,0 +1,130 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Bevel Weight) */
+
+/** \name Transform Bevel Weight
+ * \{ */
+
+static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float weight;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ weight = t->values[0];
+
+ CLAMP_MAX(weight, 1.0f);
+
+ snapGridIncrement(t, &weight);
+
+ applyNumInput(&t->num, &weight);
+
+ t->values_final[0] = weight;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ if (weight >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%s %s"), c, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %s %s"), c, t->proptext);
+ }
+ }
+ else {
+ /* default header print */
+ if (weight >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: +%.3f %s"), weight, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Bevel Weight: %.3f %s"), weight, t->proptext);
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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_status_text(t->area, str);
+}
+
+void initBevelWeight(TransInfo *t)
+{
+ t->mode = TFM_BWEIGHT;
+ t->transform = applyBevelWeight;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c
new file mode 100644
index 00000000000..4a92a57fef6
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_edge_crease.c
@@ -0,0 +1,134 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Crease) */
+
+/** \name Transform Crease
+ * \{ */
+
+static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float crease;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ crease = t->values[0];
+
+ CLAMP_MAX(crease, 1.0f);
+
+ snapGridIncrement(t, &crease);
+
+ applyNumInput(&t->num, &crease);
+
+ t->values_final[0] = crease;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ if (crease >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Crease: +%s %s"), c, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Crease: %s %s"), c, t->proptext);
+ }
+ }
+ else {
+ /* default header print */
+ if (crease >= 0.0f) {
+ BLI_snprintf(str, sizeof(str), TIP_("Crease: +%.3f %s"), crease, t->proptext);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Crease: %.3f %s"), crease, t->proptext);
+ }
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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_status_text(t->area, str);
+}
+
+void initCrease(TransInfo *t)
+{
+ t->mode = TFM_CREASE;
+ t->transform = applyCrease;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
new file mode 100644
index 00000000000..fde0d5b187e
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c
@@ -0,0 +1,156 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Normal Rotation) */
+
+/** \name Transform Normal Rotation
+ * \{ */
+
+static void storeCustomLNorValue(TransDataContainer *tc, BMesh *bm)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ // BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ tc->custom.mode.data = lnors_ed_arr;
+ tc->custom.mode.free_cb = freeCustomNormalArray;
+}
+
+void freeCustomNormalArray(TransInfo *t, TransDataContainer *tc, TransCustomData *custom_data)
+{
+ BMLoopNorEditDataArray *lnors_ed_arr = custom_data->data;
+
+ if (t->state == TRANS_CANCEL) {
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ /* Restore custom loop normal on cancel */
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->niloc, lnor_ed->clnors_data);
+ }
+ }
+
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+
+ tc->custom.mode.data = NULL;
+ tc->custom.mode.free_cb = NULL;
+}
+
+/* Works by getting custom normal from clnor_data, transform, then store */
+static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+
+ float axis_final[3];
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, NULL);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ BMLoopNorEditDataArray *lnors_ed_arr = tc->custom.mode.data;
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ float axis[3];
+ float mat[3][3];
+ float angle = t->values[0];
+ copy_v3_v3(axis, axis_final);
+
+ snapGridIncrement(t, &angle);
+
+ applySnapping(t, &angle);
+
+ applyNumInput(&t->num, &angle);
+
+ headerRotation(t, str, angle);
+
+ axis_angle_normalized_to_mat3(mat, axis, angle);
+
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ mul_v3_m3v3(lnor_ed->nloc, mat, lnor_ed->niloc);
+
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->nloc, lnor_ed->clnors_data);
+ }
+
+ t->values_final[0] = angle;
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initNormalRotation(TransInfo *t)
+{
+ t->mode = TFM_NORMAL_ROTATION;
+ t->transform = applyNormalRotation;
+
+ setInputPostFct(&t->mouse, postInputRotation);
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[2]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+
+ BKE_editmesh_ensure_autosmooth(em, tc->obedit->data);
+ BKE_editmesh_lnorspace_update(em, tc->obedit->data);
+
+ storeCustomLNorValue(tc, bm);
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
new file mode 100644
index 00000000000..ee91459dcdd
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c
@@ -0,0 +1,147 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Sequencer Slide) */
+
+/** \name Transform Sequencer Slide
+ * \{ */
+
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+ size_t ofs = 0;
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
+ }
+
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
+
+ if (t->keymap) {
+ wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
+ if (kmi) {
+ ofs += WM_keymap_item_to_string(kmi, false, str + ofs, UI_MAX_DRAW_STR - ofs);
+ }
+ }
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ TIP_(" or Alt) Expand to fit %s"),
+ WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
+}
+
+static void applySeqSlideValue(TransInfo *t, const float val[2])
+{
+ int i;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ madd_v2_v2v2fl(td->loc, td->iloc, val, td->factor);
+ }
+ }
+}
+
+static void applySeqSlide(TransInfo *t, const int mval[2])
+{
+ char str[UI_MAX_DRAW_STR];
+
+ snapSequenceBounds(t, mval);
+
+ if (t->con.mode & CON_APPLY) {
+ float pvec[3] = {0.0f, 0.0f, 0.0f};
+ float tvec[3];
+ t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec);
+ copy_v3_v3(t->values_final, tvec);
+ }
+ else {
+ // snapGridIncrement(t, t->values);
+ applyNumInput(&t->num, t->values);
+ copy_v3_v3(t->values_final, t->values);
+ }
+
+ t->values_final[0] = floorf(t->values_final[0] + 0.5f);
+ t->values_final[1] = floorf(t->values_final[1] + 0.5f);
+
+ headerSeqSlide(t, t->values_final, str);
+ applySeqSlideValue(t, t->values_final);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initSeqSlide(TransInfo *t)
+{
+ t->transform = applySeqSlide;
+
+ initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
+
+ t->idx_max = 1;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ t->snap[0] = 0.0f;
+ t->snap[1] = floorf(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
+ t->snap[2] = 10.0f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ /* Would be nice to have a time handling in units as well
+ * (supporting frames in addition to "natural" time...). */
+ t->num.unit_type[0] = B_UNIT_NONE;
+ t->num.unit_type[1] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c
new file mode 100644
index 00000000000..5613a782529
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_edge_slide.c
@@ -0,0 +1,1498 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+#include "BLI_utildefines_stack.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_editmesh_bvh.h"
+#include "BKE_unit.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Edge Slide) */
+
+/** \name Transform Edge Slide
+ * \{ */
+
+typedef struct TransDataEdgeSlideVert {
+ /** #TransDataGenericSlideVert (header) */
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ float v_co_orig[3];
+ /* end generic */
+
+ float edge_len;
+
+ struct BMVert *v_side[2];
+
+ /* add origvert.co to get the original locations */
+ float dir_side[2][3];
+
+ int loop_nr;
+} TransDataEdgeSlideVert;
+
+typedef struct EdgeSlideData {
+ TransDataEdgeSlideVert *sv;
+ int totsv;
+
+ int mval_start[2], mval_end[2];
+ int curr_sv_index;
+
+ /** when un-clamped - use this index: #TransDataEdgeSlideVert.dir_side */
+ int curr_side_unclamp;
+} EdgeSlideData;
+
+typedef struct EdgeSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} EdgeSlideParams;
+
+/**
+ * Get the first valid EdgeSlideData.
+ *
+ * Note we cannot trust TRANS_DATA_CONTAINER_FIRST_OK because of multi-object that
+ * may leave items with invalid custom data in the transform data container.
+ */
+static EdgeSlideData *edgeSlideFirstGet(TransInfo *t)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+ if (sld == NULL) {
+ continue;
+ }
+ return sld;
+ }
+ BLI_assert(!"Should never happen, at least one EdgeSlideData should be valid");
+ return NULL;
+}
+
+static void calcEdgeSlideCustomPoints(struct TransInfo *t)
+{
+ EdgeSlideData *sld = edgeSlideFirstGet(t);
+
+ setCustomPoints(t, &t->mouse, sld->mval_end, sld->mval_start);
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediately so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+}
+
+static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
+{
+ BMIter iter;
+ BMEdge *e_iter;
+
+ BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) {
+ return e_iter;
+ }
+ }
+
+ return NULL;
+}
+
+/* interpoaltes along a line made up of 2 segments (used for edge slide) */
+static void interp_line_v3_v3v3v3(
+ float p[3], const float v1[3], const float v2[3], const float v3[3], float t)
+{
+ float t_mid, t_delta;
+
+ /* could be pre-calculated */
+ t_mid = line_point_factor_v3(v2, v1, v3);
+
+ t_delta = t - t_mid;
+ if (t_delta < 0.0f) {
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v2);
+ }
+ else {
+ interp_v3_v3v3(p, v1, v2, t / t_mid);
+ }
+ }
+ else {
+ t = t - t_mid;
+ t_mid = 1.0f - t_mid;
+
+ if (UNLIKELY(fabsf(t_mid) < FLT_EPSILON)) {
+ copy_v3_v3(p, v3);
+ }
+ else {
+ interp_v3_v3v3(p, v2, v3, t / t_mid);
+ }
+ }
+}
+
+/**
+ * Find the closest point on the ngon on the opposite side.
+ * used to set the edge slide distance for ngons.
+ */
+static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], float r_co[3])
+{
+ /* skip adjacent edges */
+ BMLoop *l_first = l_tmp->next;
+ BMLoop *l_last = l_tmp->prev;
+ BMLoop *l_iter;
+ float dist = FLT_MAX;
+ bool found = false;
+
+ l_iter = l_first;
+ do {
+ float tvec[3];
+ if (isect_line_plane_v3(tvec, l_iter->v->co, l_iter->next->v->co, l_tmp->v->co, plane_no)) {
+ const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
+ /* allow some overlap to avoid missing the intersection because of float precision */
+ if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
+ /* likelihood of multiple intersections per ngon is quite low,
+ * it would have to loop back on its self, but better support it
+ * so check for the closest opposite edge */
+ const float tdist = len_v3v3(l_tmp->v->co, tvec);
+ if (tdist < dist) {
+ copy_v3_v3(r_co, tvec);
+ dist = tdist;
+ found = true;
+ }
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_last);
+
+ return found;
+}
+
+/**
+ * Given 2 edges and a loop, step over the loops
+ * and calculate a direction to slide along.
+ *
+ * \param r_slide_vec: the direction to slide,
+ * the length of the vector defines the slide distance.
+ */
+static BMLoop *get_next_loop(
+ BMVert *v, BMLoop *l, BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
+{
+ BMLoop *l_first;
+ float vec_accum[3] = {0.0f, 0.0f, 0.0f};
+ float vec_accum_len = 0.0f;
+ int i = 0;
+
+ BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
+ BLI_assert(BM_vert_in_edge(l->e, v));
+
+ l_first = l;
+ do {
+ l = BM_loop_other_edge_loop(l, v);
+
+ if (l->e == e_next) {
+ if (i) {
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
+ }
+ else {
+ /* When there is no edge to slide along,
+ * we must slide along the vector defined by the face we're attach to */
+ BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v);
+
+ BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next));
+
+ if (l_tmp->f->len == 4) {
+ /* we could use code below, but in this case
+ * sliding diagonally across the quad works well */
+ sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co);
+ }
+ else {
+ float tdir[3];
+ BM_loop_calc_face_direction(l_tmp, tdir);
+ cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
+#if 0
+ /* rough guess, we can do better! */
+ normalize_v3_length(vec_accum,
+ (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
+#else
+ /* be clever, check the opposite ngon edge to slide into.
+ * this gives best results */
+ {
+ float tvec[3];
+ float dist;
+
+ if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) {
+ dist = len_v3v3(l_tmp->v->co, tvec);
+ }
+ else {
+ dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
+ }
+
+ normalize_v3_length(vec_accum, dist);
+ }
+#endif
+ }
+ }
+
+ copy_v3_v3(r_slide_vec, vec_accum);
+ return l;
+ }
+ else {
+ /* accumulate the normalized edge vector,
+ * normalize so some edges don't skew the result */
+ float tvec[3];
+ sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co);
+ vec_accum_len += normalize_v3(tvec);
+ add_v3_v3(vec_accum, tvec);
+ i += 1;
+ }
+
+ if (BM_loop_other_edge_loop(l, v)->e == e_next) {
+ if (i) {
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
+ }
+
+ copy_v3_v3(r_slide_vec, vec_accum);
+ return BM_loop_other_edge_loop(l, v);
+ }
+
+ } while ((l != l->radial_next) && ((l = l->radial_next) != l_first));
+
+ if (i) {
+ normalize_v3_length(vec_accum, vec_accum_len / (float)i);
+ }
+
+ copy_v3_v3(r_slide_vec, vec_accum);
+
+ return NULL;
+}
+
+/**
+ * Calculate screenspace `mval_start` / `mval_end`, optionally slide direction.
+ */
+static void calcEdgeSlide_mval_range(TransInfo *t,
+ TransDataContainer *tc,
+ EdgeSlideData *sld,
+ const int *sv_table,
+ const int loop_nr,
+ const float mval[2],
+ const bool use_occlude_geometry,
+ const bool use_calc_direction)
+{
+ TransDataEdgeSlideVert *sv;
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ ARegion *region = t->region;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+ float projectMat[4][4];
+ BMBVHTree *bmbvh;
+
+ /* only for use_calc_direction */
+ float(*loop_dir)[3] = NULL, *loop_maxdist = NULL;
+
+ float mval_start[2], mval_end[2];
+ float mval_dir[3], dist_best_sq;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->area ? t->area->spacedata.first : NULL;
+ rv3d = t->region ? t->region->regiondata : NULL;
+ }
+
+ if (!rv3d) {
+ /* ok, let's try to survive this */
+ unit_m4(projectMat);
+ }
+ else {
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
+ }
+
+ if (use_occlude_geometry) {
+ bmbvh = BKE_bmbvh_new_from_editmesh(em, BMBVH_RESPECT_HIDDEN, NULL, false);
+ }
+ else {
+ bmbvh = NULL;
+ }
+
+ /* find mouse vectors, the global one, and one per loop in case we have
+ * multiple loops selected, in case they are oriented different */
+ zero_v3(mval_dir);
+ dist_best_sq = -1.0f;
+
+ if (use_calc_direction) {
+ loop_dir = MEM_callocN(sizeof(float[3]) * loop_nr, "sv loop_dir");
+ loop_maxdist = MEM_mallocN(sizeof(float) * loop_nr, "sv loop_maxdist");
+ copy_vn_fl(loop_maxdist, loop_nr, -1.0f);
+ }
+
+ sv = &sld->sv[0];
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ BMIter iter_other;
+ BMEdge *e;
+ BMVert *v = sv->v;
+
+ UNUSED_VARS_NDEBUG(sv_table); /* silence warning */
+ BLI_assert(i == sv_table[BM_elem_index_get(v)]);
+
+ /* search cross edges for visible edge to the mouse cursor,
+ * then use the shared vertex to calculate screen vector*/
+ BM_ITER_ELEM (e, &iter_other, v, BM_EDGES_OF_VERT) {
+ /* screen-space coords */
+ float sco_a[3], sco_b[3];
+ float dist_sq;
+ int l_nr;
+
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ continue;
+ }
+
+ /* This test is only relevant if object is not wire-drawn! See [#32068]. */
+ bool is_visible = !use_occlude_geometry ||
+ BMBVH_EdgeVisible(bmbvh, e, t->depsgraph, region, v3d, tc->obedit);
+
+ if (!is_visible && !use_calc_direction) {
+ continue;
+ }
+
+ if (sv->v_side[1]) {
+ ED_view3d_project_float_v3_m4(region, sv->v_side[1]->co, sco_b, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_b, v->co, sv->dir_side[1]);
+ ED_view3d_project_float_v3_m4(region, sco_b, sco_b, projectMat);
+ }
+
+ if (sv->v_side[0]) {
+ ED_view3d_project_float_v3_m4(region, sv->v_side[0]->co, sco_a, projectMat);
+ }
+ else {
+ add_v3_v3v3(sco_a, v->co, sv->dir_side[0]);
+ ED_view3d_project_float_v3_m4(region, sco_a, sco_a, projectMat);
+ }
+
+ /* global direction */
+ dist_sq = dist_squared_to_line_segment_v2(mval, sco_b, sco_a);
+ if (is_visible) {
+ if ((dist_best_sq == -1.0f) ||
+ /* intentionally use 2d size on 3d vector */
+ (dist_sq < dist_best_sq && (len_squared_v2v2(sco_b, sco_a) > 0.1f))) {
+ dist_best_sq = dist_sq;
+ sub_v3_v3v3(mval_dir, sco_b, sco_a);
+ }
+ }
+
+ if (use_calc_direction) {
+ /* per loop direction */
+ l_nr = sv->loop_nr;
+ if (loop_maxdist[l_nr] == -1.0f || dist_sq < loop_maxdist[l_nr]) {
+ loop_maxdist[l_nr] = dist_sq;
+ sub_v3_v3v3(loop_dir[l_nr], sco_b, sco_a);
+ }
+ }
+ }
+ }
+
+ if (use_calc_direction) {
+ int i;
+ sv = &sld->sv[0];
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ /* switch a/b if loop direction is different from global direction */
+ int l_nr = sv->loop_nr;
+ if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
+ swap_v3_v3(sv->dir_side[0], sv->dir_side[1]);
+ SWAP(BMVert *, sv->v_side[0], sv->v_side[1]);
+ }
+ }
+
+ MEM_freeN(loop_dir);
+ MEM_freeN(loop_maxdist);
+ }
+
+ /* possible all of the edge loops are pointing directly at the view */
+ if (UNLIKELY(len_squared_v2(mval_dir) < 0.1f)) {
+ mval_dir[0] = 0.0f;
+ mval_dir[1] = 100.0f;
+ }
+
+ /* zero out start */
+ zero_v2(mval_start);
+
+ /* dir holds a vector along edge loop */
+ copy_v2_v2(mval_end, mval_dir);
+ mul_v2_fl(mval_end, 0.5f);
+
+ sld->mval_start[0] = t->mval[0] + mval_start[0];
+ sld->mval_start[1] = t->mval[1] + mval_start[1];
+
+ sld->mval_end[0] = t->mval[0] + mval_end[0];
+ sld->mval_end[1] = t->mval[1] + mval_end[1];
+
+ if (bmbvh) {
+ BKE_bmbvh_free(bmbvh);
+ }
+}
+
+static void calcEdgeSlide_even(TransInfo *t,
+ TransDataContainer *tc,
+ EdgeSlideData *sld,
+ const float mval[2])
+{
+ TransDataEdgeSlideVert *sv = sld->sv;
+
+ if (sld->totsv > 0) {
+ ARegion *region = t->region;
+ RegionView3D *rv3d = NULL;
+ float projectMat[4][4];
+
+ int i = 0;
+
+ float v_proj[2];
+ float dist_sq = 0;
+ float dist_min_sq = FLT_MAX;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ rv3d = t->region ? t->region->regiondata : NULL;
+ }
+
+ if (!rv3d) {
+ /* ok, let's try to survive this */
+ unit_m4(projectMat);
+ }
+ else {
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, projectMat);
+ }
+
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ /* Set length */
+ sv->edge_len = len_v3v3(sv->dir_side[0], sv->dir_side[1]);
+
+ ED_view3d_project_float_v2_m4(region, sv->v->co, v_proj, projectMat);
+ dist_sq = len_squared_v2v2(mval, v_proj);
+ if (dist_sq < dist_min_sq) {
+ dist_min_sq = dist_sq;
+ sld->curr_sv_index = i;
+ }
+ }
+ }
+ else {
+ sld->curr_sv_index = 0;
+ }
+}
+
+static bool createEdgeSlideVerts_double_side(TransInfo *t, TransDataContainer *tc)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ BMVert *v;
+ TransDataEdgeSlideVert *sv_array;
+ int sv_tot;
+ int *sv_table; /* BMVert -> sv_array index */
+ EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int numsel, i, loop_nr;
+ bool use_occlude_geometry = false;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+
+ sld->curr_sv_index = 0;
+
+ /*ensure valid selection*/
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BMIter iter2;
+ numsel = 0;
+ BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ /* BMESH_TODO: this is probably very evil,
+ * set v->e to a selected edge*/
+ v->e = e;
+
+ numsel++;
+ }
+ }
+
+ if (numsel == 0 || numsel > 2) {
+ MEM_freeN(sld);
+ return false; /* invalid edge selection */
+ }
+ }
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ /* note, any edge with loops can work, but we won't get predictable results, so bail out */
+ if (!BM_edge_is_manifold(e) && !BM_edge_is_boundary(e)) {
+ /* can edges with at least once face user */
+ MEM_freeN(sld);
+ return false;
+ }
+ }
+ }
+
+ sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
+
+#define INDEX_UNSET -1
+#define INDEX_INVALID -2
+
+ {
+ int j = 0;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_UNSET;
+ j += 1;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ sv_table[i] = INDEX_INVALID;
+ }
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ if (!j) {
+ MEM_freeN(sld);
+ MEM_freeN(sv_table);
+ return false;
+ }
+ sv_tot = j;
+ }
+
+ sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
+ loop_nr = 0;
+
+ STACK_DECLARE(sv_array);
+ STACK_INIT(sv_array, sv_tot);
+
+ while (1) {
+ float vec_a[3], vec_b[3];
+ BMLoop *l_a, *l_b;
+ BMLoop *l_a_prev, *l_b_prev;
+ BMVert *v_first;
+ /* If this succeeds call get_next_loop()
+ * which calculates the direction to slide based on clever checks.
+ *
+ * otherwise we simply use 'e_dir' as an edge-rail.
+ * (which is better when the attached edge is a boundary, see: T40422)
+ */
+#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \
+ ((BM_edge_is_boundary(e_dir) == false) && (BM_vert_edge_count_nonwire(v) == 2))
+
+ v = NULL;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ break;
+ }
+ }
+
+ if (!v) {
+ break;
+ }
+
+ if (!v->e) {
+ continue;
+ }
+
+ v_first = v;
+
+ /*walk along the edge loop*/
+ e = v->e;
+
+ /*first, rewind*/
+ do {
+ e = get_other_edge(v, e);
+ if (!e) {
+ e = v->e;
+ break;
+ }
+
+ if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG)) {
+ break;
+ }
+
+ v = BM_edge_other_vert(e, v);
+ } while (e != v_first->e);
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ l_a = e->l;
+ l_b = e->l->radial_next;
+
+ /* regarding e_next, use get_next_loop()'s improved interpolation where possible */
+ {
+ BMEdge *e_next = get_other_edge(v, e);
+ if (e_next) {
+ get_next_loop(v, l_a, e, e_next, vec_a);
+ }
+ else {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
+ get_next_loop(v, l_a, e, l_tmp->e, vec_a);
+ }
+ else {
+ sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ }
+ }
+ }
+
+ /* !BM_edge_is_boundary(e); */
+ if (l_b != l_a) {
+ BMEdge *e_next = get_other_edge(v, e);
+ if (e_next) {
+ get_next_loop(v, l_b, e, e_next, vec_b);
+ }
+ else {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
+ get_next_loop(v, l_b, e, l_tmp->e, vec_b);
+ }
+ else {
+ sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ }
+ }
+ }
+ else {
+ l_b = NULL;
+ }
+
+ l_a_prev = NULL;
+ l_b_prev = NULL;
+
+#define SV_FROM_VERT(v) \
+ ((sv_table[BM_elem_index_get(v)] == INDEX_UNSET) ? \
+ ((void)(sv_table[BM_elem_index_get(v)] = STACK_SIZE(sv_array)), \
+ STACK_PUSH_RET_PTR(sv_array)) : \
+ (&sv_array[sv_table[BM_elem_index_get(v)]]))
+
+ /*iterate over the loop*/
+ v_first = v;
+ do {
+ bool l_a_ok_prev;
+ bool l_b_ok_prev;
+ TransDataEdgeSlideVert *sv;
+ BMVert *v_prev;
+ BMEdge *e_prev;
+
+ /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
+ BLI_assert(v != NULL);
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->loop_nr = loop_nr;
+
+ if (l_a || l_a_prev) {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_a ? l_a : l_a_prev, v);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[0], vec_a);
+ }
+
+ if (l_b || l_b_prev) {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_b ? l_b : l_b_prev, v);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
+ copy_v3_v3(sv->dir_side[1], vec_b);
+ }
+
+ v_prev = v;
+ v = BM_edge_other_vert(e, v);
+
+ e_prev = e;
+ e = get_other_edge(v, e);
+
+ if (!e) {
+ BLI_assert(v != NULL);
+
+ BLI_assert(sv_table[BM_elem_index_get(v)] != INDEX_INVALID);
+ sv = SV_FROM_VERT(v);
+
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->loop_nr = loop_nr;
+
+ if (l_a) {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+ sv->v_side[0] = BM_edge_other_vert(l_tmp->e, v);
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
+ get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_side[0]);
+ }
+ else {
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
+ }
+ }
+
+ if (l_b) {
+ BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+ sv->v_side[1] = BM_edge_other_vert(l_tmp->e, v);
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
+ get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_side[1]);
+ }
+ else {
+ sub_v3_v3v3(sv->dir_side[1], sv->v_side[1]->co, v->co);
+ }
+ }
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
+
+ break;
+ }
+ l_a_ok_prev = (l_a != NULL);
+ l_b_ok_prev = (l_b != NULL);
+
+ l_a_prev = l_a;
+ l_b_prev = l_b;
+
+ if (l_a) {
+ l_a = get_next_loop(v, l_a, e_prev, e, vec_a);
+ }
+ else {
+ zero_v3(vec_a);
+ }
+
+ if (l_b) {
+ l_b = get_next_loop(v, l_b, e_prev, e, vec_b);
+ }
+ else {
+ zero_v3(vec_b);
+ }
+
+ if (l_a && l_b) {
+ /* pass */
+ }
+ else {
+ if (l_a || l_b) {
+ /* find the opposite loop if it was missing previously */
+ if (l_a == NULL && l_b && (l_b->radial_next != l_b)) {
+ l_a = l_b->radial_next;
+ }
+ else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) {
+ l_b = l_a->radial_next;
+ }
+ }
+ else if (e->l != NULL) {
+ /* if there are non-contiguous faces, we can still recover
+ * the loops of the new edges faces */
+
+ /* note!, the behavior in this case means edges may move in opposite directions,
+ * this could be made to work more usefully. */
+
+ if (l_a_ok_prev) {
+ l_a = e->l;
+ l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL;
+ }
+ else if (l_b_ok_prev) {
+ l_b = e->l;
+ l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL;
+ }
+ }
+
+ if (!l_a_ok_prev && l_a) {
+ get_next_loop(v, l_a, e, e_prev, vec_a);
+ }
+ if (!l_b_ok_prev && l_b) {
+ get_next_loop(v, l_b, e, e_prev, vec_b);
+ }
+ }
+
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ BM_elem_flag_disable(v_prev, BM_ELEM_TAG);
+ } while ((e != v_first->e) && (l_a || l_b));
+
+#undef SV_FROM_VERT
+#undef INDEX_UNSET
+#undef INDEX_INVALID
+
+ loop_nr++;
+
+#undef EDGESLIDE_VERT_IS_INNER
+ }
+
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+
+ BLI_assert(STACK_SIZE(sv_array) == sv_tot);
+
+ sld->sv = sv_array;
+ sld->totsv = sv_tot;
+
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->area ? t->area->spacedata.first : NULL;
+ rv3d = t->region ? t->region->regiondata : NULL;
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
+ !XRAY_ENABLED(v3d));
+ }
+
+ calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, true);
+
+ if (rv3d) {
+ calcEdgeSlide_even(t, tc, sld, mval);
+ }
+
+ tc->custom.mode.data = sld;
+
+ MEM_freeN(sv_table);
+
+ return true;
+}
+
+/**
+ * A simple version of #createEdgeSlideVerts_double_side
+ * Which assumes the longest unselected.
+ */
+static bool createEdgeSlideVerts_single_side(TransInfo *t, TransDataContainer *tc)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ TransDataEdgeSlideVert *sv_array;
+ int sv_tot;
+ int *sv_table; /* BMVert -> sv_array index */
+ EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
+ int loop_nr;
+ bool use_occlude_geometry = false;
+ View3D *v3d = NULL;
+ RegionView3D *rv3d = NULL;
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* background mode support */
+ v3d = t->area ? t->area->spacedata.first : NULL;
+ rv3d = t->region ? t->region->regiondata : NULL;
+ }
+
+ sld->curr_sv_index = 0;
+ /* ensure valid selection */
+ {
+ int i = 0, j = 0;
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float len_sq_max = -1.0f;
+ BMIter iter2;
+ BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float len_sq = BM_edge_calc_length_squared(e);
+ if (len_sq > len_sq_max) {
+ len_sq_max = len_sq;
+ v->e = e;
+ }
+ }
+ }
+
+ if (len_sq_max != -1.0f) {
+ j++;
+ }
+ }
+ BM_elem_index_set(v, i); /* set_inline */
+ }
+ bm->elem_index_dirty &= ~BM_VERT;
+
+ if (!j) {
+ MEM_freeN(sld);
+ return false;
+ }
+
+ sv_tot = j;
+ }
+
+ BLI_assert(sv_tot != 0);
+ /* over alloc */
+ sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * bm->totvertsel, "sv_array");
+
+ /* same loop for all loops, weak but we dont connect loops in this case */
+ loop_nr = 1;
+
+ sv_table = MEM_mallocN(sizeof(*sv_table) * bm->totvert, __func__);
+
+ {
+ int i = 0, j = 0;
+ BMVert *v;
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ sv_table[i] = -1;
+ if ((v->e != NULL) && (BM_elem_flag_test(v, BM_ELEM_SELECT))) {
+ if (BM_elem_flag_test(v->e, BM_ELEM_SELECT) == 0) {
+ TransDataEdgeSlideVert *sv;
+ sv = &sv_array[j];
+ sv->v = v;
+ copy_v3_v3(sv->v_co_orig, v->co);
+ sv->v_side[0] = BM_edge_other_vert(v->e, v);
+ sub_v3_v3v3(sv->dir_side[0], sv->v_side[0]->co, v->co);
+ sv->loop_nr = 0;
+ sv_table[i] = j;
+ j += 1;
+ }
+ }
+ }
+ }
+
+ /* check for wire vertices,
+ * interpolate the directions of wire verts between non-wire verts */
+ if (sv_tot != bm->totvert) {
+ const int sv_tot_nowire = sv_tot;
+ TransDataEdgeSlideVert *sv_iter = sv_array;
+
+ for (int i = 0; i < sv_tot_nowire; i++, sv_iter++) {
+ BMIter eiter;
+ BM_ITER_ELEM (e, &eiter, sv_iter->v, BM_EDGES_OF_VERT) {
+ /* walk over wire */
+ TransDataEdgeSlideVert *sv_end = NULL;
+ BMEdge *e_step = e;
+ BMVert *v = sv_iter->v;
+ int j;
+
+ j = sv_tot;
+
+ while (1) {
+ BMVert *v_other = BM_edge_other_vert(e_step, v);
+ int endpoint = ((sv_table[BM_elem_index_get(v_other)] != -1) +
+ (BM_vert_is_edge_pair(v_other) == false));
+
+ if ((BM_elem_flag_test(e_step, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(v_other, BM_ELEM_SELECT)) &&
+ (endpoint == 0)) {
+ /* scan down the list */
+ TransDataEdgeSlideVert *sv;
+ BLI_assert(sv_table[BM_elem_index_get(v_other)] == -1);
+ sv_table[BM_elem_index_get(v_other)] = j;
+ sv = &sv_array[j];
+ sv->v = v_other;
+ copy_v3_v3(sv->v_co_orig, v_other->co);
+ copy_v3_v3(sv->dir_side[0], sv_iter->dir_side[0]);
+ j++;
+
+ /* advance! */
+ v = v_other;
+ e_step = BM_DISK_EDGE_NEXT(e_step, v_other);
+ }
+ else {
+ if ((endpoint == 2) && (sv_tot != j)) {
+ BLI_assert(BM_elem_index_get(v_other) != -1);
+ sv_end = &sv_array[sv_table[BM_elem_index_get(v_other)]];
+ }
+ break;
+ }
+ }
+
+ if (sv_end) {
+ int sv_tot_prev = sv_tot;
+ const float *co_src = sv_iter->v->co;
+ const float *co_dst = sv_end->v->co;
+ const float *dir_src = sv_iter->dir_side[0];
+ const float *dir_dst = sv_end->dir_side[0];
+ sv_tot = j;
+
+ while (j-- != sv_tot_prev) {
+ float factor;
+ factor = line_point_factor_v3(sv_array[j].v->co, co_src, co_dst);
+ interp_v3_v3v3(sv_array[j].dir_side[0], dir_src, dir_dst, factor);
+ }
+ }
+ }
+ }
+ }
+
+ /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
+
+ sld->sv = sv_array;
+ sld->totsv = sv_tot;
+
+ /* use for visibility checks */
+ if (t->spacetype == SPACE_VIEW3D) {
+ v3d = t->area ? t->area->spacedata.first : NULL;
+ rv3d = t->region ? t->region->regiondata : NULL;
+ use_occlude_geometry = (v3d && TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->dt > OB_WIRE &&
+ !XRAY_ENABLED(v3d));
+ }
+
+ calcEdgeSlide_mval_range(t, tc, sld, sv_table, loop_nr, mval, use_occlude_geometry, false);
+
+ if (rv3d) {
+ calcEdgeSlide_even(t, tc, sld, mval);
+ }
+
+ tc->custom.mode.data = sld;
+
+ MEM_freeN(sv_table);
+
+ return true;
+}
+
+void projectEdgeSlideData(TransInfo *t, bool is_final)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
+ if (sld == NULL) {
+ continue;
+ }
+
+ trans_mesh_customdata_correction_apply(tc, is_final);
+ }
+}
+
+static void freeEdgeSlideVerts(TransInfo *UNUSED(t),
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ EdgeSlideData *sld = custom_data->data;
+
+ if (sld == NULL) {
+ return;
+ }
+
+ MEM_freeN(sld->sv);
+ MEM_freeN(sld);
+
+ custom_data->data = NULL;
+}
+
+static eRedrawFlag handleEventEdgeSlide(struct TransInfo *t, const struct wmEvent *event)
+{
+ if (t->mode == TFM_EDGE_SLIDE) {
+ EdgeSlideParams *slp = t->custom.mode.data;
+
+ if (slp) {
+ switch (event->type) {
+ case EVT_EKEY:
+ if (event->val == KM_PRESS) {
+ slp->use_even = !slp->use_even;
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case EVT_FKEY:
+ if (event->val == KM_PRESS) {
+ slp->flipped = !slp->flipped;
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case EVT_CKEY:
+ /* use like a modifier key */
+ if (event->val == KM_PRESS) {
+ t->flag ^= T_ALT_TRANSFORM;
+ calcEdgeSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case EVT_MODAL_MAP:
+#if 0
+ switch (event->val) {
+ case TFM_MODAL_EDGESLIDE_DOWN:
+ sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
+ return TREDRAW_HARD;
+ case TFM_MODAL_EDGESLIDE_UP:
+ sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
+ return TREDRAW_HARD;
+ }
+#endif
+ break;
+ case MOUSEMOVE:
+ calcEdgeSlideCustomPoints(t);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return TREDRAW_NOTHING;
+}
+
+void drawEdgeSlide(TransInfo *t)
+{
+ if ((t->mode == TFM_EDGE_SLIDE) && edgeSlideFirstGet(t)) {
+ const EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld = edgeSlideFirstGet(t);
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
+ /* Even mode */
+ if ((slp->use_even == true) || (is_clamp == false)) {
+ const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
+
+ GPU_depth_test(false);
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+
+ if (slp->use_even == true) {
+ float co_a[3], co_b[3], co_mark[3];
+ TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+ const float fac = (slp->perc + 1.0f) / 2.0f;
+ const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+ const float guide_size = ctrl_size - 0.5f;
+ const int alpha_shade = -30;
+
+ add_v3_v3v3(co_a, curr_sv->v_co_orig, curr_sv->dir_side[0]);
+ add_v3_v3v3(co_b, curr_sv->v_co_orig, curr_sv->dir_side[1]);
+
+ GPU_line_width(line_size);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBeginAtMost(GPU_PRIM_LINES, 4);
+ if (curr_sv->v_side[0]) {
+ immVertex3fv(pos, curr_sv->v_side[0]->co);
+ immVertex3fv(pos, curr_sv->v_co_orig);
+ }
+ if (curr_sv->v_side[1]) {
+ immVertex3fv(pos, curr_sv->v_side[1]->co);
+ immVertex3fv(pos, curr_sv->v_co_orig);
+ }
+ immEnd();
+
+ {
+ float *co_test = NULL;
+ if (slp->flipped) {
+ if (curr_sv->v_side[1]) {
+ co_test = curr_sv->v_side[1]->co;
+ }
+ }
+ else {
+ if (curr_sv->v_side[0]) {
+ co_test = curr_sv->v_side[0]->co;
+ }
+ }
+
+ if (co_test != NULL) {
+ immUniformThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
+ GPU_point_size(ctrl_size);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(pos, co_test);
+ immEnd();
+ }
+ }
+
+ immUniformThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
+ GPU_point_size(guide_size);
+ immBegin(GPU_PRIM_POINTS, 1);
+ interp_line_v3_v3v3v3(co_mark, co_b, curr_sv->v_co_orig, co_a, fac);
+ immVertex3fv(pos, co_mark);
+ immEnd();
+ }
+ else {
+ if (is_clamp == false) {
+ const int side_index = sld->curr_side_unclamp;
+ TransDataEdgeSlideVert *sv;
+ int i;
+ const int alpha_shade = -160;
+
+ GPU_line_width(line_size);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+ immBegin(GPU_PRIM_LINES, sld->totsv * 2);
+
+ /* TODO(campbell): Loop over all verts */
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float a[3], b[3];
+
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(a, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(a, sv->dir_side[!side_index]);
+ }
+
+ mul_v3_fl(a, 100.0f);
+ negate_v3_v3(b, a);
+ add_v3_v3(a, sv->v_co_orig);
+ add_v3_v3(b, sv->v_co_orig);
+
+ immVertex3fv(pos, a);
+ immVertex3fv(pos, b);
+ }
+ immEnd();
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ immUnbindProgram();
+
+ GPU_matrix_pop();
+
+ GPU_blend(false);
+
+ GPU_depth_test(true);
+ }
+ }
+}
+
+void doEdgeSlide(TransInfo *t, float perc)
+{
+ EdgeSlideParams *slp = t->custom.mode.data;
+ EdgeSlideData *sld_active = edgeSlideFirstGet(t);
+
+ slp->perc = perc;
+
+ if (slp->use_even == false) {
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ if (is_clamp) {
+ const int side_index = (perc < 0.0f);
+ const float perc_final = fabsf(perc);
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
+ if (sld == NULL) {
+ continue;
+ }
+
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, sv->dir_side[side_index], perc_final);
+ }
+ sld->curr_side_unclamp = side_index;
+ }
+ }
+ else {
+ const float perc_init = fabsf(perc) *
+ ((sld_active->curr_side_unclamp == (perc < 0.0f)) ? 1 : -1);
+ const int side_index = sld_active->curr_side_unclamp;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
+ if (sld == NULL) {
+ continue;
+ }
+
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ float dir_flip[3];
+ float perc_final = perc_init;
+ if (!is_zero_v3(sv->dir_side[side_index])) {
+ copy_v3_v3(dir_flip, sv->dir_side[side_index]);
+ }
+ else {
+ copy_v3_v3(dir_flip, sv->dir_side[!side_index]);
+ perc_final *= -1;
+ }
+ madd_v3_v3v3fl(sv->v->co, sv->v_co_orig, dir_flip, perc_final);
+ }
+ }
+ }
+ }
+ else {
+ /**
+ * Implementation note, even mode ignores the starting positions and uses
+ * only the a/b verts, this could be changed/improved so the distance is
+ * still met but the verts are moved along their original path (which may not be straight),
+ * however how it works now is OK and matches 2.4x - Campbell
+ *
+ * \note `len_v3v3(curr_sv->dir_side[0], curr_sv->dir_side[1])`
+ * is the same as the distance between the original vert locations,
+ * same goes for the lines below.
+ */
+ TransDataEdgeSlideVert *curr_sv = &sld_active->sv[sld_active->curr_sv_index];
+ const float curr_length_perc = curr_sv->edge_len *
+ (((slp->flipped ? perc : -perc) + 1.0f) / 2.0f);
+
+ float co_a[3];
+ float co_b[3];
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ EdgeSlideData *sld = tc->custom.mode.data;
+
+ if (sld == NULL) {
+ continue;
+ }
+
+ TransDataEdgeSlideVert *sv = sld->sv;
+ for (int i = 0; i < sld->totsv; i++, sv++) {
+ if (sv->edge_len > FLT_EPSILON) {
+ const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
+
+ add_v3_v3v3(co_a, sv->v_co_orig, sv->dir_side[0]);
+ add_v3_v3v3(co_b, sv->v_co_orig, sv->dir_side[1]);
+
+ if (slp->flipped) {
+ interp_line_v3_v3v3v3(sv->v->co, co_b, sv->v_co_orig, co_a, fac);
+ }
+ else {
+ interp_line_v3_v3v3v3(sv->v->co, co_a, sv->v_co_orig, co_b, fac);
+ }
+ }
+ }
+ }
+ }
+}
+
+static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+ size_t ofs = 0;
+ float final;
+ EdgeSlideParams *slp = t->custom.mode.data;
+ bool flipped = slp->flipped;
+ bool use_even = slp->use_even;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
+
+ final = t->values[0];
+
+ snapGridIncrement(t, &final);
+
+ /* only do this so out of range values are not displayed */
+ if (is_constrained) {
+ CLAMP(final, -1.0f, 1.0f);
+ }
+
+ applyNumInput(&t->num, &final);
+
+ t->values_final[0] = final;
+
+ /* header string */
+ ofs += BLI_strncpy_rlen(str + ofs, TIP_("Edge Slide: "), sizeof(str) - ofs);
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
+ }
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ if (use_even) {
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ }
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ /* done with header string */
+
+ /* do stuff here */
+ doEdgeSlide(t, final);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initEdgeSlide_ex(
+ TransInfo *t, bool use_double_side, bool use_even, bool flipped, bool use_clamp)
+{
+ EdgeSlideData *sld;
+ bool ok = false;
+
+ t->mode = TFM_EDGE_SLIDE;
+ t->transform = applyEdgeSlide;
+ t->handleEvent = handleEventEdgeSlide;
+
+ {
+ EdgeSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ /* happens to be best for single-sided */
+ if (use_double_side == false) {
+ slp->flipped = !flipped;
+ }
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
+ }
+
+ if (use_double_side) {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_double_side(t, tc);
+ }
+ }
+ else {
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createEdgeSlideVerts_single_side(t, tc);
+ }
+ }
+
+ if (!ok) {
+ t->state = TRANS_CANCEL;
+ return;
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ sld = tc->custom.mode.data;
+ if (!sld) {
+ continue;
+ }
+ tc->custom.mode.free_cb = freeEdgeSlideVerts;
+ }
+
+ trans_mesh_customdata_correction_init(t);
+
+ /* set custom point first if you want value to be initialized by init */
+ calcEdgeSlideCustomPoints(t);
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+
+void initEdgeSlide(TransInfo *t)
+{
+ initEdgeSlide_ex(t, true, false, false, true);
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c
new file mode 100644
index 00000000000..267d297a31c
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_gpopacity.c
@@ -0,0 +1,120 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (GPencil Opacity) */
+
+/** \name Transform GPencil Strokes Opacity
+ * \{ */
+
+static void applyGPOpacity(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float ratio;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, sizeof(str), TIP_("Opacity: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Opacity: %3f"), ratio);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ CLAMP(*td->val, 0.0f, 1.0f);
+ }
+ }
+ }
+
+ ED_area_status_text(t->area, str);
+}
+
+void initGPOpacity(TransInfo *t)
+{
+ t->mode = TFM_GPENCIL_OPACITY;
+ t->transform = applyGPOpacity;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
new file mode 100644
index 00000000000..7c49d107703
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c
@@ -0,0 +1,122 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (GPencil Shrink/Fatten) */
+
+/** \name Transform GPencil Strokes Shrink/Fatten
+ * \{ */
+
+static void applyGPShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float ratio;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Shrink/Fatten: %3f"), ratio);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (td->val) {
+ *td->val = td->ival * ratio;
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) {
+ *td->val = 0.001f;
+ }
+ }
+ }
+ }
+
+ ED_area_status_text(t->area, str);
+}
+
+void initGPShrinkFatten(TransInfo *t)
+{
+ t->mode = TFM_GPENCIL_SHRINKFATTEN;
+ t->transform = applyGPShrinkFatten;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_maskshrinkfatten.c b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
new file mode 100644
index 00000000000..e42439920db
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_maskshrinkfatten.c
@@ -0,0 +1,154 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Mask Shrink/Fatten) */
+
+/** \name Transform Mask Shrink/Fatten
+ * \{ */
+
+static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float ratio;
+ int i;
+ bool initial_feather = false;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %s"), c);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Feather Shrink/Fatten: %3f"), ratio);
+ }
+
+ /* detect if no points have feather yet */
+ if (ratio > 1.0f) {
+ initial_feather = true;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (td->ival >= 0.001f) {
+ initial_feather = false;
+ }
+ }
+ }
+ }
+
+ /* apply shrink/fatten */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (td = tc->data, i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (td->val) {
+ if (initial_feather) {
+ *td->val = td->ival + (ratio - 1.0f) * 0.01f;
+ }
+ else {
+ *td->val = td->ival * ratio;
+ }
+
+ /* apply PET */
+ *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
+ if (*td->val <= 0.0f) {
+ *td->val = 0.001f;
+ }
+ }
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initMaskShrinkFatten(TransInfo *t)
+{
+ t->mode = TFM_MASK_SHRINKFATTEN;
+ t->transform = applyMaskShrinkFatten;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c
new file mode 100644
index 00000000000..dae17374481
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_mirror.c
@@ -0,0 +1,129 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Mirror) */
+
+/** \name Transform Mirror
+ * \{ */
+
+static void applyMirror(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float size[3], mat[3][3];
+ int i;
+ char str[UI_MAX_DRAW_STR];
+ copy_v3_v3(t->values_final, t->values);
+
+ /* OPTIMIZATION:
+ * This still recalculates transformation on mouse move
+ * while it should only recalculate on constraint change. */
+
+ /* if an axis has been selected */
+ if (t->con.mode & CON_APPLY) {
+ size[0] = size[1] = size[2] = -1;
+
+ size_to_mat3(mat, size);
+
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, NULL, mat);
+ }
+
+ BLI_snprintf(str, sizeof(str), TIP_("Mirror%s"), t->con.text);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ ElementResize(t, tc, td, mat);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+ }
+ else {
+ size[0] = size[1] = size[2] = 1;
+
+ size_to_mat3(mat, size);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ ElementResize(t, tc, td, mat);
+ }
+ }
+
+ recalcData(t);
+
+ if (t->flag & T_2D_EDIT) {
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y)"));
+ }
+ else {
+ ED_area_status_text(t->area, TIP_("Select a mirror axis (X, Y, Z)"));
+ }
+ }
+}
+
+void initMirror(TransInfo *t)
+{
+ t->transform = applyMirror;
+ initMouseInputMode(t, &t->mouse, INPUT_NONE);
+
+ t->flag |= T_NULL_ONE;
+ if ((t->flag & T_EDIT) == 0) {
+ t->flag |= T_NO_ZERO;
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_push_pull.c b/source/blender/editors/transform/transform_mode_push_pull.c
new file mode 100644
index 00000000000..6eb038ea9b0
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_push_pull.c
@@ -0,0 +1,137 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_constraints.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Push/Pull) */
+
+/** \name Transform Push/Pull
+ * \{ */
+
+static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float vec[3], axis_global[3];
+ float distance;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ distance = t->values[0];
+
+ snapGridIncrement(t, &distance);
+
+ applyNumInput(&t->num, &distance);
+
+ t->values_final[0] = distance;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str, sizeof(str), TIP_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
+ }
+ else {
+ /* default header print */
+ BLI_snprintf(
+ str, sizeof(str), TIP_("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, NULL, axis_global, NULL);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ sub_v3_v3v3(vec, tc->center_local, td->center);
+ if (t->con.applyRot && t->con.mode & CON_APPLY) {
+ float axis[3];
+ copy_v3_v3(axis, axis_global);
+ t->con.applyRot(t, tc, td, axis, NULL);
+
+ mul_m3_v3(td->smtx, axis);
+ if (isLockConstraint(t)) {
+ float dvec[3];
+ project_v3_v3v3(dvec, vec, axis);
+ sub_v3_v3(vec, dvec);
+ }
+ else {
+ project_v3_v3v3(vec, vec, axis);
+ }
+ }
+ normalize_v3_length(vec, distance * td->factor);
+
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initPushPull(TransInfo *t)
+{
+ t->mode = TFM_PUSHPULL;
+ t->transform = applyPushPull;
+
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_LENGTH;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_resize.c b/source/blender/editors/transform/transform_mode_resize.c
new file mode 100644
index 00000000000..00644b9bfdc
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_resize.c
@@ -0,0 +1,170 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_constraints.h"
+#include "transform_convert.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Resize) */
+
+/** \name Transform Resize
+ * \{ */
+
+static void applyResize(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float mat[3][3];
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ if (t->flag & T_INPUT_IS_VALUES_FINAL) {
+ copy_v3_v3(t->values_final, t->values);
+ }
+ else {
+ float ratio = t->values[0];
+
+ copy_v3_fl(t->values_final, ratio);
+
+ snapGridIncrement(t, t->values_final);
+
+ if (applyNumInput(&t->num, t->values_final)) {
+ constraintNumInput(t, t->values_final);
+ }
+
+ applySnapping(t, t->values_final);
+ }
+
+ size_to_mat3(mat, t->values_final);
+ if (t->con.mode & CON_APPLY) {
+ t->con.applySize(t, NULL, NULL, mat);
+
+ /* Only so we have re-usable value with redo. */
+ float pvec[3] = {0.0f, 0.0f, 0.0f};
+ int j = 0;
+ for (i = 0; i < 3; i++) {
+ if (!(t->con.mode & (CON_AXIS0 << i))) {
+ t->values_final[i] = 1.0f;
+ }
+ else {
+ pvec[j++] = t->values_final[i];
+ }
+ }
+ headerResize(t, pvec, str);
+ }
+ else {
+ headerResize(t, t->values_final, str);
+ }
+
+ copy_m3_m3(t->mat, mat); // used in gizmo
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ ElementResize(t, tc, td, mat);
+ }
+ }
+
+ /* evil hack - redo resize if cliping needed */
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values_final, 1)) {
+ size_to_mat3(mat, t->values_final);
+
+ if (t->con.mode & CON_APPLY) {
+ t->con.applySize(t, NULL, NULL, mat);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ ElementResize(t, tc, td, mat);
+ }
+
+ /* In proportional edit it can happen that */
+ /* vertices in the radius of the brush end */
+ /* outside the clipping area */
+ /* XXX HACK - dg */
+ if (t->flag & T_PROP_EDIT_ALL) {
+ clipUVData(t);
+ }
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initResize(TransInfo *t)
+{
+ t->mode = TFM_RESIZE;
+ t->transform = applyResize;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+
+ t->flag |= T_NULL_ONE;
+ t->num.val_flag[0] |= NUM_NULL_ONE;
+ t->num.val_flag[1] |= NUM_NULL_ONE;
+ t->num.val_flag[2] |= NUM_NULL_ONE;
+ t->num.flag |= NUM_AFFECT_ALL;
+ if ((t->flag & T_EDIT) == 0) {
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+ t->num.val_flag[1] |= NUM_NO_ZERO;
+ t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
+ }
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+ t->num.unit_type[1] = B_UNIT_NONE;
+ t->num.unit_type[2] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c
new file mode 100644
index 00000000000..f52bfda0d14
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_rotate.c
@@ -0,0 +1,198 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Rotation) */
+
+/** \name Transform Rotation
+ * \{ */
+
+static float large_rotation_limit(float angle)
+{
+ /* Limit rotation to 1001 turns max
+ * (otherwise iterative handling of 'large' rotations would become too slow). */
+ const float angle_max = (float)(M_PI * 2000.0);
+ if (fabsf(angle) > angle_max) {
+ const float angle_sign = angle < 0.0f ? -1.0f : 1.0f;
+ angle = angle_sign * (fmodf(fabsf(angle), (float)(M_PI * 2.0)) + angle_max);
+ }
+ return angle;
+}
+
+static void applyRotationValue(TransInfo *t,
+ float angle,
+ float axis[3],
+ const bool is_large_rotation)
+{
+ float mat[3][3];
+ int i;
+
+ const float angle_sign = angle < 0.0f ? -1.0f : 1.0f;
+ /* We cannot use something too close to 180°, or 'continuous' rotation may fail
+ * due to computing error... */
+ const float angle_step = angle_sign * (float)(0.9 * M_PI);
+
+ if (is_large_rotation) {
+ /* Just in case, calling code should have already done that in practice
+ * (for UI feedback reasons). */
+ angle = large_rotation_limit(angle);
+ }
+
+ axis_angle_normalized_to_mat3(mat, axis, angle);
+ /* Counter for needed updates (when we need to update to non-default matrix,
+ * we also need another update on next iteration to go back to default matrix,
+ * hence the '2' value used here, instead of a mere boolean). */
+ short do_update_matrix = 0;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ float angle_final = angle;
+ if (t->con.applyRot) {
+ t->con.applyRot(t, tc, td, axis, NULL);
+ angle_final = angle * td->factor;
+ /* Even though final angle might be identical to orig value,
+ * we have to update the rotation matrix in that case... */
+ do_update_matrix = 2;
+ }
+ else if (t->flag & T_PROP_EDIT) {
+ angle_final = angle * td->factor;
+ }
+
+ /* Rotation is very likely to be above 180°, we need to do rotation by steps.
+ * Note that this is only needed when doing 'absolute' rotation
+ * (i.e. from initial rotation again, typically when using numinput).
+ * regular incremental rotation (from mouse/widget/...) will be called often enough,
+ * hence steps are small enough to be properly handled without that complicated trick.
+ * Note that we can only do that kind of stepped rotation if we have initial rotation values
+ * (and access to some actual rotation value storage).
+ * Otherwise, just assume it's useless (e.g. in case of mesh/UV/etc. editing).
+ * Also need to be in Euler rotation mode, the others never allow more than one turn anyway.
+ */
+ if (is_large_rotation && td->ext != NULL && td->ext->rotOrder == ROT_MODE_EUL) {
+ copy_v3_v3(td->ext->rot, td->ext->irot);
+ for (float angle_progress = angle_step; fabsf(angle_progress) < fabsf(angle_final);
+ angle_progress += angle_step) {
+ axis_angle_normalized_to_mat3(mat, axis, angle_progress);
+ ElementRotation(t, tc, td, mat, t->around);
+ }
+ do_update_matrix = 2;
+ }
+ else if (angle_final != angle) {
+ do_update_matrix = 2;
+ }
+
+ if (do_update_matrix > 0) {
+ axis_angle_normalized_to_mat3(mat, axis, angle_final);
+ do_update_matrix--;
+ }
+
+ ElementRotation(t, tc, td, mat, t->around);
+ }
+ }
+}
+
+static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+
+ float final;
+
+ final = t->values[0];
+
+ snapGridIncrement(t, &final);
+
+ float axis_final[3];
+ copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]);
+
+ if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
+ t->con.applyRot(t, NULL, NULL, axis_final, NULL);
+ }
+
+ applySnapping(t, &final);
+
+ if (applyNumInput(&t->num, &final)) {
+ /* We have to limit the amount of turns to a reasonable number here,
+ * to avoid things getting *very* slow, see how applyRotationValue() handles those... */
+ final = large_rotation_limit(final);
+ }
+
+ t->values_final[0] = final;
+
+ headerRotation(t, str, final);
+
+ const bool is_large_rotation = hasNumInput(&t->num);
+ applyRotationValue(t, final, axis_final, is_large_rotation);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initRotation(TransInfo *t)
+{
+ t->mode = TFM_ROTATION;
+ t->transform = applyRotation;
+
+ setInputPostFct(&t->mouse, postInputRotation);
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[2]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+
+ if (t->flag & T_2D_EDIT) {
+ t->flag |= T_NO_CONSTRAINT;
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c
new file mode 100644
index 00000000000..da34bf50ba3
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_shear.c
@@ -0,0 +1,248 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "WM_types.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Shear) */
+
+/** \name Transform Shear
+ * \{ */
+
+static void initShear_mouseInputMode(TransInfo *t)
+{
+ float dir[3];
+ bool dir_flip = false;
+ copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]);
+
+ /* Needed for axis aligned view gizmo. */
+ if (t->orientation.types[t->orientation.index] == V3D_ORIENT_VIEW) {
+ if (t->orient_axis_ortho == 0) {
+ if (t->center2d[1] < t->mouse.imval[1]) {
+ dir_flip = !dir_flip;
+ }
+ }
+ else if (t->orient_axis_ortho == 1) {
+ if (t->center2d[0] < t->mouse.imval[0]) {
+ dir_flip = !dir_flip;
+ }
+ }
+ }
+
+ /* Without this, half the gizmo handles move in the opposite direction. */
+ if ((t->orient_axis_ortho + 1) % 3 != t->orient_axis) {
+ dir_flip = !dir_flip;
+ }
+
+ if (dir_flip) {
+ negate_v3(dir);
+ }
+
+ mul_mat3_m4_v3(t->viewmat, dir);
+ if (normalize_v2(dir) == 0.0f) {
+ dir[0] = 1.0f;
+ }
+ setCustomPointsFromDirection(t, &t->mouse, dir);
+
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+}
+
+static eRedrawFlag handleEventShear(TransInfo *t, const wmEvent *event)
+{
+ eRedrawFlag status = TREDRAW_NOTHING;
+
+ if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
+ /* Use custom.mode.data pointer to signal Shear direction */
+ do {
+ t->orient_axis_ortho = (t->orient_axis_ortho + 1) % 3;
+ } while (t->orient_axis_ortho == t->orient_axis);
+
+ initShear_mouseInputMode(t);
+
+ status = TREDRAW_HARD;
+ }
+ else if (event->type == EVT_XKEY && event->val == KM_PRESS) {
+ t->orient_axis_ortho = (t->orient_axis + 1) % 3;
+ initShear_mouseInputMode(t);
+
+ status = TREDRAW_HARD;
+ }
+ else if (event->type == EVT_YKEY && event->val == KM_PRESS) {
+ t->orient_axis_ortho = (t->orient_axis + 2) % 3;
+ initShear_mouseInputMode(t);
+
+ status = TREDRAW_HARD;
+ }
+
+ return status;
+}
+
+static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float vec[3];
+ float smat[3][3], tmat[3][3], totmat[3][3], axismat[3][3], axismat_inv[3][3];
+ float value;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+ const bool is_local_center = transdata_check_local_center(t, t->around);
+
+ value = t->values[0];
+
+ snapGridIncrement(t, &value);
+
+ applyNumInput(&t->num, &value);
+
+ t->values_final[0] = value;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str, sizeof(str), TIP_("Shear: %s %s"), c, t->proptext);
+ }
+ else {
+ /* default header print */
+ BLI_snprintf(str,
+ sizeof(str),
+ TIP_("Shear: %.3f %s (Press X or Y to set shear axis)"),
+ value,
+ t->proptext);
+ }
+
+ unit_m3(smat);
+ smat[1][0] = value;
+
+ copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]);
+ copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]);
+ cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]);
+ invert_m3_m3(axismat, axismat_inv);
+
+ mul_m3_series(totmat, axismat_inv, smat, axismat);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ const float *center, *co;
+
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (t->flag & T_EDIT) {
+ mul_m3_series(tmat, td->smtx, totmat, td->mtx);
+ }
+ else {
+ copy_m3_m3(tmat, totmat);
+ }
+
+ if (is_local_center) {
+ center = td->center;
+ co = td->loc;
+ }
+ else {
+ center = tc->center_local;
+ co = td->center;
+ }
+
+ sub_v3_v3v3(vec, co, center);
+
+ mul_m3_v3(tmat, vec);
+
+ add_v3_v3(vec, center);
+ sub_v3_v3(vec, co);
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* grease pencil multiframe falloff */
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ if (gps != NULL) {
+ mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
+ }
+ else {
+ mul_v3_fl(vec, td->factor);
+ }
+ }
+ else {
+ mul_v3_fl(vec, td->factor);
+ }
+
+ add_v3_v3v3(td->loc, td->iloc, vec);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initShear(TransInfo *t)
+{
+ t->mode = TFM_SHEAR;
+ t->transform = applyShear;
+ t->handleEvent = handleEventShear;
+
+ if (t->orient_axis == t->orient_axis_ortho) {
+ t->orient_axis = 2;
+ t->orient_axis_ortho = 1;
+ }
+
+ initShear_mouseInputMode(t);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = 0.1f;
+ t->snap[2] = t->snap[1] * 0.1f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE; /* Don't think we have any unit here? */
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_shrink_fatten.c b/source/blender/editors/transform/transform_mode_shrink_fatten.c
new file mode 100644
index 00000000000..ed082e86b6d
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_shrink_fatten.c
@@ -0,0 +1,146 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Shrink-Fatten) */
+
+/** \name Transform Shrink-Fatten
+ * \{ */
+
+static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float distance;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+ size_t ofs = 0;
+
+ distance = -t->values[0];
+
+ snapGridIncrement(t, &distance);
+
+ applyNumInput(&t->num, &distance);
+
+ t->values_final[0] = -distance;
+
+ /* header print for NumInput */
+ ofs += BLI_strncpy_rlen(str + ofs, TIP_("Shrink/Fatten:"), sizeof(str) - ofs);
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", c);
+ }
+ else {
+ /* default header print */
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %.4f", distance);
+ }
+
+ if (t->proptext[0]) {
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, " %s", t->proptext);
+ }
+ ofs += BLI_strncpy_rlen(str + ofs, ", (", sizeof(str) - ofs);
+
+ if (t->keymap) {
+ wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
+ if (kmi) {
+ ofs += WM_keymap_item_to_string(kmi, false, str + ofs, sizeof(str) - ofs);
+ }
+ }
+ BLI_snprintf(str + ofs,
+ sizeof(str) - ofs,
+ TIP_(" or Alt) Even Thickness %s"),
+ WM_bool_as_string((t->flag & T_ALT_TRANSFORM) != 0));
+ /* done with header string */
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tdistance; /* temp dist */
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ /* get the final offset */
+ tdistance = distance * td->factor;
+ if (td->ext && (t->flag & T_ALT_TRANSFORM) != 0) {
+ tdistance *= td->ext->isize[0]; /* shell factor */
+ }
+
+ madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initShrinkFatten(TransInfo *t)
+{
+ // If not in mesh edit mode, fallback to Resize
+ if ((t->flag & T_EDIT) == 0 || (t->obedit_type != OB_MESH)) {
+ initResize(t);
+ }
+ else {
+ t->mode = TFM_SHRINKFATTEN;
+ t->transform = applyShrinkFatten;
+
+ initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_LENGTH;
+
+ t->flag |= T_NO_CONSTRAINT;
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_skin_resize.c b/source/blender/editors/transform/transform_mode_skin_resize.c
new file mode 100644
index 00000000000..b53dbb55c62
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_skin_resize.c
@@ -0,0 +1,141 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "transform.h"
+#include "transform_constraints.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Skin) */
+
+/** \name Transform Skin
+ * \{ */
+
+static void applySkinResize(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float mat[3][3];
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ if (t->flag & T_INPUT_IS_VALUES_FINAL) {
+ copy_v3_v3(t->values_final, t->values);
+ }
+ else {
+ copy_v3_fl(t->values_final, t->values[0]);
+
+ snapGridIncrement(t, t->values_final);
+
+ if (applyNumInput(&t->num, t->values_final)) {
+ constraintNumInput(t, t->values_final);
+ }
+
+ applySnapping(t, t->values_final);
+ }
+
+ size_to_mat3(mat, t->values_final);
+
+ headerResize(t, t->values_final, str);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tmat[3][3], smat[3][3];
+ float fsize[3];
+
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (t->flag & T_EDIT) {
+ mul_m3_m3m3(smat, mat, td->mtx);
+ mul_m3_m3m3(tmat, td->smtx, smat);
+ }
+ else {
+ copy_m3_m3(tmat, mat);
+ }
+
+ if (t->con.applySize) {
+ t->con.applySize(t, NULL, NULL, tmat);
+ }
+
+ mat3_to_size(fsize, tmat);
+ td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
+ td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initSkinResize(TransInfo *t)
+{
+ t->mode = TFM_SKIN_RESIZE;
+ t->transform = applySkinResize;
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+
+ t->flag |= T_NULL_ONE;
+ t->num.val_flag[0] |= NUM_NULL_ONE;
+ t->num.val_flag[1] |= NUM_NULL_ONE;
+ t->num.val_flag[2] |= NUM_NULL_ONE;
+ t->num.flag |= NUM_AFFECT_ALL;
+ if ((t->flag & T_EDIT) == 0) {
+ t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
+ t->num.val_flag[0] |= NUM_NO_ZERO;
+ t->num.val_flag[1] |= NUM_NO_ZERO;
+ t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
+ }
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+ t->num.unit_type[1] = B_UNIT_NONE;
+ t->num.unit_type[2] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tilt.c b/source/blender/editors/transform/transform_mode_tilt.c
new file mode 100644
index 00000000000..2f56f4bd162
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_tilt.c
@@ -0,0 +1,119 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Tilt) */
+
+/** \name Transform Tilt
+ * \{ */
+
+static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
+{
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ float final;
+
+ final = t->values[0];
+
+ snapGridIncrement(t, &final);
+
+ applyNumInput(&t->num, &final);
+
+ t->values_final[0] = final;
+
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str, sizeof(str), TIP_("Tilt: %s° %s"), &c[0], t->proptext);
+
+ /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
+ t->values_final[0] = final;
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), TIP_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; 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_status_text(t->area, str);
+}
+
+void initTilt(TransInfo *t)
+{
+ t->mode = TFM_TILT;
+ t->transform = applyTilt;
+
+ initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
+
+ t->idx_max = 0;
+ t->num.idx_max = 0;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[2]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timescale.c b/source/blender/editors/transform/transform_mode_timescale.c
new file mode 100644
index 00000000000..ce46cc36276
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_timescale.c
@@ -0,0 +1,158 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "DNA_anim_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_nla.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Time Scale) */
+
+/** \name Transform Animation Time Scale
+ * \{ */
+
+static void headerTimeScale(TransInfo *t, char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values_final[0]);
+ }
+
+ BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("ScaleX: %s"), &tvec[0]);
+}
+
+static void applyTimeScaleValue(TransInfo *t, float value)
+{
+ Scene *scene = t->scene;
+ const short autosnap = getAnimEdit_SnapMode(t);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ for (int i = 0; i < tc->data_len; i++, td++, td2d++) {
+ /* it is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from
+ * (this is only valid when not in NLA)
+ */
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float startx = CFRA;
+ float fac = value;
+
+ /* take proportional editing into account */
+ fac = ((fac - 1.0f) * td->factor) + 1;
+
+ /* check if any need to apply nla-mapping */
+ if (adt) {
+ startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
+ }
+
+ /* now, calculate the new value */
+ *(td->val) = ((td->ival - startx) * fac) + startx;
+
+ /* apply nearest snapping */
+ doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+ }
+ }
+}
+
+static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+
+ /* handle numeric-input stuff */
+ t->vec[0] = t->values[0];
+ applyNumInput(&t->num, &t->vec[0]);
+ t->values_final[0] = t->vec[0];
+ headerTimeScale(t, str);
+
+ applyTimeScaleValue(t, t->values_final[0]);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initTimeScale(TransInfo *t)
+{
+ float center[2];
+
+ /* this tool is only really available in the Action Editor
+ * AND NLA Editor (for strip scaling)
+ */
+ if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) {
+ t->state = TRANS_CANCEL;
+ }
+
+ t->mode = TFM_TIME_SCALE;
+ t->transform = applyTimeScale;
+
+ /* recalculate center2d to use CFRA and mouse Y, since that's
+ * what is used in time scale */
+ if ((t->flag & T_OVERRIDE_CENTER) == 0) {
+ t->center_global[0] = t->scene->r.cfra;
+ projectFloatView(t, t->center_global, center);
+ center[1] = t->mouse.imval[1];
+ }
+
+ /* force a reinit with the center2d used here */
+ initMouseInput(t, &t->mouse, center, t->mouse.imval, false);
+
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
+
+ t->flag |= T_NULL_ONE;
+ t->num.val_flag[0] |= 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;
+
+ /* initialize snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timeslide.c b/source/blender/editors/transform/transform_mode_timeslide.c
new file mode 100644
index 00000000000..43e14a26930
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_timeslide.c
@@ -0,0 +1,236 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_nla.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Time Slide) */
+
+/** \name Transform Animation Time Slide
+ * \{ */
+
+static void headerTimeSlide(TransInfo *t, const float sval, char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
+ float cval = t->values_final[0];
+ float val;
+
+ val = 2.0f * (cval - sval) / (maxx - minx);
+ CLAMP(val, -1.0f, 1.0f);
+
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
+ }
+
+ BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("TimeSlide: %s"), &tvec[0]);
+}
+
+static void applyTimeSlideValue(TransInfo *t, float sval, float cval)
+{
+ int i;
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
+
+ /* set value for drawing black line */
+ if (t->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
+ saction->timeslide = cval;
+ }
+
+ /* It doesn't matter whether we apply to t->data or
+ * t->data2d, but t->data2d is more convenient. */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ /* it is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from
+ * (this is only valid when not in NLA)
+ */
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+
+ /* only apply to data if in range */
+ if ((sval > minx) && (sval < maxx)) {
+ float cvalc = CLAMPIS(cval, minx, maxx);
+ float ival = td->ival;
+ float timefac;
+
+ /* NLA mapping magic here works as follows:
+ * - "ival" goes from strip time to global time
+ * - calculation is performed into td->val in global time
+ * (since sval and min/max are all in global time)
+ * - "td->val" then gets put back into strip time
+ */
+ if (adt) {
+ /* strip to global */
+ ival = BKE_nla_tweakedit_remap(adt, ival, NLATIME_CONVERT_MAP);
+ }
+
+ /* left half? */
+ if (ival < sval) {
+ timefac = (sval - ival) / (sval - minx);
+ *(td->val) = cvalc - timefac * (cvalc - minx);
+ }
+ else {
+ timefac = (ival - sval) / (maxx - sval);
+ *(td->val) = cvalc + timefac * (maxx - cvalc);
+ }
+
+ if (adt) {
+ /* global to strip */
+ *(td->val) = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_UNMAP);
+ }
+ }
+ }
+ }
+}
+
+static void applyTimeSlide(TransInfo *t, const int mval[2])
+{
+ View2D *v2d = (View2D *)t->view;
+ float cval[2], sval[2];
+ const float *range = t->custom.mode.data;
+ float minx = range[0];
+ float maxx = range[1];
+ char str[UI_MAX_DRAW_STR];
+
+ /* calculate mouse co-ordinates */
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[1], &sval[0], &sval[1]);
+
+ /* t->values_final[0] stores cval[0], which is the current mouse-pointer location (in frames) */
+ // XXX Need to be able to repeat this
+ /* t->values_final[0] = cval[0]; */ /* UNUSED (reset again later). */
+
+ /* handle numeric-input stuff */
+ t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
+ applyNumInput(&t->num, &t->vec[0]);
+ t->values_final[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0];
+
+ headerTimeSlide(t, sval[0], str);
+ applyTimeSlideValue(t, sval[0], t->values_final[0]);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initTimeSlide(TransInfo *t)
+{
+ /* this tool is only really available in the Action Editor... */
+ if (t->spacetype == SPACE_ACTION) {
+ SpaceAction *saction = (SpaceAction *)t->area->spacedata.first;
+
+ /* set flag for drawing stuff */
+ saction->flag |= SACTION_MOVING;
+ }
+ else {
+ t->state = TRANS_CANCEL;
+ }
+
+ t->mode = TFM_TIME_SLIDE;
+ t->transform = applyTimeSlide;
+
+ initMouseInputMode(t, &t->mouse, INPUT_NONE);
+
+ {
+ Scene *scene = t->scene;
+ float *range;
+ t->custom.mode.data = range = MEM_mallocN(sizeof(float[2]), "TimeSlide Min/Max");
+ t->custom.mode.use_free = true;
+
+ float min = 999999999.0f, max = -999999999.0f;
+ int i;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+ float val = *(td->val);
+
+ /* strip/action time to global (mapped) time */
+ if (adt) {
+ val = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_MAP);
+ }
+
+ if (min > val) {
+ min = val;
+ }
+ if (max < val) {
+ max = val;
+ }
+ }
+ }
+
+ if (min == max) {
+ /* just use the current frame ranges */
+ min = (float)PSFRA;
+ max = (float)PEFRA;
+ }
+
+ range[0] = min;
+ range[1] = max;
+ }
+
+ /* num-input has max of (n-1) */
+ t->idx_max = 0;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ /* initialize snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ /* No time unit supporting frames currently... */
+ t->num.unit_type[0] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c
new file mode 100644
index 00000000000..c514df497bc
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_timetranslate.c
@@ -0,0 +1,167 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "DNA_anim_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_nla.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Animation Translation) */
+
+/** \name Transform Animation Translation
+ * \{ */
+
+static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR])
+{
+ char tvec[NUM_STR_REP_LEN * 3];
+ int ofs = 0;
+
+ /* if numeric input is active, use results from that, otherwise apply snapping to result */
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ }
+ else {
+ const short autosnap = getAnimEdit_SnapMode(t);
+ float val = t->values_final[0];
+
+ float snap_val;
+ snapFrameTransform(t, autosnap, false, val, &snap_val);
+
+ if (autosnap == SACTSNAP_FRAME) {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val);
+ }
+ else if (autosnap == SACTSNAP_SECOND) {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val);
+ }
+ else if (autosnap == SACTSNAP_TSTEP) {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val);
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val);
+ }
+ }
+
+ ofs += BLI_snprintf(str, UI_MAX_DRAW_STR, TIP_("DeltaX: %s"), &tvec[0]);
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ }
+}
+
+static void applyTimeTranslateValue(TransInfo *t, const float deltax)
+{
+ const short autosnap = getAnimEdit_SnapMode(t);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ TransData2D *td2d = tc->data_2d;
+ /* It doesn't matter whether we apply to t->data or
+ * t->data2d, but t->data2d is more convenient. */
+ for (int i = 0; i < tc->data_len; i++, td++, td2d++) {
+ /* It is assumed that td->extra is a pointer to the AnimData,
+ * whose active action is where this keyframe comes from.
+ * (this is only valid when not in NLA)
+ * (also: masks and gpencil dont have animadata)
+ */
+ AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
+
+ /* apply nearest snapping */
+ *(td->val) = td->ival + deltax * td->factor;
+ doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
+ }
+ }
+}
+
+static void applyTimeTranslate(TransInfo *t, const int mval[2])
+{
+ View2D *v2d = (View2D *)t->view;
+ char str[UI_MAX_DRAW_STR];
+
+ /* calculate translation amount from mouse movement - in 'time-grid space' */
+ if (t->flag & T_MODAL) {
+ float cval[2], sval[2];
+ UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
+ UI_view2d_region_to_view(v2d, t->mouse.imval[0], t->mouse.imval[0], &sval[0], &sval[1]);
+
+ /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
+ t->values[0] = cval[0] - sval[0];
+ }
+
+ /* handle numeric-input stuff */
+ t->vec[0] = t->values[0];
+ applyNumInput(&t->num, &t->vec[0]);
+ t->values_final[0] = t->vec[0];
+ headerTimeTranslate(t, str);
+
+ applyTimeTranslateValue(t, t->values_final[0]);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initTimeTranslate(TransInfo *t)
+{
+ /* this tool is only really available in the Action Editor... */
+ if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) {
+ t->state = TRANS_CANCEL;
+ }
+
+ t->transform = applyTimeTranslate;
+
+ initMouseInputMode(t, &t->mouse, INPUT_NONE);
+
+ /* num-input has max of (n-1) */
+ t->idx_max = 0;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ /* initialize snap like for everything else */
+ t->snap[0] = 0.0f;
+ t->snap[1] = t->snap[2] = 1.0f;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ /* No time unit supporting frames currently... */
+ t->num.unit_type[0] = B_UNIT_NONE;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_tosphere.c b/source/blender/editors/transform/transform_mode_tosphere.c
new file mode 100644
index 00000000000..841ccf41365
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_tosphere.c
@@ -0,0 +1,139 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (ToSphere) */
+
+/** \name Transform ToSphere
+ * \{ */
+
+static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
+{
+ float vec[3];
+ float ratio, radius;
+ int i;
+ char str[UI_MAX_DRAW_STR];
+
+ ratio = t->values[0];
+
+ snapGridIncrement(t, &ratio);
+
+ applyNumInput(&t->num, &ratio);
+
+ CLAMP(ratio, 0.0f, 1.0f);
+
+ t->values_final[0] = ratio;
+
+ /* header print for NumInput */
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %s %s"), c, t->proptext);
+ }
+ else {
+ /* default header print */
+ BLI_snprintf(str, sizeof(str), TIP_("To Sphere: %.4f %s"), ratio, t->proptext);
+ }
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ float tratio;
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ sub_v3_v3v3(vec, td->iloc, tc->center_local);
+
+ radius = normalize_v3(vec);
+
+ tratio = ratio * td->factor;
+
+ mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
+
+ add_v3_v3v3(td->loc, tc->center_local, vec);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initToSphere(TransInfo *t)
+{
+ int i;
+
+ t->mode = TFM_TOSPHERE;
+ t->transform = applyToSphere;
+
+ initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->num.val_flag[0] |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
+ t->flag |= T_NO_CONSTRAINT;
+
+ // Calculate average radius
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ t->val += len_v3v3(tc->center_local, td->iloc);
+ }
+ }
+
+ t->val /= (float)t->data_len_all;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_trackball.c b/source/blender/editors/transform/transform_mode_trackball.c
new file mode 100644
index 00000000000..c6e0b205204
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_trackball.c
@@ -0,0 +1,170 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Rotation - Trackball) */
+
+/** \name Transform Rotation - Trackball
+ * \{ */
+
+static void applyTrackballValue(TransInfo *t,
+ const float axis1[3],
+ const float axis2[3],
+ const float angles[2])
+{
+ float mat[3][3];
+ float axis[3];
+ float angle;
+ int i;
+
+ mul_v3_v3fl(axis, axis1, angles[0]);
+ madd_v3_v3fl(axis, axis2, angles[1]);
+ angle = normalize_v3(axis);
+ axis_angle_normalized_to_mat3(mat, axis, angle);
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ TransData *td = tc->data;
+ for (i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ if (t->flag & T_PROP_EDIT) {
+ axis_angle_normalized_to_mat3(mat, axis, td->factor * angle);
+ }
+
+ ElementRotation(t, tc, td, mat, t->around);
+ }
+ }
+}
+
+static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+ size_t ofs = 0;
+ float axis1[3], axis2[3];
+#if 0 /* UNUSED */
+ float mat[3][3], totmat[3][3], smat[3][3];
+#endif
+ float phi[2];
+
+ copy_v3_v3(axis1, t->persinv[0]);
+ copy_v3_v3(axis2, t->persinv[1]);
+ normalize_v3(axis1);
+ normalize_v3(axis2);
+
+ copy_v2_v2(phi, t->values);
+
+ snapGridIncrement(t, phi);
+
+ applyNumInput(&t->num, phi);
+
+ copy_v2_v2(t->values_final, phi);
+
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN * 2];
+
+ outputNumInput(&(t->num), c, &t->scene->unit);
+
+ ofs += BLI_snprintf(str + ofs,
+ sizeof(str) - ofs,
+ TIP_("Trackball: %s %s %s"),
+ &c[0],
+ &c[NUM_STR_REP_LEN],
+ t->proptext);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs,
+ sizeof(str) - ofs,
+ TIP_("Trackball: %.2f %.2f %s"),
+ RAD2DEGF(phi[0]),
+ RAD2DEGF(phi[1]),
+ t->proptext);
+ }
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ }
+
+#if 0 /* UNUSED */
+ axis_angle_normalized_to_mat3(smat, axis1, phi[0]);
+ axis_angle_normalized_to_mat3(totmat, axis2, phi[1]);
+
+ mul_m3_m3m3(mat, smat, totmat);
+
+ // TRANSFORM_FIX_ME
+ //copy_m3_m3(t->mat, mat); // used in gizmo
+#endif
+
+ applyTrackballValue(t, axis1, axis2, phi);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initTrackball(TransInfo *t)
+{
+ t->mode = TFM_TRACKBALL;
+ t->transform = applyTrackball;
+
+ initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
+
+ t->idx_max = 1;
+ t->num.idx_max = 1;
+ t->snap[0] = 0.0f;
+ t->snap[1] = DEG2RAD(5.0);
+ t->snap[2] = DEG2RAD(1.0);
+
+ copy_v3_fl(t->num.val_inc, t->snap[2]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_use_radians = (t->scene->unit.system_rotation == USER_UNIT_ROT_RADIANS);
+ t->num.unit_type[0] = B_UNIT_ROTATION;
+ t->num.unit_type[1] = B_UNIT_ROTATION;
+
+ t->flag |= T_NO_CONSTRAINT;
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c
new file mode 100644
index 00000000000..0a7d8bd90d3
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_translate.c
@@ -0,0 +1,412 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_gpencil_types.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_unit.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+
+#include "UI_interface.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Translation) */
+
+/** \name Transform Translation
+ * \{ */
+
+static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_DRAW_STR])
+{
+ size_t ofs = 0;
+ char tvec[NUM_STR_REP_LEN * 3];
+ char distvec[NUM_STR_REP_LEN];
+ char autoik[NUM_STR_REP_LEN];
+ float dist;
+
+ if (hasNumInput(&t->num)) {
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
+ dist = len_v3(t->num.val);
+ }
+ else {
+ float dvec[3];
+
+ copy_v3_v3(dvec, vec);
+ applyAspectRatio(t, dvec);
+
+ dist = len_v3(vec);
+ if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ bUnit_AsString2(&tvec[NUM_STR_REP_LEN * i],
+ NUM_STR_REP_LEN,
+ dvec[i] * t->scene->unit.scale_length,
+ 4,
+ B_UNIT_LENGTH,
+ &t->scene->unit,
+ true);
+ }
+ }
+ else {
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", dvec[0]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", dvec[1]);
+ BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", dvec[2]);
+ }
+ }
+
+ if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
+ bUnit_AsString2(distvec,
+ sizeof(distvec),
+ dist * t->scene->unit.scale_length,
+ 4,
+ B_UNIT_LENGTH,
+ &t->scene->unit,
+ false);
+ }
+ else if (dist > 1e10f || dist < -1e10f) {
+ /* prevent string buffer overflow */
+ BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4e", dist);
+ }
+ else {
+ BLI_snprintf(distvec, NUM_STR_REP_LEN, "%.4f", dist);
+ }
+
+ if (t->flag & T_AUTOIK) {
+ short chainlen = t->settings->autoik_chainlen;
+
+ if (chainlen) {
+ BLI_snprintf(autoik, NUM_STR_REP_LEN, TIP_("AutoIK-Len: %d"), chainlen);
+ }
+ else {
+ autoik[0] = '\0';
+ }
+ }
+ else {
+ autoik[0] = '\0';
+ }
+
+ if (t->con.mode & CON_APPLY) {
+ switch (t->num.idx_max) {
+ case 0:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ "D: %s (%s)%s %s %s",
+ &tvec[0],
+ distvec,
+ t->con.text,
+ t->proptext,
+ autoik);
+ break;
+ case 1:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ "D: %s D: %s (%s)%s %s %s",
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ distvec,
+ t->con.text,
+ t->proptext,
+ autoik);
+ break;
+ case 2:
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ "D: %s D: %s D: %s (%s)%s %s %s",
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ distvec,
+ t->con.text,
+ t->proptext,
+ autoik);
+ break;
+ }
+ }
+ else {
+ if (t->flag & T_2D_EDIT) {
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ "Dx: %s Dy: %s (%s)%s %s",
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ distvec,
+ t->con.text,
+ t->proptext);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs,
+ UI_MAX_DRAW_STR - ofs,
+ "Dx: %s Dy: %s Dz: %s (%s)%s %s %s",
+ &tvec[0],
+ &tvec[NUM_STR_REP_LEN],
+ &tvec[NUM_STR_REP_LEN * 2],
+ distvec,
+ t->con.text,
+ t->proptext,
+ autoik);
+ }
+ }
+
+ if (t->flag & T_PROP_EDIT_ALL) {
+ ofs += BLI_snprintf(
+ str + ofs, UI_MAX_DRAW_STR - ofs, TIP_(" Proportional size: %.2f"), t->prop_size);
+ }
+
+ if (t->spacetype == SPACE_NODE) {
+ SpaceNode *snode = (SpaceNode *)t->area->spacedata.first;
+
+ if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) {
+ const char *str_old = BLI_strdup(str);
+ const char *str_dir = (snode->insert_ofs_dir == SNODE_INSERTOFS_DIR_RIGHT) ? TIP_("right") :
+ TIP_("left");
+ char str_km[64];
+
+ WM_modalkeymap_items_to_string(
+ t->keymap, TFM_MODAL_INSERTOFS_TOGGLE_DIR, true, str_km, sizeof(str_km));
+
+ ofs += BLI_snprintf(str,
+ UI_MAX_DRAW_STR,
+ TIP_("Auto-offset set to %s - press %s to toggle direction | %s"),
+ str_dir,
+ str_km,
+ str_old);
+
+ MEM_freeN((void *)str_old);
+ }
+ }
+}
+
+static void applyTranslationValue(TransInfo *t, const float vec[3])
+{
+ const bool apply_snap_align_rotation = usingSnappingNormal(
+ t); // && (t->tsnap.status & POINT_INIT);
+ float tvec[3];
+
+ /* The ideal would be "apply_snap_align_rotation" only when a snap point is found
+ * so, maybe inside this function is not the best place to apply this rotation.
+ * but you need "handle snapping rotation before doing the translation" (really?) */
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+
+ float pivot[3];
+ if (apply_snap_align_rotation) {
+ copy_v3_v3(pivot, t->tsnap.snapTarget);
+ /* The pivot has to be in local-space (see T49494) */
+ if (tc->use_local_mat) {
+ mul_m4_v3(tc->imat, pivot);
+ }
+ }
+
+ TransData *td = tc->data;
+ for (int i = 0; i < tc->data_len; i++, td++) {
+ if (td->flag & TD_NOACTION) {
+ break;
+ }
+
+ if (td->flag & TD_SKIP) {
+ continue;
+ }
+
+ float rotate_offset[3] = {0};
+ bool use_rotate_offset = false;
+
+ /* handle snapping rotation before doing the translation */
+ if (apply_snap_align_rotation) {
+ float mat[3][3];
+
+ if (validSnappingNormal(t)) {
+ const float *original_normal;
+
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ if (t->flag & T_POSE) {
+ original_normal = td->axismtx[1];
+ }
+ else {
+ original_normal = td->axismtx[2];
+ }
+
+ rotation_between_vecs_to_mat3(mat, original_normal, t->tsnap.snapNormal);
+ }
+ else {
+ unit_m3(mat);
+ }
+
+ ElementRotation_ex(t, tc, td, mat, pivot);
+
+ if (td->loc) {
+ use_rotate_offset = true;
+ sub_v3_v3v3(rotate_offset, td->loc, td->iloc);
+ }
+ }
+
+ if (t->con.applyVec) {
+ float pvec[3];
+ t->con.applyVec(t, tc, td, vec, tvec, pvec);
+ }
+ else {
+ copy_v3_v3(tvec, vec);
+ }
+
+ mul_m3_v3(td->smtx, tvec);
+
+ if (use_rotate_offset) {
+ add_v3_v3(tvec, rotate_offset);
+ }
+
+ if (t->options & CTX_GPENCIL_STROKES) {
+ /* grease pencil multiframe falloff */
+ bGPDstroke *gps = (bGPDstroke *)td->extra;
+ if (gps != NULL) {
+ mul_v3_fl(tvec, td->factor * gps->runtime.multi_frame_falloff);
+ }
+ else {
+ mul_v3_fl(tvec, td->factor);
+ }
+ }
+ else {
+ /* proportional editing falloff */
+ mul_v3_fl(tvec, td->factor);
+ }
+
+ protectedTransBits(td->protectflag, tvec);
+
+ if (td->loc) {
+ add_v3_v3v3(td->loc, td->iloc, tvec);
+ }
+
+ constraintTransLim(t, td);
+ }
+ }
+}
+
+static void applyTranslation(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+ float values_final[3];
+
+ if (t->flag & T_INPUT_IS_VALUES_FINAL) {
+ copy_v3_v3(t->values_final, t->values);
+ }
+ else {
+ copy_v3_v3(t->values_final, t->values);
+ if ((t->con.mode & CON_APPLY) == 0) {
+ snapGridIncrement(t, t->values_final);
+ }
+
+ if (applyNumInput(&t->num, t->values_final)) {
+ removeAspectRatio(t, t->values_final);
+ }
+
+ applySnapping(t, t->values_final);
+ }
+ copy_v3_v3(values_final, t->values_final);
+
+ if (t->con.mode & CON_APPLY) {
+ float pvec[3] = {0.0f, 0.0f, 0.0f};
+ t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec);
+ headerTranslation(t, pvec, str);
+
+ /* only so we have re-usable value with redo, see T46741. */
+ mul_v3_m3v3(t->values_final, t->con.imtx, values_final);
+ }
+ else {
+ headerTranslation(t, t->values_final, str);
+ copy_v3_v3(values_final, t->values_final);
+ }
+
+ /* don't use 't->values' now on */
+
+ applyTranslationValue(t, values_final);
+
+ /* evil hack - redo translation if clipping needed */
+ if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) {
+ applyTranslationValue(t, values_final);
+
+ /* In proportional edit it can happen that */
+ /* vertices in the radius of the brush end */
+ /* outside the clipping area */
+ /* XXX HACK - dg */
+ if (t->flag & T_PROP_EDIT_ALL) {
+ clipUVData(t);
+ }
+ }
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initTranslation(TransInfo *t)
+{
+ if (t->spacetype == SPACE_ACTION) {
+ /* this space uses time translate */
+ BKE_report(t->reports,
+ RPT_ERROR,
+ "Use 'Time_Translate' transform mode instead of 'Translation' mode "
+ "for translating keyframes in Dope Sheet Editor");
+ t->state = TRANS_CANCEL;
+ }
+
+ t->transform = applyTranslation;
+
+ initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
+
+ t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2;
+ t->num.flag = 0;
+ t->num.idx_max = t->idx_max;
+
+ copy_v3_v3(t->snap, t->snap_spatial);
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* Handling units makes only sense in 3Dview... See T38877. */
+ t->num.unit_type[0] = B_UNIT_LENGTH;
+ t->num.unit_type[1] = B_UNIT_LENGTH;
+ t->num.unit_type[2] = B_UNIT_LENGTH;
+ }
+ else {
+ /* SPACE_GRAPH, SPACE_ACTION, etc. could use some time units, when we have them... */
+ t->num.unit_type[0] = B_UNIT_NONE;
+ t->num.unit_type[1] = B_UNIT_NONE;
+ t->num.unit_type[2] = B_UNIT_NONE;
+ }
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_mode_vert_slide.c b/source/blender/editors/transform/transform_mode_vert_slide.c
new file mode 100644
index 00000000000..7bee48337f9
--- /dev/null
+++ b/source/blender/editors/transform/transform_mode_vert_slide.c
@@ -0,0 +1,666 @@
+/*
+ * 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) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup edtransform
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_string.h"
+
+#include "BKE_context.h"
+#include "BKE_editmesh.h"
+#include "BKE_unit.h"
+
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_state.h"
+
+#include "ED_screen.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "BLT_translation.h"
+
+#include "transform.h"
+#include "transform_convert.h"
+#include "transform_mode.h"
+#include "transform_snap.h"
+
+/* -------------------------------------------------------------------- */
+/* Transform (Vert Slide) */
+
+/** \name Transform Vert Slide
+ * \{ */
+
+typedef struct TransDataVertSlideVert {
+ /** #TransDataGenericSlideVert (header) */
+ struct BMVert *v;
+ struct LinkNode **cd_loop_groups;
+ float co_orig_3d[3];
+ /* end generic */
+
+ float (*co_link_orig_3d)[3];
+ int co_link_tot;
+ int co_link_curr;
+} TransDataVertSlideVert;
+
+typedef struct VertSlideData {
+ TransDataVertSlideVert *sv;
+ int totsv;
+ int curr_sv_index;
+
+ /* result of ED_view3d_ob_project_mat_get */
+ float proj_mat[4][4];
+} VertSlideData;
+
+typedef struct VertSlideParams {
+ float perc;
+
+ bool use_even;
+ bool flipped;
+} VertSlideParams;
+
+static void calcVertSlideCustomPoints(struct TransInfo *t)
+{
+ VertSlideParams *slp = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
+ TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
+
+ const float *co_orig_3d = sv->co_orig_3d;
+ const float *co_curr_3d = sv->co_link_orig_3d[sv->co_link_curr];
+
+ float co_curr_2d[2], co_orig_2d[2];
+
+ int mval_ofs[2], mval_start[2], mval_end[2];
+
+ ED_view3d_project_float_v2_m4(t->region, co_orig_3d, co_orig_2d, sld->proj_mat);
+ ED_view3d_project_float_v2_m4(t->region, co_curr_3d, co_curr_2d, sld->proj_mat);
+
+ ARRAY_SET_ITEMS(mval_ofs, t->mouse.imval[0] - co_orig_2d[0], t->mouse.imval[1] - co_orig_2d[1]);
+ ARRAY_SET_ITEMS(mval_start, co_orig_2d[0] + mval_ofs[0], co_orig_2d[1] + mval_ofs[1]);
+ ARRAY_SET_ITEMS(mval_end, co_curr_2d[0] + mval_ofs[0], co_curr_2d[1] + mval_ofs[1]);
+
+ if (slp->flipped && slp->use_even) {
+ setCustomPoints(t, &t->mouse, mval_start, mval_end);
+ }
+ else {
+ setCustomPoints(t, &t->mouse, mval_end, mval_start);
+ }
+
+ /* setCustomPoints isn't normally changing as the mouse moves,
+ * in this case apply mouse input immediately so we don't refresh
+ * with the value from the previous points */
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+}
+
+/**
+ * Run once when initializing vert slide to find the reference edge
+ */
+static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
+{
+ /* Active object may have no selected vertices. */
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
+ float mval_fl[2] = {UNPACK2(mval)};
+ TransDataVertSlideVert *sv;
+
+ /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */
+ float dist_sq = 0.0f;
+ float dist_min_sq = FLT_MAX;
+ int i;
+
+ for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
+ float co_2d[2];
+
+ ED_view3d_project_float_v2_m4(t->region, sv->co_orig_3d, co_2d, sld->proj_mat);
+
+ dist_sq = len_squared_v2v2(mval_fl, co_2d);
+ if (dist_sq < dist_min_sq) {
+ dist_min_sq = dist_sq;
+ sld->curr_sv_index = i;
+ }
+ }
+}
+
+/**
+ * Run while moving the mouse to slide along the edge matching the mouse direction
+ */
+static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
+{
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
+ float imval_fl[2] = {UNPACK2(t->mouse.imval)};
+ float mval_fl[2] = {UNPACK2(mval)};
+
+ float dir[3];
+ TransDataVertSlideVert *sv;
+ int i;
+
+ /* note: we could save a matrix-multiply for each vertex
+ * by finding the closest edge in local-space.
+ * However this skews the outcome with non-uniform-scale. */
+
+ /* first get the direction of the original mouse position */
+ sub_v2_v2v2(dir, imval_fl, mval_fl);
+ ED_view3d_win_to_delta(t->region, dir, dir, t->zfac);
+ normalize_v3(dir);
+
+ for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
+ if (sv->co_link_tot > 1) {
+ float dir_dot_best = -FLT_MAX;
+ int co_link_curr_best = -1;
+ int j;
+
+ for (j = 0; j < sv->co_link_tot; j++) {
+ float tdir[3];
+ float dir_dot;
+
+ sub_v3_v3v3(tdir, sv->co_orig_3d, sv->co_link_orig_3d[j]);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, tdir);
+ project_plane_v3_v3v3(tdir, tdir, t->viewinv[2]);
+
+ normalize_v3(tdir);
+ dir_dot = dot_v3v3(dir, tdir);
+ if (dir_dot > dir_dot_best) {
+ dir_dot_best = dir_dot;
+ co_link_curr_best = j;
+ }
+ }
+
+ if (co_link_curr_best != -1) {
+ sv->co_link_curr = co_link_curr_best;
+ }
+ }
+ }
+}
+
+static bool createVertSlideVerts(TransInfo *t, TransDataContainer *tc)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMIter eiter;
+ BMEdge *e;
+ BMVert *v;
+ TransDataVertSlideVert *sv_array;
+ VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
+ int j;
+
+ sld->curr_sv_index = 0;
+
+ j = 0;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ bool ok = false;
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) {
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ ok = true;
+ break;
+ }
+ }
+ }
+
+ if (ok) {
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ j += 1;
+ }
+ else {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
+
+ if (!j) {
+ MEM_freeN(sld);
+ return false;
+ }
+
+ sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array");
+
+ j = 0;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ int k;
+ sv_array[j].v = v;
+ copy_v3_v3(sv_array[j].co_orig_3d, v->co);
+
+ k = 0;
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ k++;
+ }
+ }
+
+ sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k,
+ __func__);
+ sv_array[j].co_link_tot = k;
+
+ k = 0;
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
+ k++;
+ }
+ }
+ j++;
+ }
+ }
+
+ sld->sv = sv_array;
+ sld->totsv = j;
+
+ tc->custom.mode.data = sld;
+
+ /* most likely will be set below */
+ unit_m4(sld->proj_mat);
+
+ if (t->spacetype == SPACE_VIEW3D) {
+ /* view vars */
+ RegionView3D *rv3d = NULL;
+ ARegion *region = t->region;
+
+ rv3d = region ? region->regiondata : NULL;
+ if (rv3d) {
+ ED_view3d_ob_project_mat_get(rv3d, tc->obedit, sld->proj_mat);
+ }
+ }
+
+ /* XXX, calc vert slide across all objects */
+ if (tc == t->data_container) {
+ calcVertSlideMouseActiveVert(t, t->mval);
+ calcVertSlideMouseActiveEdges(t, t->mval);
+ }
+
+ return true;
+}
+
+static void freeVertSlideVerts(TransInfo *UNUSED(t),
+ TransDataContainer *UNUSED(tc),
+ TransCustomData *custom_data)
+{
+ VertSlideData *sld = custom_data->data;
+
+ if (!sld) {
+ return;
+ }
+
+ if (sld->totsv > 0) {
+ TransDataVertSlideVert *sv = sld->sv;
+ int i = 0;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ MEM_freeN(sv->co_link_orig_3d);
+ }
+ }
+
+ MEM_freeN(sld->sv);
+ MEM_freeN(sld);
+
+ custom_data->data = NULL;
+}
+
+static eRedrawFlag handleEventVertSlide(struct TransInfo *t, const struct wmEvent *event)
+{
+ if (t->mode == TFM_VERT_SLIDE) {
+ VertSlideParams *slp = t->custom.mode.data;
+
+ if (slp) {
+ switch (event->type) {
+ case EVT_EKEY:
+ if (event->val == KM_PRESS) {
+ slp->use_even = !slp->use_even;
+ if (slp->flipped) {
+ calcVertSlideCustomPoints(t);
+ }
+ return TREDRAW_HARD;
+ }
+ break;
+ case EVT_FKEY:
+ if (event->val == KM_PRESS) {
+ slp->flipped = !slp->flipped;
+ calcVertSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+ case EVT_CKEY:
+ /* use like a modifier key */
+ if (event->val == KM_PRESS) {
+ t->flag ^= T_ALT_TRANSFORM;
+ calcVertSlideCustomPoints(t);
+ return TREDRAW_HARD;
+ }
+ break;
+#if 0
+ case EVT_MODAL_MAP:
+ switch (event->val) {
+ case TFM_MODAL_EDGESLIDE_DOWN:
+ sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
+ break;
+ case TFM_MODAL_EDGESLIDE_UP:
+ sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
+ break;
+ }
+ break;
+#endif
+ case MOUSEMOVE: {
+ /* don't recalculate the best edge */
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ if (is_clamp) {
+ calcVertSlideMouseActiveEdges(t, event->mval);
+ }
+ calcVertSlideCustomPoints(t);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ return TREDRAW_NOTHING;
+}
+
+void projectVertSlideData(TransInfo *t, bool is_final)
+{
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ trans_mesh_customdata_correction_apply(tc, is_final);
+ }
+}
+
+void drawVertSlide(TransInfo *t)
+{
+ if ((t->mode == TFM_VERT_SLIDE) && TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data) {
+ const VertSlideParams *slp = t->custom.mode.data;
+ VertSlideData *sld = TRANS_DATA_CONTAINER_FIRST_OK(t)->custom.mode.data;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+
+ /* Non-Prop mode */
+ {
+ TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
+ TransDataVertSlideVert *sv;
+ const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
+ const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
+ const int alpha_shade = -160;
+ int i;
+
+ GPU_depth_test(false);
+
+ GPU_blend(true);
+ GPU_blend_set_func_separate(
+ GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
+
+ GPU_matrix_push();
+ GPU_matrix_mul(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+
+ GPU_line_width(line_size);
+
+ const uint shdr_pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
+ immUniformThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
+
+ immBegin(GPU_PRIM_LINES, sld->totsv * 2);
+ if (is_clamp) {
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ immVertex3fv(shdr_pos, sv->co_orig_3d);
+ immVertex3fv(shdr_pos, sv->co_link_orig_3d[sv->co_link_curr]);
+ }
+ }
+ else {
+ sv = sld->sv;
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float a[3], b[3];
+ sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+ mul_v3_fl(a, 100.0f);
+ negate_v3_v3(b, a);
+ add_v3_v3(a, sv->co_orig_3d);
+ add_v3_v3(b, sv->co_orig_3d);
+
+ immVertex3fv(shdr_pos, a);
+ immVertex3fv(shdr_pos, b);
+ }
+ }
+ immEnd();
+
+ GPU_point_size(ctrl_size);
+
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex3fv(shdr_pos,
+ (slp->flipped && slp->use_even) ?
+ curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
+ curr_sv->co_orig_3d);
+ immEnd();
+
+ immUnbindProgram();
+
+ /* direction from active vertex! */
+ if ((t->mval[0] != t->mouse.imval[0]) || (t->mval[1] != t->mouse.imval[1])) {
+ float zfac;
+ float mval_ofs[2];
+ float co_orig_3d[3];
+ float co_dest_3d[3];
+
+ mval_ofs[0] = t->mval[0] - t->mouse.imval[0];
+ mval_ofs[1] = t->mval[1] - t->mouse.imval[1];
+
+ mul_v3_m4v3(
+ co_orig_3d, TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat, curr_sv->co_orig_3d);
+ zfac = ED_view3d_calc_zfac(t->region->regiondata, co_orig_3d, NULL);
+
+ ED_view3d_win_to_delta(t->region, mval_ofs, co_dest_3d, zfac);
+
+ invert_m4_m4(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat,
+ TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->obmat);
+ mul_mat3_m4_v3(TRANS_DATA_CONTAINER_FIRST_OK(t)->obedit->imat, co_dest_3d);
+
+ add_v3_v3(co_dest_3d, curr_sv->co_orig_3d);
+
+ GPU_line_width(1.0f);
+
+ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ GPU_viewport_size_get_f(viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 0); /* "simple" mode */
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ immUniform1f("dash_width", 6.0f);
+ immUniform1f("dash_factor", 0.5f);
+
+ immBegin(GPU_PRIM_LINES, 2);
+ immVertex3fv(shdr_pos, curr_sv->co_orig_3d);
+ immVertex3fv(shdr_pos, co_dest_3d);
+ immEnd();
+
+ immUnbindProgram();
+ }
+
+ GPU_matrix_pop();
+
+ GPU_depth_test(true);
+ }
+ }
+}
+
+void doVertSlide(TransInfo *t, float perc)
+{
+ VertSlideParams *slp = t->custom.mode.data;
+
+ slp->perc = perc;
+
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ VertSlideData *sld = tc->custom.mode.data;
+ TransDataVertSlideVert *svlist = sld->sv, *sv;
+ int i;
+
+ sv = svlist;
+
+ if (slp->use_even == false) {
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
+ }
+ }
+ else {
+ TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
+ const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d,
+ sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
+ const float tperc = perc * edge_len_curr;
+
+ for (i = 0; i < sld->totsv; i++, sv++) {
+ float edge_len;
+ float dir[3];
+
+ sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
+ edge_len = normalize_v3(dir);
+
+ if (edge_len > FLT_EPSILON) {
+ if (slp->flipped) {
+ madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
+ }
+ else {
+ madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
+ }
+ }
+ else {
+ copy_v3_v3(sv->v->co, sv->co_orig_3d);
+ }
+ }
+ }
+ }
+}
+
+static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
+{
+ char str[UI_MAX_DRAW_STR];
+ size_t ofs = 0;
+ float final;
+ VertSlideParams *slp = t->custom.mode.data;
+ const bool flipped = slp->flipped;
+ const bool use_even = slp->use_even;
+ const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
+ const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
+
+ final = t->values[0];
+
+ snapGridIncrement(t, &final);
+
+ /* only do this so out of range values are not displayed */
+ if (is_constrained) {
+ CLAMP(final, 0.0f, 1.0f);
+ }
+
+ applyNumInput(&t->num, &final);
+
+ t->values_final[0] = final;
+
+ /* header string */
+ ofs += BLI_strncpy_rlen(str + ofs, TIP_("Vert Slide: "), sizeof(str) - ofs);
+ if (hasNumInput(&t->num)) {
+ char c[NUM_STR_REP_LEN];
+ outputNumInput(&(t->num), c, &t->scene->unit);
+ ofs += BLI_strncpy_rlen(str + ofs, &c[0], sizeof(str) - ofs);
+ }
+ else {
+ ofs += BLI_snprintf(str + ofs, sizeof(str) - ofs, "%.4f ", final);
+ }
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("(E)ven: %s, "), WM_bool_as_string(use_even));
+ if (use_even) {
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("(F)lipped: %s, "), WM_bool_as_string(flipped));
+ }
+ ofs += BLI_snprintf(
+ str + ofs, sizeof(str) - ofs, TIP_("Alt or (C)lamp: %s"), WM_bool_as_string(is_clamp));
+ /* done with header string */
+
+ /* do stuff here */
+ doVertSlide(t, final);
+
+ recalcData(t);
+
+ ED_area_status_text(t->area, str);
+}
+
+void initVertSlide_ex(TransInfo *t, bool use_even, bool flipped, bool use_clamp)
+{
+
+ t->mode = TFM_VERT_SLIDE;
+ t->transform = applyVertSlide;
+ t->handleEvent = handleEventVertSlide;
+
+ {
+ VertSlideParams *slp = MEM_callocN(sizeof(*slp), __func__);
+ slp->use_even = use_even;
+ slp->flipped = flipped;
+ slp->perc = 0.0f;
+
+ if (!use_clamp) {
+ t->flag |= T_ALT_TRANSFORM;
+ }
+
+ t->custom.mode.data = slp;
+ t->custom.mode.use_free = true;
+ }
+
+ bool ok = false;
+ FOREACH_TRANS_DATA_CONTAINER (t, tc) {
+ ok |= createVertSlideVerts(t, tc);
+ VertSlideData *sld = tc->custom.mode.data;
+ if (sld) {
+ tc->custom.mode.free_cb = freeVertSlideVerts;
+ }
+ }
+
+ if (ok == false) {
+ t->state = TRANS_CANCEL;
+ return;
+ }
+
+ trans_mesh_customdata_correction_init(t);
+
+ /* set custom point first if you want value to be initialized by init */
+ calcVertSlideCustomPoints(t);
+ initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
+
+ 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;
+
+ copy_v3_fl(t->num.val_inc, t->snap[1]);
+ t->num.unit_sys = t->scene->unit.system;
+ t->num.unit_type[0] = B_UNIT_NONE;
+
+ t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
+}
+
+void initVertSlide(TransInfo *t)
+{
+ initVertSlide_ex(t, false, false, true);
+}
+/** \} */
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 09992e8be0e..d643244e6ca 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -30,10 +30,10 @@
#include "BLT_translation.h"
#include "BKE_context.h"
-#include "BKE_global.h"
-#include "BKE_report.h"
#include "BKE_editmesh.h"
+#include "BKE_global.h"
#include "BKE_layer.h"
+#include "BKE_report.h"
#include "BKE_scene.h"
#include "RNA_access.h"
@@ -42,8 +42,8 @@
#include "WM_api.h"
#include "WM_message.h"
-#include "WM_types.h"
#include "WM_toolsystem.h"
+#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@@ -75,6 +75,7 @@ static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
static const char OP_TILT[] = "TRANSFORM_OT_tilt";
static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
static const char OP_MIRROR[] = "TRANSFORM_OT_mirror";
+static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
@@ -94,6 +95,7 @@ static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot);
static void TRANSFORM_OT_tilt(struct wmOperatorType *ot);
static void TRANSFORM_OT_trackball(struct wmOperatorType *ot);
static void TRANSFORM_OT_mirror(struct wmOperatorType *ot);
+static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
@@ -114,6 +116,7 @@ static TransformModeItem transform_modes[] = {
{OP_TILT, TFM_TILT, TRANSFORM_OT_tilt},
{OP_TRACKBALL, TFM_TRACKBALL, TRANSFORM_OT_trackball},
{OP_MIRROR, TFM_MIRROR, TRANSFORM_OT_mirror},
+ {OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
{OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
{OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
{OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
@@ -220,6 +223,9 @@ static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+
return OPERATOR_FINISHED;
}
@@ -230,12 +236,11 @@ static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent
static bool delete_orientation_poll(bContext *C)
{
- Scene *scene = CTX_data_scene(C);
-
if (ED_operator_areaactive(C) == 0) {
return 0;
}
+ Scene *scene = CTX_data_scene(C);
return ((scene->orientation_slots[SCE_ORIENT_DEFAULT].type >= V3D_ORIENT_CUSTOM) &&
(scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom != -1));
}
@@ -261,6 +266,7 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
const bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
const bool use_view = RNA_boolean_get(op->ptr, "use_view");
View3D *v3d = CTX_wm_view3d(C);
+ Scene *scene = CTX_data_scene(C);
RNA_string_get(op->ptr, "name", name);
@@ -271,10 +277,18 @@ static int create_orientation_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite);
+ if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create orientation");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (use) {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
+ WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
+ }
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
- WM_event_add_notifier(C, NC_SCENE | NA_EDITED, CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -702,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags)
prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
+
+ if (flags & P_POST_TRANSFORM) {
+ prop = RNA_def_boolean(ot->srna,
+ "use_automerge_and_split",
+ 0,
+ "Auto Merge & Split",
+ "Forces the use of Auto Merge & Split");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
}
static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
@@ -727,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
Transform_Properties(ot,
P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
- P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT);
+ P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
}
static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
@@ -890,8 +913,8 @@ static bool transform_shear_poll(bContext *C)
return false;
}
- ScrArea *sa = CTX_wm_area(C);
- return sa && !ELEM(sa->spacetype, SPACE_ACTION);
+ ScrArea *area = CTX_wm_area(C);
+ return area && !ELEM(area->spacetype, SPACE_ACTION);
}
static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
@@ -1015,6 +1038,30 @@ static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
}
+static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Scale B-Bone";
+ ot->description = "Scale selected bendy bones display size";
+ ot->idname = OP_BONE_SIZE;
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ /* api callbacks */
+ ot->invoke = transform_invoke;
+ ot->exec = transform_exec;
+ ot->modal = transform_modal;
+ ot->cancel = transform_cancel;
+ ot->poll = ED_operator_editarmature;
+ ot->poll_property = transform_poll_property;
+
+ RNA_def_float_translation(
+ ot->srna, "value", 2, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX);
+
+ WM_operatortype_props_advanced_begin(ot);
+
+ Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_MIRROR);
+}
+
static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -1221,8 +1268,8 @@ static int transform_from_gizmo_invoke(bContext *C,
{
bToolRef *tref = WM_toolsystem_ref_from_context(C);
if (tref) {
- ARegion *ar = CTX_wm_region(C);
- wmGizmoMap *gzmap = ar->gizmo_map;
+ ARegion *region = CTX_wm_region(C);
+ wmGizmoMap *gzmap = region->gizmo_map;
wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_xform_gizmo") : NULL;
if (gzgroup != NULL) {
PointerRNA gzg_ptr;
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index 1952a2c862e..81c63278366 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -18,9 +18,9 @@
* \ingroup edtransform
*/
-#include <string.h>
-#include <stddef.h>
#include <ctype.h>
+#include <stddef.h>
+#include <string.h>
#include "MEM_guardedalloc.h"
@@ -34,15 +34,15 @@
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
-#include "BLI_math.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_action.h"
-#include "BKE_curve.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_report.h"
@@ -296,7 +296,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa
return true;
}
-void BIF_createTransformOrientation(bContext *C,
+bool BIF_createTransformOrientation(bContext *C,
ReportList *reports,
const char *name,
const bool use_view,
@@ -333,6 +333,7 @@ void BIF_createTransformOrientation(bContext *C,
if (activate && ts != NULL) {
BIF_selectTransformOrientation(C, ts);
}
+ return (ts != NULL);
}
TransformOrientation *addMatrixSpace(bContext *C,
@@ -406,14 +407,19 @@ bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3]
return true;
}
-static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
+/* Updates all `BONE_TRANSFORM` flags.
+ * Returns total number of bones with `BONE_TRANSFORM`.
+ * Note: `transform_convert_pose_transflags_update` has a similar logic. */
+static int armature_bone_transflags_update_recursive(bArmature *arm,
+ ListBase *lb,
+ const bool do_it)
{
Bone *bone;
bool do_next;
int total = 0;
for (bone = lb->first; bone; bone = bone->next) {
- bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR);
+ bone->flag &= ~BONE_TRANSFORM;
do_next = do_it;
if (do_it) {
if (bone->layer & arm->layer) {
@@ -426,18 +432,18 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
}
}
}
- total += count_bone_select(arm, &bone->childbase, do_next);
+ total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next);
}
return total;
}
-void initTransformOrientation(bContext *C, TransInfo *t)
+void initTransformOrientation(bContext *C, TransInfo *t, short orientation)
{
Object *ob = CTX_data_active_object(C);
Object *obedit = CTX_data_active_object(C);
- switch (t->orientation.user) {
+ switch (orientation) {
case V3D_ORIENT_GLOBAL:
unit_m3(t->spacemtx);
BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename));
@@ -470,32 +476,33 @@ void initTransformOrientation(bContext *C, TransInfo *t)
break;
- case V3D_ORIENT_VIEW:
- if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
- RegionView3D *rv3d = t->ar->regiondata;
- float mat[3][3];
-
+ case V3D_ORIENT_VIEW: {
+ float mat[3][3];
+ if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) {
BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename));
- copy_m3_m4(mat, rv3d->viewinv);
+ copy_m3_m4(mat, t->viewinv);
normalize_m3(mat);
- copy_m3_m3(t->spacemtx, mat);
}
else {
- unit_m3(t->spacemtx);
+ unit_m3(mat);
}
+ negate_v3(mat[2]);
+ copy_m3_m3(t->spacemtx, mat);
break;
+ }
case V3D_ORIENT_CURSOR: {
BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename));
BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx);
break;
}
case V3D_ORIENT_CUSTOM_MATRIX:
- /* Already set. */
BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename));
+ copy_m3_m3(t->spacemtx, t->orientation.custom_matrix);
break;
case V3D_ORIENT_CUSTOM:
+ default:
+ BLI_assert(orientation >= V3D_ORIENT_CUSTOM);
BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename));
-
if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) {
/* pass */
}
@@ -504,31 +511,17 @@ void initTransformOrientation(bContext *C, TransInfo *t)
}
break;
}
-
- if (t->orient_matrix_is_set == false) {
- t->orient_matrix_is_set = true;
- if (t->flag & T_MODAL) {
- /* Rotate for example defaults to operating on the view plane. */
- t->orientation.unset = V3D_ORIENT_VIEW;
- copy_m3_m4(t->orient_matrix, t->viewinv);
- normalize_m3(t->orient_matrix);
- }
- else {
- copy_m3_m3(t->orient_matrix, t->spacemtx);
- }
- negate_m3(t->orient_matrix);
- }
}
/**
* utility function - get first n, selected vert/edge/faces
*/
-static unsigned int bm_mesh_elems_select_get_n__internal(
- BMesh *bm, BMElem **elems, const unsigned int n, const BMIterType itype, const char htype)
+static uint bm_mesh_elems_select_get_n__internal(
+ BMesh *bm, BMElem **elems, const uint n, const BMIterType itype, const char htype)
{
BMIter iter;
BMElem *ele;
- unsigned int i;
+ uint i;
BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
@@ -579,18 +572,18 @@ static unsigned int bm_mesh_elems_select_get_n__internal(
return i;
}
-static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totvertsel), BM_VERTS_OF_MESH, BM_VERT);
}
-static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n)
+static uint bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totedgesel), BM_EDGES_OF_MESH, BM_EDGE);
}
#if 0
-static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+static uint bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const uint n)
{
return bm_mesh_elems_select_get_n__internal(
bm, (BMElem **)elems, min_ii(n, bm->totfacesel), BM_FACES_OF_MESH, BM_FACE);
@@ -1071,10 +1064,9 @@ int getTransformOrientation_ex(const bContext *C,
ok = true;
}
else {
- int totsel;
-
- totsel = count_bone_select(arm, &arm->bonebase, true);
- if (totsel) {
+ int transformed_len;
+ transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true);
+ if (transformed_len) {
/* use channels to get stats */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 4b6ab2045c0..cb4446deb99 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -21,36 +21,36 @@
* \ingroup edtransform
*/
-#include <stdlib.h>
-#include <math.h>
#include <float.h>
+#include <math.h>
#include <stdio.h>
+#include <stdlib.h>
#include "PIL_time.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
#include "DNA_meshdata_types.h" /* Temporary, for snapping to other unselected meshes */
#include "DNA_node_types.h"
-#include "DNA_space_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
-#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "GPU_immediate.h"
#include "GPU_state.h"
-#include "BKE_layer.h"
-#include "BKE_object.h"
-#include "BKE_anim.h" /* for duplis */
#include "BKE_context.h"
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
-#include "BKE_sequencer.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_sequencer.h"
#include "RNA_access.h"
@@ -59,9 +59,9 @@
#include "ED_image.h"
#include "ED_markers.h"
#include "ED_node.h"
+#include "ED_transform_snap_object_context.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
-#include "ED_transform_snap_object_context.h"
#include "DEG_depsgraph.h"
@@ -158,7 +158,7 @@ static bool doForceIncrementSnap(const TransInfo *t)
void drawSnapping(const struct bContext *C, TransInfo *t)
{
- unsigned char col[4], selectedCol[4], activeCol[4];
+ uchar col[4], selectedCol[4], activeCol[4];
if (!activeSnap(t)) {
return;
@@ -283,7 +283,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NODE) {
if (validSnap(t)) {
- ARegion *ar = CTX_wm_region(C);
+ ARegion *region = CTX_wm_region(C);
TransSnapPoint *p;
float size;
@@ -304,13 +304,13 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
immUniformColor4ubv(col);
}
- ED_node_draw_snap(&ar->v2d, p->co, size, 0, pos);
+ ED_node_draw_snap(&region->v2d, p->co, size, 0, pos);
}
if (t->tsnap.status & POINT_INIT) {
immUniformColor4ubv(activeCol);
- ED_node_draw_snap(&ar->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
+ ED_node_draw_snap(&region->v2d, t->tsnap.snapPoint, size, t->tsnap.snapNodeBorder, pos);
}
immUnbindProgram();
@@ -373,10 +373,11 @@ void applyProject(TransInfo *t)
copy_v3_v3(iloc, td->ob->obmat[3]);
}
- if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
+ if (ED_view3d_project_float_global(t->region, iloc, mval_fl, V3D_PROJ_TEST_NOP) ==
V3D_PROJ_RET_OK) {
if (ED_transform_snap_object_project_view3d(
t->tsnap.object_context,
+ t->depsgraph,
SCE_SNAP_MODE_FACE,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
@@ -686,7 +687,7 @@ static void initSnappingMode(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D) {
if (t->tsnap.object_context == NULL) {
t->tsnap.object_context = ED_transform_snap_object_context_create_view3d(
- bmain, t->scene, t->depsgraph, 0, t->ar, t->view);
+ bmain, t->scene, 0, t->region, t->view);
ED_transform_snap_object_context_set_editmesh_callbacks(
t->tsnap.object_context,
@@ -847,7 +848,7 @@ eRedrawFlag updateSelectedSnapPoint(TransInfo *t)
for (p = t->tsnap.points.first; p; p = p->next) {
float dist_sq;
- if (ED_view3d_project_float_global(t->ar, p->co, screen_loc, V3D_PROJ_TEST_NOP) !=
+ if (ED_view3d_project_float_global(t->region, p->co, screen_loc, V3D_PROJ_TEST_NOP) !=
V3D_PROJ_RET_OK) {
continue;
}
@@ -936,7 +937,7 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3])
else {
if (t->spacetype == SPACE_VIEW3D) {
if (t->options & CTX_PAINT_CURVE) {
- if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) !=
+ if (ED_view3d_project_float_global(t->region, point, point, V3D_PROJ_TEST_NOP) !=
V3D_PROJ_RET_OK) {
zero_v3(point); /* no good answer here... */
}
@@ -1105,10 +1106,10 @@ static void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
}
else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) {
if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) {
- Image *ima = ED_space_image(t->sa->spacedata.first);
+ Image *ima = ED_space_image(t->area->spacedata.first);
float co[2];
- UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
+ UI_view2d_region_to_view(&t->region->v2d, t->mval[0], t->mval[1], &co[0], &co[1]);
uint objects_len = 0;
Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
@@ -1365,6 +1366,7 @@ short snapObjectsTransform(
float *target = (t->tsnap.status & TARGET_INIT) ? t->tsnap.snapTarget : t->center_global;
return ED_transform_snap_object_project_view3d_ex(
t->tsnap.object_context,
+ t->depsgraph,
t->scene->toolsettings->snap_mode,
&(const struct SnapObjectParams){
.snap_select = t->tsnap.modeSelect,
@@ -1389,17 +1391,26 @@ short snapObjectsTransform(
/** \name Peeling
* \{ */
-bool peelObjectsSnapContext(SnapObjectContext *sctx,
- const float mval[2],
- const struct SnapObjectParams *params,
- const bool use_peel_object,
- /* return args */
- float r_loc[3],
- float r_no[3],
- float *r_thickness)
+bool peelObjectsTransform(TransInfo *t,
+ const float mval[2],
+ const bool use_peel_object,
+ /* return args */
+ float r_loc[3],
+ float r_no[3],
+ float *r_thickness)
{
ListBase depths_peel = {0};
- ED_transform_snap_object_project_all_view3d_ex(sctx, params, mval, -1.0f, false, &depths_peel);
+ ED_transform_snap_object_project_all_view3d_ex(
+ t->tsnap.object_context,
+ t->depsgraph,
+ &(const struct SnapObjectParams){
+ .snap_select = t->tsnap.modeSelect,
+ .use_object_edit_cage = (t->flag & T_EDIT) != 0,
+ },
+ mval,
+ -1.0f,
+ false,
+ &depths_peel);
if (!BLI_listbase_is_empty(&depths_peel)) {
/* At the moment we only use the hits of the first object */
@@ -1455,26 +1466,6 @@ bool peelObjectsSnapContext(SnapObjectContext *sctx,
return false;
}
-bool peelObjectsTransform(TransInfo *t,
- const float mval[2],
- const bool use_peel_object,
- /* return args */
- float r_loc[3],
- float r_no[3],
- float *r_thickness)
-{
- return peelObjectsSnapContext(t->tsnap.object_context,
- mval,
- &(const struct SnapObjectParams){
- .snap_select = t->tsnap.modeSelect,
- .use_object_edit_cage = (t->flag & T_EDIT) != 0,
- },
- use_peel_object,
- r_loc,
- r_no,
- r_thickness);
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1504,14 +1495,14 @@ static NodeBorder snapNodeBorder(int snap_node_mode)
static bool snapNode(ToolSettings *ts,
SpaceNode *UNUSED(snode),
- ARegion *ar,
+ ARegion *region,
bNode *node,
const int mval[2],
float r_loc[2],
float *r_dist_px,
char *r_node_border)
{
- View2D *v2d = &ar->v2d;
+ View2D *v2d = &region->v2d;
NodeBorder border = snapNodeBorder(ts->snap_node_mode);
bool retval = false;
rcti totr;
@@ -1564,7 +1555,7 @@ static bool snapNode(ToolSettings *ts,
static bool snapNodes(ToolSettings *ts,
SpaceNode *snode,
- ARegion *ar,
+ ARegion *region,
const int mval[2],
eSnapSelect snap_select,
float r_loc[2],
@@ -1578,8 +1569,8 @@ static bool snapNodes(ToolSettings *ts,
*r_node_border = 0;
for (node = ntree->nodes.first; node; node = node->next) {
- if (snapNodeTest(&ar->v2d, node, snap_select)) {
- retval |= snapNode(ts, snode, ar, node, mval, r_loc, r_dist_px, r_node_border);
+ if (snapNodeTest(&region->v2d, node, snap_select)) {
+ retval |= snapNode(ts, snode, region, node, mval, r_loc, r_dist_px, r_node_border);
}
}
@@ -1590,8 +1581,8 @@ bool snapNodesTransform(
TransInfo *t, const int mval[2], float r_loc[2], float *r_dist_px, char *r_node_border)
{
return snapNodes(t->settings,
- t->sa->spacedata.first,
- t->ar,
+ t->area->spacedata.first,
+ t->region,
mval,
t->tsnap.modeSelect,
r_loc,
@@ -1691,7 +1682,7 @@ void snapSequenceBounds(TransInfo *t, const int mval[2])
}
/* convert to frame range */
- UI_view2d_region_to_view(&t->ar->v2d, mval[0], mval[1], &xmouse, &ymouse);
+ UI_view2d_region_to_view(&t->region->v2d, mval[0], mval[1], &xmouse, &ymouse);
mframe = round_fl_to_int(xmouse);
/* now find the closest sequence */
frame = BKE_sequencer_find_next_prev_edit(t->scene, mframe, SEQ_SIDE_BOTH, true, false, true);
@@ -1723,9 +1714,9 @@ static void applyGridIncrement(
if (use_aspect) {
/* custom aspect for fcurve */
if (t->spacetype == SPACE_GRAPH) {
- View2D *v2d = &t->ar->v2d;
+ View2D *v2d = &t->region->v2d;
Scene *scene = t->scene;
- SpaceGraph *sipo = t->sa->spacedata.first;
+ SpaceGraph *sipo = t->area->spacedata.first;
asp_local[0] = UI_view2d_grid_resolution_x__frames_or_seconds(
v2d, scene, sipo->flag & SIPO_DRAWTIME);
asp_local[1] = UI_view2d_grid_resolution_y__values(v2d);
diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h
index a188e2eb829..c088cf80f0d 100644
--- a/source/blender/editors/transform/transform_snap.h
+++ b/source/blender/editors/transform/transform_snap.h
@@ -35,14 +35,6 @@ bool peelObjectsTransform(struct TransInfo *t,
float r_loc[3],
float r_no[3],
float *r_thickness);
-bool peelObjectsSnapContext(struct SnapObjectContext *sctx,
- const float mval[2],
- const struct SnapObjectParams *params,
- const bool use_peel_object,
- /* return args */
- float r_loc[3],
- float r_no[3],
- float *r_thickness);
short snapObjectsTransform(struct TransInfo *t,
const float mval[2],
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index 63b9eb3937a..2cfeedbb346 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -19,50 +19,44 @@
*/
#include <stdlib.h>
-#include <math.h>
-#include <float.h>
-#include <stdio.h>
#include "MEM_guardedalloc.h"
-#include "BLI_math.h"
-#include "BLI_kdopbvh.h"
-#include "BLI_memarena.h"
#include "BLI_ghash.h"
+#include "BLI_kdopbvh.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_memarena.h"
#include "BLI_utildefines.h"
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_view3d_types.h"
-#include "BKE_bvhutils.h"
#include "BKE_armature.h"
+#include "BKE_bvhutils.h"
#include "BKE_curve.h"
-#include "BKE_object.h"
-#include "BKE_anim.h" /* for duplis */
+#include "BKE_duplilist.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
#include "BKE_main.h"
-#include "BKE_tracking.h"
-#include "BKE_context.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
+#include "BKE_object.h"
+#include "BKE_tracking.h"
-#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
-#include "ED_transform.h"
+#include "ED_armature.h"
#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
-#include "ED_armature.h"
-#include "transform.h"
+#include "ED_transform.h"
/* -------------------------------------------------------------------- */
/** \name Internal Data Types
@@ -92,30 +86,32 @@ typedef struct SnapObjectData {
SNAP_MESH = 1,
SNAP_EDIT_MESH,
} type;
-} SnapObjectData;
-
-typedef struct SnapObjectData_Mesh {
- SnapObjectData sd;
- BVHTreeFromMesh treedata;
- const struct MPoly *poly;
- BVHTree *bvhtree[2]; /* from loose verts and from loose edges */
- uint has_looptris : 1;
- uint has_loose_edge : 1;
- uint has_loose_vert : 1;
-} SnapObjectData_Mesh;
+ BVHTree *bvhtree[2]; /* MESH: loose edges, loose verts
+ * EDIT_MESH: verts, edges. */
+ bool cached[2];
-typedef struct SnapObjectData_EditMesh {
- SnapObjectData sd;
- BVHTreeFromEditMesh *bvh_trees[3];
- float min[3], max[3];
-
-} SnapObjectData_EditMesh;
+ union {
+ struct {
+ /* SNAP_MESH */
+ BVHTreeFromMesh treedata_mesh;
+ const struct MPoly *poly;
+ uint has_looptris : 1;
+ uint has_loose_edge : 1;
+ uint has_loose_vert : 1;
+ };
+ struct {
+ /* SNAP_EDIT_MESH */
+ BVHTreeFromEditMesh treedata_editmesh;
+ float min[3], max[3];
+ struct LinkNode **bvh_cache_p;
+ };
+ };
+} SnapObjectData;
struct SnapObjectContext {
Main *bmain;
Scene *scene;
- Depsgraph *depsgraph;
int flag;
@@ -124,7 +120,7 @@ struct SnapObjectContext {
bool use_v3d;
struct {
const struct View3D *v3d;
- const struct ARegion *ar;
+ const struct ARegion *region;
} v3d_data;
/* Object -> SnapObjectData map */
@@ -149,7 +145,7 @@ struct SnapObjectContext {
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Common Utilities
+/** \name Snap Object Data
* \{ */
/**
@@ -166,6 +162,45 @@ static void bm_mesh_minmax(BMesh *bm, float r_min[3], float r_max[3])
}
}
+static void snap_object_data_mesh_clear(SnapObjectData *sod)
+{
+ BLI_assert(sod->type == SNAP_MESH);
+ for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
+ if (!sod->cached[i]) {
+ BLI_bvhtree_free(sod->bvhtree[i]);
+ }
+ sod->bvhtree[i] = NULL;
+ }
+ free_bvhtree_from_mesh(&sod->treedata_mesh);
+}
+
+static void snap_object_data_editmesh_clear(SnapObjectData *sod)
+{
+ BLI_assert(sod->type == SNAP_EDIT_MESH);
+ for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
+ if (!sod->cached[i]) {
+ BLI_bvhtree_free(sod->bvhtree[i]);
+ }
+ sod->bvhtree[i] = NULL;
+ }
+ free_bvhtree_from_editmesh(&sod->treedata_editmesh);
+}
+
+static void snap_object_data_clear(SnapObjectData *sod)
+{
+ switch (sod->type) {
+ case SNAP_MESH: {
+ snap_object_data_mesh_clear(sod);
+ break;
+ }
+ case SNAP_EDIT_MESH: {
+ snap_object_data_editmesh_clear(sod);
+ break;
+ }
+ }
+ memset(&sod->type, 0x0, sizeof(*sod) - offsetof(SnapObjectData, type));
+}
+
static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *ob)
{
SnapObjectData *sod = BLI_ghash_lookup(sctx->cache.object_map, ob);
@@ -181,29 +216,55 @@ static SnapObjectData *snap_object_data_lookup(SnapObjectContext *sctx, Object *
return sod;
}
-static SnapObjectData_Mesh *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
+static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object *ob)
{
+ SnapObjectData *sod;
void **sod_p;
+ bool init = false;
+
if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_MESH);
+ sod = *sod_p;
+ if (sod->type != SNAP_MESH) {
+ snap_object_data_clear(sod);
+ init = true;
+ }
}
else {
- SnapObjectData_Mesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
- sod->sd.type = SNAP_MESH;
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ init = true;
+ }
+
+ if (init) {
+ sod->type = SNAP_MESH;
/* start assuming that it has each of these element types */
sod->has_looptris = true;
sod->has_loose_edge = true;
sod->has_loose_vert = true;
}
- return *sod_p;
+ return sod;
}
-static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext *sctx,
- Object *ob,
- BMEditMesh *em)
+static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob)
{
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (em->mesh_eval_final) {
+ return &em->mesh_eval_final->runtime.bvh_cache;
+ }
+ if (em->mesh_eval_cage) {
+ return &em->mesh_eval_cage->runtime.bvh_cache;
+ }
+
+ return &((Mesh *)ob->data)->runtime.bvh_cache;
+}
+
+static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
+ Object *ob,
+ BMEditMesh *em)
+{
+ SnapObjectData *sod;
void **sod_p;
+ bool init = false, init_min_max = true, clear_cache = false;
{
/* Use object-data as the key in ghash since the editmesh
@@ -221,18 +282,83 @@ static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext
}
if (BLI_ghash_ensure_p(sctx->cache.object_map, ob, &sod_p)) {
- BLI_assert(((SnapObjectData *)*sod_p)->type == SNAP_EDIT_MESH);
+ sod = *sod_p;
+ bool clear = false;
+ /* Check if the geometry has changed. */
+ if (sod->type != SNAP_EDIT_MESH) {
+ clear = true;
+ }
+ else if (sod->treedata_editmesh.em != em) {
+ clear_cache = true;
+ init = true;
+ }
+ else if (sod->bvh_cache_p) {
+ if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) {
+ clear_cache = true;
+ init = true;
+ }
+ else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
+ !bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) {
+ /* The tree is owned by the EditMesh and may have been freed since we last used! */
+ clear = true;
+ }
+ else if (sod->bvhtree[0] && sod->cached[0] &&
+ !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) {
+ /* The tree is owned by the EditMesh and may have been freed since we last used! */
+ clear = true;
+ }
+ else if (sod->bvhtree[1] && sod->cached[1] &&
+ !bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) {
+ /* The tree is owned by the EditMesh and may have been freed since we last used! */
+ clear = true;
+ }
+ }
+
+ if (clear) {
+ snap_object_data_clear(sod);
+ init = true;
+ }
}
else {
- SnapObjectData_EditMesh *sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena,
- sizeof(*sod));
- sod->sd.type = SNAP_EDIT_MESH;
- bm_mesh_minmax(em->bm, sod->min, sod->max);
+ sod = *sod_p = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(*sod));
+ init = true;
+ }
+
+ if (init) {
+ sod->type = SNAP_EDIT_MESH;
+ sod->treedata_editmesh.em = em;
+
+ if (clear_cache) {
+ /* Only init min and max when you have a non-custom bvhtree pending. */
+ init_min_max = false;
+ if (sod->treedata_editmesh.cached) {
+ sod->treedata_editmesh.tree = NULL;
+ init_min_max = true;
+ }
+ for (int i = 0; i < ARRAY_SIZE(sod->bvhtree); i++) {
+ if (sod->cached[i]) {
+ sod->bvhtree[i] = NULL;
+ init_min_max = true;
+ }
+ }
+ }
+
+ if (init_min_max) {
+ bm_mesh_minmax(em->bm, sod->min, sod->max);
+ }
+
+ sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob);
}
- return *sod_p;
+ return sod;
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Iterator
+ * \{ */
+
typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
bool is_obedit,
bool use_backface_culling,
@@ -247,11 +373,12 @@ typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
* \param snap_select: from enum #eSnapSelect.
*/
static void iter_snap_objects(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
IterSnapObjsCallback sob_callback,
void *data)
{
- ViewLayer *view_layer = DEG_get_input_view_layer(sctx->depsgraph);
+ ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph);
const View3D *v3d = sctx->v3d_data.v3d;
const eSnapSelect snap_select = params->snap_select;
const bool use_object_edit_cage = params->use_object_edit_cage;
@@ -282,10 +409,10 @@ static void iter_snap_objects(SnapObjectContext *sctx,
}
}
- Object *obj_eval = DEG_get_evaluated_object(sctx->depsgraph, base->object);
+ Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
if (obj_eval->transflag & OB_DUPLI) {
DupliObject *dupli_ob;
- ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
+ ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
sob_callback(
sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data);
@@ -320,7 +447,7 @@ struct RayCastAll_Data {
float local_scale;
Object *ob;
- unsigned int ob_uuid;
+ uint ob_uuid;
/* output data */
ListBase *hit_list;
@@ -333,7 +460,7 @@ static struct SnapObjectHitDepth *hit_depth_create(const float depth,
int index,
Object *ob,
const float obmat[4][4],
- unsigned int ob_uuid)
+ uint ob_uuid)
{
struct SnapObjectHitDepth *hit = MEM_mallocN(sizeof(*hit), __func__);
@@ -459,7 +586,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
Object *ob,
Mesh *me,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_hide,
bool use_backface_culling,
/* read/write args */
@@ -516,9 +643,9 @@ static bool raycastMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
- BVHTreeFromMesh *treedata = &sod->treedata;
+ BVHTreeFromMesh *treedata = &sod->treedata_mesh;
/* The tree is owned by the Mesh and may have been freed since we last used. */
if (treedata->tree) {
@@ -634,7 +761,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
Object *ob,
BMEditMesh *em,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_backface_culling,
/* read/write args */
float *ray_depth,
@@ -668,7 +795,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
local_depth *= local_scale;
}
- SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
/* Test BoundBox */
@@ -690,30 +817,18 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
len_diff = 0.0f;
}
- if (sod->bvh_trees[2] == NULL) {
- sod->bvh_trees[2] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(BVHTreeFromEditMesh));
- }
-
- BVHTreeFromEditMesh *treedata = sod->bvh_trees[2];
-
- BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache;
-
- if (sctx->callbacks.edit_mesh.test_face_fn == NULL) {
- /* The tree is owned by the Mesh and may have been freed since we last used! */
- if (treedata->tree && !bvhcache_has_tree(*em_bvh_cache, treedata->tree)) {
- free_bvhtree_from_editmesh(treedata);
- }
- }
+ BVHTreeFromEditMesh *treedata = &sod->treedata_editmesh;
if (treedata->tree == NULL) {
- /* Get original version of the edit_mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BLI_assert(sod->treedata_editmesh.em == BKE_editmesh_from_object(DEG_get_original_object(ob)));
+ em = sod->treedata_editmesh.em;
if (sctx->callbacks.edit_mesh.test_face_fn) {
- BMesh *bm = em_orig->bm;
- BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em_orig->tottri);
+ BMesh *bm = em->bm;
+ BLI_assert(poly_to_tri_count(bm->totface, bm->totloop) == em->tottri);
- BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em_orig->tottri, __func__);
+ BLI_bitmap *elem_mask = BLI_BITMAP_NEW(em->tottri, __func__);
int looptri_num_active = BM_iter_mesh_bitmap_from_filter_tessface(
bm,
elem_mask,
@@ -721,14 +836,14 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_looptri_ex(
- treedata, em_orig, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL);
+ treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL);
MEM_freeN(elem_mask);
}
else {
/* Only cache if bvhtree is created without a mask.
* This helps keep a standardized bvhtree in cache. */
- BKE_bvhtree_from_editmesh_get(treedata, em_orig, 4, BVHTREE_FROM_EM_LOOPTRI, em_bvh_cache);
+ BKE_bvhtree_from_editmesh_get(treedata, em, 4, BVHTREE_FROM_EM_LOOPTRI, sod->bvh_cache_p);
}
if (treedata->tree == NULL) {
@@ -795,10 +910,9 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
retval = true;
if (r_index) {
- /* Get original version of the edit_mesh. */
- BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
+ em = sod->treedata_editmesh.em;
- *r_index = BM_elem_index_get(em_orig->looptris[hit.index][0]->f);
+ *r_index = BM_elem_index_get(em->looptris[hit.index][0]->f);
}
}
}
@@ -817,7 +931,7 @@ static bool raycastObj(SnapObjectContext *sctx,
const float ray_dir[3],
Object *ob,
const float obmat[4][4],
- const unsigned int ob_index,
+ const uint ob_index,
bool use_obedit,
bool use_occlusion_test,
bool use_backface_culling,
@@ -850,13 +964,14 @@ static bool raycastObj(SnapObjectContext *sctx,
Mesh *me = ob->data;
bool use_hide = false;
if (BKE_object_is_in_editmode(ob)) {
- BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_obedit) {
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
retval = raycastEditMesh(sctx,
ray_start,
ray_dir,
ob,
- em,
+ em_orig,
obmat,
ob_index,
use_backface_culling,
@@ -867,9 +982,12 @@ static bool raycastObj(SnapObjectContext *sctx,
r_hit_list);
break;
}
- else if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
- use_hide = true;
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (em->mesh_eval_final) {
+ me = em->mesh_eval_final;
+ use_hide = true;
+ }
}
}
retval = raycastMesh(sctx,
@@ -891,12 +1009,13 @@ static bool raycastObj(SnapObjectContext *sctx,
case OB_CURVE:
case OB_SURF:
case OB_FONT: {
- if (ob->runtime.mesh_eval) {
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ if (mesh_eval) {
retval = raycastMesh(sctx,
ray_start,
ray_dir,
ob,
- ob->runtime.mesh_eval,
+ mesh_eval,
obmat,
ob_index,
false,
@@ -927,7 +1046,7 @@ static bool raycastObj(SnapObjectContext *sctx,
struct RaycastObjUserData {
const float *ray_start;
const float *ray_dir;
- unsigned int ob_index;
+ uint ob_index;
/* read/write args */
float *ray_depth;
/* return args */
@@ -997,6 +1116,7 @@ static void raycast_obj_cb(SnapObjectContext *sctx,
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*/
static bool raycastObjects(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_dir[3],
@@ -1025,7 +1145,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
.ret = false,
};
- iter_snap_objects(sctx, params, raycast_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, raycast_obj_cb, &data);
return data.ret;
}
@@ -1037,7 +1157,7 @@ static bool raycastObjects(SnapObjectContext *sctx,
* \{ */
/* Test BoundBox */
-static bool snap_bound_box_check_dist(float min[3],
+static bool snap_bound_box_check_dist(const float min[3],
const float max[3],
const float lpmat[4][4],
const float win_size[2],
@@ -1107,7 +1227,7 @@ static void cb_mlooptri_edges_get(const int index, int v_index[3], const BVHTree
const MLoopTri *lt = &data->looptri[index];
for (int j = 2, j_next = 0; j_next < 3; j = j_next++) {
const MEdge *ed = &medge[mloop[lt->tri[j]].e];
- unsigned int tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
+ uint tri_edge[2] = {mloop[lt->tri[j]].v, mloop[lt->tri[j_next]].v};
if (ELEM(ed->v1, tri_edge[0], tri_edge[1]) && ELEM(ed->v2, tri_edge[0], tri_edge[1])) {
// printf("real edge found\n");
v_index[j] = mloop[lt->tri[j]].e;
@@ -1392,7 +1512,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BVHTreeNearest nearest = {
.index = -1,
- .dist_sq = SQUARE(*dist_px),
+ .dist_sq = square_f(*dist_px),
};
SnapObjectData *sod = snap_object_data_lookup(sctx, ob);
@@ -1400,14 +1520,14 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
BLI_assert(sod != NULL);
if (sod->type == SNAP_MESH) {
- BVHTreeFromMesh *treedata = &((SnapObjectData_Mesh *)sod)->treedata;
+ BVHTreeFromMesh *treedata = &sod->treedata_mesh;
nearest2d.userdata = treedata;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
- const MPoly *mp = &((SnapObjectData_Mesh *)sod)->poly[*r_index];
+ const MPoly *mp = &sod->poly[*r_index];
const MLoop *ml = &treedata->loop[mp->loopstart];
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
elem = SCE_SNAP_MODE_EDGE;
@@ -1435,7 +1555,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
}
else {
BLI_assert(sod->type == SNAP_EDIT_MESH);
- BMEditMesh *em = BKE_editmesh_from_object(ob);
+ BMEditMesh *em = sod->treedata_editmesh.em;
nearest2d.userdata = em;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
@@ -1525,14 +1645,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
nearest2d.use_backface_culling = use_backface_culling;
if (sod->type == SNAP_MESH) {
- nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
+ nearest2d.userdata = &sod->treedata_mesh;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get;
nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy;
}
else {
BLI_assert(sod->type == SNAP_EDIT_MESH);
- nearest2d.userdata = BKE_editmesh_from_object(ob);
+ nearest2d.userdata = sod->treedata_editmesh.em;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get;
nearest2d.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get;
nearest2d.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy;
@@ -1557,7 +1677,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
BVHTreeNearest nearest = {
.index = -1,
- .dist_sq = SQUARE(original_dist_px),
+ .dist_sq = square_f(original_dist_px),
};
float lambda;
@@ -1690,7 +1810,7 @@ static short snapArmature(SnapData *snapdata,
return retval;
}
- float lpmat[4][4], dist_px_sq = SQUARE(*dist_px);
+ float lpmat[4][4], dist_px_sq = square_f(*dist_px);
mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
struct DistProjectedAABBPrecalc neasrest_precalc;
@@ -1718,7 +1838,7 @@ static short snapArmature(SnapData *snapdata,
bArmature *arm = ob->data;
if (arm->edbo) {
- for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) {
+ LISTBASE_FOREACH (EditBone *, eBone, arm->edbo) {
if (eBone->layer & arm->layer) {
/* skip hidden or moving (selected) bones */
if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) {
@@ -1761,7 +1881,7 @@ static short snapArmature(SnapData *snapdata,
}
}
else if (ob->pose && ob->pose->chanbase.first) {
- for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
Bone *bone = pchan->bone;
/* skip hidden bones */
if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) {
@@ -1837,7 +1957,7 @@ static short snapCurve(SnapData *snapdata,
}
Curve *cu = ob->data;
- float dist_px_sq = SQUARE(*dist_px);
+ float dist_px_sq = square_f(*dist_px);
float lpmat[4][4];
mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
@@ -1998,7 +2118,7 @@ static short snapEmpty(SnapData *snapdata,
}
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- float dist_px_sq = SQUARE(*dist_px);
+ float dist_px_sq = square_f(*dist_px);
float co[3];
copy_v3_v3(co, obmat[3]);
if (test_projected_vert_dist(&neasrest_precalc,
@@ -2040,7 +2160,7 @@ static short snapCamera(const SnapObjectContext *sctx,
Scene *scene = sctx->scene;
bool is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
- float dist_px_sq = SQUARE(*dist_px);
+ float dist_px_sq = square_f(*dist_px);
float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4];
MovieClip *clip = BKE_object_movieclip_get(scene, object, false);
@@ -2055,7 +2175,7 @@ static short snapCamera(const SnapObjectContext *sctx,
tracking = &clip->tracking;
- BKE_tracking_get_camera_object_matrix(scene, object, orig_camera_mat);
+ BKE_tracking_get_camera_object_matrix(object, orig_camera_mat);
invert_m4_m4(orig_camera_imat, orig_camera_mat);
invert_m4_m4(imat, obmat);
@@ -2151,7 +2271,7 @@ static short snapMesh(SnapObjectContext *sctx,
float lpmat[4][4];
mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- float dist_px_sq = SQUARE(*dist_px);
+ float dist_px_sq = square_f(*dist_px);
/* Test BoundBox */
BoundBox *bb = BKE_mesh_boundbox_get(ob);
@@ -2160,27 +2280,23 @@ static short snapMesh(SnapObjectContext *sctx,
return 0;
}
- SnapObjectData_Mesh *sod = snap_object_data_mesh_get(sctx, ob);
+ SnapObjectData *sod = snap_object_data_mesh_get(sctx, ob);
BVHTreeFromMesh *treedata, dummy_treedata;
- BVHTree **bvhtree;
- treedata = &sod->treedata;
- bvhtree = sod->bvhtree;
+ treedata = &sod->treedata_mesh;
/* The tree is owned by the Mesh and may have been freed since we last used! */
- if ((sod->has_looptris && treedata->tree &&
- !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) ||
- (sod->has_loose_edge && bvhtree[0] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0])) ||
- (sod->has_loose_vert && bvhtree[1] &&
- !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1]))) {
- BLI_assert(!treedata->tree || !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree));
- BLI_assert(!bvhtree[0] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[0]));
- BLI_assert(!bvhtree[1] || !bvhcache_has_tree(me->runtime.bvh_cache, bvhtree[1]));
-
+ if (treedata->cached && treedata->tree &&
+ !bvhcache_has_tree(me->runtime.bvh_cache, treedata->tree)) {
free_bvhtree_from_mesh(treedata);
- bvhtree[0] = NULL;
- bvhtree[1] = NULL;
+ }
+ if (sod->cached[0] && sod->bvhtree[0] &&
+ !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[0])) {
+ sod->bvhtree[0] = NULL;
+ }
+ if (sod->cached[1] && sod->bvhtree[1] &&
+ !bvhcache_has_tree(me->runtime.bvh_cache, sod->bvhtree[1])) {
+ sod->bvhtree[1] = NULL;
}
if (sod->has_looptris && treedata->tree == NULL) {
@@ -2191,9 +2307,10 @@ static short snapMesh(SnapObjectContext *sctx,
treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
}
}
- if (sod->has_loose_edge && bvhtree[0] == NULL) {
- bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
- sod->has_loose_edge = bvhtree[0] != NULL;
+ if (sod->has_loose_edge && sod->bvhtree[0] == NULL) {
+ sod->bvhtree[0] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEEDGES, 2);
+ sod->has_loose_edge = sod->bvhtree[0] != NULL;
+ sod->cached[0] = dummy_treedata.cached;
if (sod->has_loose_edge) {
BLI_assert(treedata->vert_allocated == false);
@@ -2206,9 +2323,10 @@ static short snapMesh(SnapObjectContext *sctx,
}
}
if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
- if (sod->has_loose_vert && bvhtree[1] == NULL) {
- bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
- sod->has_loose_vert = bvhtree[1] != NULL;
+ if (sod->has_loose_vert && sod->bvhtree[1] == NULL) {
+ sod->bvhtree[1] = BKE_bvhtree_from_mesh_get(&dummy_treedata, me, BVHTREE_FROM_LOOSEVERTS, 2);
+ sod->has_loose_vert = sod->bvhtree[1] != NULL;
+ sod->cached[1] = dummy_treedata.cached;
if (sod->has_loose_vert) {
BLI_assert(treedata->vert_allocated == false);
@@ -2226,7 +2344,7 @@ static short snapMesh(SnapObjectContext *sctx,
if (treedata->vert_allocated == false) {
treedata->vert = me->mvert; /* CustomData_get_layer(&me->vdata, CD_MVERT);? */
}
- if (treedata->tree || bvhtree[0]) {
+ if (treedata->tree || sod->bvhtree[0]) {
if (treedata->edge_allocated == false) {
/* If raycast has been executed before, `treedata->edge` can be NULL. */
treedata->edge = me->medge; /* CustomData_get_layer(&me->edata, CD_MEDGE);? */
@@ -2263,9 +2381,9 @@ static short snapMesh(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- if (bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
/* snap to loose verts */
- BLI_bvhtree_find_nearest_projected(bvhtree[1],
+ BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
lpmat,
snapdata->win_size,
snapdata->mval,
@@ -2279,9 +2397,9 @@ static short snapMesh(SnapObjectContext *sctx,
}
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
- if (bvhtree[0]) {
+ if (sod->bvhtree[0]) {
/* snap to loose edges */
- BLI_bvhtree_find_nearest_projected(bvhtree[0],
+ BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
snapdata->win_size,
snapdata->mval,
@@ -2311,9 +2429,9 @@ static short snapMesh(SnapObjectContext *sctx,
}
else {
BLI_assert(snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX);
- if (bvhtree[0]) {
- /* snap to loose edges */
- BLI_bvhtree_find_nearest_projected(bvhtree[0],
+ if (sod->bvhtree[0]) {
+ /* snap to loose edge verts */
+ BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
snapdata->win_size,
snapdata->mval,
@@ -2325,7 +2443,7 @@ static short snapMesh(SnapObjectContext *sctx,
}
if (treedata->tree) {
- /* snap to looptris */
+ /* snap to looptri verts */
BLI_bvhtree_find_nearest_projected(treedata->tree,
lpmat,
snapdata->win_size,
@@ -2388,17 +2506,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
}
- BVHTreeFromEditMesh *treedata_vert = NULL, *treedata_edge = NULL;
-
- BLI_assert(BKE_object_get_pre_modified_mesh(ob) == BKE_object_get_pre_modified_mesh(ob));
- UNUSED_VARS_NDEBUG(ob);
-
float lpmat[4][4];
mul_m4_m4m4(lpmat, snapdata->pmat, obmat);
- float dist_px_sq = SQUARE(*dist_px);
+ float dist_px_sq = square_f(*dist_px);
- SnapObjectData_EditMesh *sod = snap_object_data_editmesh_get(sctx, ob, em);
+ SnapObjectData *sod = snap_object_data_editmesh_get(sctx, ob, em);
/* Test BoundBox */
@@ -2408,22 +2521,10 @@ static short snapEditMesh(SnapObjectContext *sctx,
return 0;
}
- BVHCache **em_bvh_cache = &((Mesh *)ob->data)->runtime.bvh_cache;
-
if (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX) {
- if (sod->bvh_trees[0] == NULL) {
- sod->bvh_trees[0] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
- }
- treedata_vert = sod->bvh_trees[0];
-
- if (sctx->callbacks.edit_mesh.test_vert_fn == NULL) {
- /* The tree is owned by the Mesh and may have been freed since we last used! */
- if (treedata_vert->tree && !bvhcache_has_tree(*em_bvh_cache, treedata_vert->tree)) {
- free_bvhtree_from_editmesh(treedata_vert);
- }
- }
+ BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[0]};
- if (treedata_vert->tree == NULL) {
+ if (treedata.tree == NULL) {
BLI_bitmap *verts_mask = NULL;
int verts_num_active = -1;
if (sctx->callbacks.edit_mesh.test_vert_fn) {
@@ -2436,29 +2537,21 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_verts_ex(
- treedata_vert, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL);
MEM_freeN(verts_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(treedata_vert, em, 2, BVHTREE_FROM_EM_VERTS, em_bvh_cache);
+ BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p);
}
+ sod->bvhtree[0] = treedata.tree;
+ sod->cached[0] = treedata.cached;
}
}
if (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE) {
- if (sod->bvh_trees[1] == NULL) {
- sod->bvh_trees[1] = BLI_memarena_calloc(sctx->cache.mem_arena, sizeof(**sod->bvh_trees));
- }
- treedata_edge = sod->bvh_trees[1];
-
- if (sctx->callbacks.edit_mesh.test_edge_fn == NULL) {
- /* The tree is owned by the Mesh and may have been freed since we last used! */
- if (treedata_edge->tree && !bvhcache_has_tree(*em_bvh_cache, treedata_edge->tree)) {
- free_bvhtree_from_editmesh(treedata_edge);
- }
- }
+ BVHTreeFromEditMesh treedata = {.tree = sod->bvhtree[1]};
- if (treedata_edge->tree == NULL) {
+ if (treedata.tree == NULL) {
BLI_bitmap *edges_mask = NULL;
int edges_num_active = -1;
if (sctx->callbacks.edit_mesh.test_edge_fn) {
@@ -2471,12 +2564,14 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_edges_ex(
- treedata_edge, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL);
+ &treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL);
MEM_freeN(edges_mask);
}
else {
- BKE_bvhtree_from_editmesh_get(treedata_edge, em, 2, BVHTREE_FROM_EM_EDGES, em_bvh_cache);
+ BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p);
}
+ sod->bvhtree[1] = treedata.tree;
+ sod->cached[1] = treedata.cached;
}
}
@@ -2502,10 +2597,10 @@ static short snapEditMesh(SnapObjectContext *sctx,
mul_v4_m4v4(clip_planes_local[i], tobmat, snapdata->clip_plane[i]);
}
- if (treedata_vert && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
+ if (sod->bvhtree[0] && (snapdata->snap_to_flag & SCE_SNAP_MODE_VERTEX)) {
BM_mesh_elem_table_ensure(em->bm, BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_VERT);
- BLI_bvhtree_find_nearest_projected(treedata_vert->tree,
+ BLI_bvhtree_find_nearest_projected(sod->bvhtree[0],
lpmat,
snapdata->win_size,
snapdata->mval,
@@ -2516,12 +2611,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
&nearest2d);
}
- if (treedata_edge && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
+ if (sod->bvhtree[1] && (snapdata->snap_to_flag & SCE_SNAP_MODE_EDGE)) {
int last_index = nearest.index;
nearest.index = -1;
BM_mesh_elem_table_ensure(em->bm, BM_EDGE | BM_VERT);
BM_mesh_elem_index_ensure(em->bm, BM_EDGE | BM_VERT);
- BLI_bvhtree_find_nearest_projected(treedata_edge->tree,
+ BLI_bvhtree_find_nearest_projected(sod->bvhtree[1],
lpmat,
snapdata->win_size,
snapdata->mval,
@@ -2588,14 +2683,26 @@ static short snapObject(SnapObjectContext *sctx,
case OB_MESH: {
Mesh *me = ob->data;
if (BKE_object_is_in_editmode(ob)) {
- BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_obedit) {
- retval = snapEditMesh(
- sctx, snapdata, ob, em, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
+ /* Operators only update the editmesh looptris of the original mesh. */
+ BMEditMesh *em_orig = BKE_editmesh_from_object(DEG_get_original_object(ob));
+ retval = snapEditMesh(sctx,
+ snapdata,
+ ob,
+ em_orig,
+ obmat,
+ use_backface_culling,
+ dist_px,
+ r_loc,
+ r_no,
+ r_index);
break;
}
- else if (em->mesh_eval_final) {
- me = em->mesh_eval_final;
+ else {
+ BMEditMesh *em = BKE_editmesh_from_object(ob);
+ if (em->mesh_eval_final) {
+ me = em->mesh_eval_final;
+ }
}
}
else if (ob->dt == OB_BOUNDBOX) {
@@ -2615,11 +2722,12 @@ static short snapObject(SnapObjectContext *sctx,
break; /* Use ATTR_FALLTHROUGH if we want to snap to the generated mesh. */
case OB_SURF:
case OB_FONT: {
- if (ob->runtime.mesh_eval) {
+ Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
+ if (mesh_eval) {
retval |= snapMesh(sctx,
snapdata,
ob,
- ob->runtime.mesh_eval,
+ mesh_eval,
obmat,
use_backface_culling,
dist_px,
@@ -2721,6 +2829,7 @@ static void sanp_obj_cb(SnapObjectContext *sctx,
* \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances).
*/
static short snapObjectsRay(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
SnapData *snapdata,
const struct SnapObjectParams *params,
/* read/write args */
@@ -2743,7 +2852,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
.ret = 0,
};
- iter_snap_objects(sctx, params, sanp_obj_cb, &data);
+ iter_snap_objects(sctx, depsgraph, params, sanp_obj_cb, &data);
return data.ret;
}
@@ -2754,10 +2863,7 @@ static short snapObjectsRay(SnapObjectContext *sctx,
/** \name Public Object Snapping API
* \{ */
-SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain,
- Scene *scene,
- Depsgraph *depsgraph,
- int flag)
+SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain, Scene *scene, int flag)
{
SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__);
@@ -2765,7 +2871,6 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain,
sctx->bmain = bmain;
sctx->scene = scene;
- sctx->depsgraph = depsgraph;
sctx->cache.object_map = BLI_ghash_ptr_new(__func__);
/* Initialize as needed (edit-mode only). */
@@ -2777,16 +2882,15 @@ SnapObjectContext *ED_transform_snap_object_context_create(Main *bmain,
SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain,
Scene *scene,
- Depsgraph *depsgraph,
int flag,
/* extra args for view3d */
- const ARegion *ar,
+ const ARegion *region,
const View3D *v3d)
{
- SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, depsgraph, flag);
+ SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag);
sctx->use_v3d = true;
- sctx->v3d_data.ar = ar;
+ sctx->v3d_data.region = region;
sctx->v3d_data.v3d = v3d;
return sctx;
@@ -2794,24 +2898,8 @@ SnapObjectContext *ED_transform_snap_object_context_create_view3d(Main *bmain,
static void snap_object_data_free(void *sod_v)
{
- switch (((SnapObjectData *)sod_v)->type) {
- case SNAP_MESH: {
- SnapObjectData_Mesh *sod = sod_v;
- if (sod->treedata.tree) {
- free_bvhtree_from_mesh(&sod->treedata);
- }
- break;
- }
- case SNAP_EDIT_MESH: {
- SnapObjectData_EditMesh *sod = sod_v;
- for (int i = 0; i < ARRAY_SIZE(sod->bvh_trees); i++) {
- if (sod->bvh_trees[i]) {
- free_bvhtree_from_editmesh(sod->bvh_trees[i]);
- }
- }
- break;
- }
- }
+ SnapObjectData *sod = sod_v;
+ snap_object_data_clear(sod);
}
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
@@ -2840,6 +2928,7 @@ void ED_transform_snap_object_context_set_editmesh_callbacks(
}
bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2850,8 +2939,18 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
Object **r_ob,
float r_obmat[4][4])
{
- return raycastObjects(
- sctx, params, ray_start, ray_normal, ray_depth, r_loc, r_no, r_index, r_ob, r_obmat, NULL);
+ return raycastObjects(sctx,
+ depsgraph,
+ params,
+ ray_start,
+ ray_normal,
+ ray_depth,
+ r_loc,
+ r_no,
+ r_index,
+ r_ob,
+ r_obmat,
+ NULL);
}
/**
@@ -2862,6 +2961,7 @@ bool ED_transform_snap_object_project_ray_ex(SnapObjectContext *sctx,
* \param r_hit_list: List of #SnapObjectHitDepth (caller must free).
*/
bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2877,8 +2977,18 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
float ray_depth_prev = ray_depth;
#endif
- bool retval = raycastObjects(
- sctx, params, ray_start, ray_normal, &ray_depth, NULL, NULL, NULL, NULL, NULL, r_hit_list);
+ bool retval = raycastObjects(sctx,
+ depsgraph,
+ params,
+ ray_start,
+ ray_normal,
+ &ray_depth,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ r_hit_list);
/* meant to be readonly for 'all' hits, ensure it is */
#ifdef DEBUG
@@ -2900,6 +3010,7 @@ bool ED_transform_snap_object_project_ray_all(SnapObjectContext *sctx,
* \return Snap success
*/
static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_start[3],
const float ray_normal[3],
@@ -2911,12 +3022,13 @@ static bool transform_snap_context_project_ray_impl(SnapObjectContext *sctx,
/* try snap edge, then face if it fails */
ret = ED_transform_snap_object_project_ray_ex(
- sctx, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL);
+ sctx, depsgraph, params, ray_start, ray_normal, ray_depth, r_co, r_no, NULL, NULL, NULL);
return ret;
}
bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float ray_origin[3],
const float ray_direction[3],
@@ -2931,12 +3043,13 @@ bool ED_transform_snap_object_project_ray(SnapObjectContext *sctx,
}
return transform_snap_context_project_ray_impl(
- sctx, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
+ sctx, depsgraph, params, ray_origin, ray_direction, ray_depth, r_co, r_no);
}
static short transform_snap_context_project_view3d_mixed_impl(
SnapObjectContext *sctx,
- const unsigned short snap_to_flag,
+ Depsgraph *depsgraph,
+ const ushort snap_to_flag,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -2958,15 +3071,15 @@ static short transform_snap_context_project_view3d_mixed_impl(
float loc[3], no[3], obmat[4][4];
int index = -1;
- const ARegion *ar = sctx->v3d_data.ar;
- const RegionView3D *rv3d = ar->regiondata;
+ const ARegion *region = sctx->v3d_data.region;
+ const RegionView3D *rv3d = region->regiondata;
bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(sctx->v3d_data.v3d);
if (snap_to_flag & SCE_SNAP_MODE_FACE || use_occlusion_test) {
float ray_start[3], ray_normal[3];
- if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph,
- sctx->v3d_data.ar,
+ if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
+ sctx->v3d_data.region,
sctx->v3d_data.v3d,
mval,
NULL,
@@ -2978,8 +3091,18 @@ static short transform_snap_context_project_view3d_mixed_impl(
float dummy_ray_depth = BVH_RAYCAST_DIST_MAX;
- has_hit = raycastObjects(
- sctx, params, ray_start, ray_normal, &dummy_ray_depth, loc, no, &index, &ob, obmat, NULL);
+ has_hit = raycastObjects(sctx,
+ depsgraph,
+ params,
+ ray_start,
+ ray_normal,
+ &dummy_ray_depth,
+ loc,
+ no,
+ &index,
+ &ob,
+ obmat,
+ NULL);
if (has_hit && (snap_to_flag & SCE_SNAP_MODE_FACE)) {
retval = SCE_SNAP_MODE_FACE;
@@ -3007,8 +3130,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
SnapData snapdata;
copy_m4_m4(snapdata.pmat, rv3d->persmat);
- snapdata.win_size[0] = ar->winx;
- snapdata.win_size[1] = ar->winy;
+ snapdata.win_size[0] = region->winx;
+ snapdata.win_size[1] = region->winy;
copy_v2_v2(snapdata.mval, mval);
snapdata.view_proj = rv3d->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO;
@@ -3053,7 +3176,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
snapdata.has_occlusion_plane = true;
}
- elem_test = snapObjectsRay(sctx, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
+ elem_test = snapObjectsRay(
+ sctx, depsgraph, &snapdata, params, &dist_px_tmp, loc, no, &index, &ob, obmat);
if (elem_test) {
elem = elem_test;
}
@@ -3100,7 +3224,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
}
short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
- const unsigned short snap_to,
+ Depsgraph *depsgraph,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3111,8 +3236,18 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
Object **r_ob,
float r_obmat[4][4])
{
- return transform_snap_context_project_view3d_mixed_impl(
- sctx, snap_to, params, mval, prev_co, dist_px, r_loc, r_no, r_index, r_ob, r_obmat);
+ return transform_snap_context_project_view3d_mixed_impl(sctx,
+ depsgraph,
+ snap_to,
+ params,
+ mval,
+ prev_co,
+ dist_px,
+ r_loc,
+ r_no,
+ r_index,
+ r_ob,
+ r_obmat);
}
/**
@@ -3129,7 +3264,8 @@ short ED_transform_snap_object_project_view3d_ex(SnapObjectContext *sctx,
* \return Snap success
*/
bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
- const unsigned short snap_to,
+ Depsgraph *depsgraph,
+ const ushort snap_to,
const struct SnapObjectParams *params,
const float mval[2],
const float prev_co[3],
@@ -3137,14 +3273,25 @@ bool ED_transform_snap_object_project_view3d(SnapObjectContext *sctx,
float r_loc[3],
float r_no[3])
{
- return ED_transform_snap_object_project_view3d_ex(
- sctx, snap_to, params, mval, prev_co, dist_px, r_loc, r_no, NULL, NULL, NULL) != 0;
+ return ED_transform_snap_object_project_view3d_ex(sctx,
+ depsgraph,
+ snap_to,
+ params,
+ mval,
+ prev_co,
+ dist_px,
+ r_loc,
+ r_no,
+ NULL,
+ NULL,
+ NULL) != 0;
}
/**
* see: #ED_transform_snap_object_project_ray_all
*/
bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
+ Depsgraph *depsgraph,
const struct SnapObjectParams *params,
const float mval[2],
float ray_depth,
@@ -3153,8 +3300,8 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
{
float ray_start[3], ray_normal[3];
- if (!ED_view3d_win_to_ray_clipped_ex(sctx->depsgraph,
- sctx->v3d_data.ar,
+ if (!ED_view3d_win_to_ray_clipped_ex(depsgraph,
+ sctx->v3d_data.region,
sctx->v3d_data.v3d,
mval,
NULL,
@@ -3165,7 +3312,7 @@ bool ED_transform_snap_object_project_all_view3d_ex(SnapObjectContext *sctx,
}
return ED_transform_snap_object_project_ray_all(
- sctx, params, ray_start, ray_normal, ray_depth, sort, r_hit_list);
+ sctx, depsgraph, params, ray_start, ray_normal, ray_depth, sort, r_hit_list);
}
/** \} */