~ubuntu-branches/ubuntu/trusty/blender/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/0010-fix_format-security_issue.patch/source/blender/editors/transform/transform.c

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2013-08-14 10:43:49 UTC
  • mfrom: (14.2.19 sid)
  • Revision ID: package-import@ubuntu.com-20130814104349-t1d5mtwkphp12dyj
Tags: 2.68a-3
* Upload to unstable
* debian/: python3.3 Depends simplified
  - debian/control: python3.3 Depends dropped
    for blender-data package
  - 0001-blender_thumbnailer.patch refreshed
* debian/control: libavcodec b-dep versioning dropped

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * ***** BEGIN GPL LICENSE BLOCK *****
3
 
 *
4
 
 * This program is free software; you can redistribute it and/or
5
 
 * modify it under the terms of the GNU General Public License
6
 
 * as published by the Free Software Foundation; either version 2
7
 
 * of the License, or (at your option) any later version.
8
 
 *
9
 
 * This program is distributed in the hope that it will be useful,
10
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 * GNU General Public License for more details.
13
 
 *
14
 
 * You should have received a copy of the GNU General Public License
15
 
 * along with this program; if not, write to the Free Software Foundation,
16
 
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
 
 *
18
 
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19
 
 * All rights reserved.
20
 
 *
21
 
 * The Original Code is: all of this file.
22
 
 *
23
 
 * Contributor(s): none yet.
24
 
 *
25
 
 * ***** END GPL LICENSE BLOCK *****
26
 
 */
27
 
 
28
 
/** \file blender/editors/transform/transform.c
29
 
 *  \ingroup edtransform
30
 
 */
31
 
 
32
 
#include <stdlib.h>
33
 
#include <stdio.h>
34
 
#include <string.h>
35
 
#include <math.h>
36
 
#include <float.h>
37
 
 
38
 
#ifndef WIN32
39
 
#  include <unistd.h>
40
 
#else
41
 
#  include <io.h>
42
 
#endif
43
 
 
44
 
#include "MEM_guardedalloc.h"
45
 
 
46
 
#include "DNA_anim_types.h"
47
 
#include "DNA_armature_types.h"
48
 
#include "DNA_constraint_types.h"
49
 
#include "DNA_mesh_types.h"
50
 
#include "DNA_meshdata_types.h"
51
 
#include "DNA_mask_types.h"
52
 
#include "DNA_movieclip_types.h"
53
 
#include "DNA_scene_types.h"  /* PET modes */
54
 
 
55
 
#include "BLI_utildefines.h"
56
 
#include "BLI_math.h"
57
 
#include "BLI_rect.h"
58
 
#include "BLI_listbase.h"
59
 
#include "BLI_string.h"
60
 
#include "BLI_ghash.h"
61
 
#include "BLI_linklist.h"
62
 
#include "BLI_smallhash.h"
63
 
 
64
 
#include "BKE_nla.h"
65
 
#include "BKE_bmesh.h"
66
 
#include "BKE_context.h"
67
 
#include "BKE_constraint.h"
68
 
#include "BKE_global.h"
69
 
#include "BKE_particle.h"
70
 
#include "BKE_pointcache.h"
71
 
#include "BKE_unit.h"
72
 
#include "BKE_mask.h"
73
 
 
74
 
#include "BIF_gl.h"
75
 
#include "BIF_glutil.h"
76
 
 
77
 
#include "ED_image.h"
78
 
#include "ED_keyframing.h"
79
 
#include "ED_screen.h"
80
 
#include "ED_space_api.h"
81
 
#include "ED_markers.h"
82
 
#include "ED_view3d.h"
83
 
#include "ED_mesh.h"
84
 
#include "ED_clip.h"
85
 
#include "ED_mask.h"
86
 
 
87
 
#include "WM_types.h"
88
 
#include "WM_api.h"
89
 
 
90
 
#include "UI_view2d.h"
91
 
#include "UI_interface_icons.h"
92
 
#include "UI_resources.h"
93
 
 
94
 
#include "RNA_access.h"
95
 
 
96
 
#include "BLF_api.h"
97
 
#include "BLF_translation.h"
98
 
 
99
 
#include "transform.h"
100
 
 
101
 
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
102
 
static int doEdgeSlide(TransInfo *t, float perc);
103
 
static int doVertSlide(TransInfo *t, float perc);
104
 
 
105
 
static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
106
 
static void drawVertSlide(const struct bContext *C, TransInfo *t);
107
 
 
108
 
static bool transdata_check_local_center(TransInfo *t)
109
 
{
110
 
        return ((t->around == V3D_LOCAL) && (
111
 
                    (t->flag & (T_OBJECT | T_POSE)) ||
112
 
                    (t->obedit && t->obedit->type == OB_MESH && (t->settings->selectmode & (SCE_SELECT_EDGE | SCE_SELECT_FACE))) ||
113
 
                    (t->obedit && t->obedit->type == OB_ARMATURE) ||
114
 
                    (t->spacetype == SPACE_IPO))
115
 
                );
116
 
}
117
 
 
118
 
/* ************************** SPACE DEPENDANT CODE **************************** */
119
 
 
120
 
void setTransformViewMatrices(TransInfo *t)
121
 
{
122
 
        if (t->spacetype == SPACE_VIEW3D && t->ar && t->ar->regiontype == RGN_TYPE_WINDOW) {
123
 
                RegionView3D *rv3d = t->ar->regiondata;
124
 
 
125
 
                copy_m4_m4(t->viewmat, rv3d->viewmat);
126
 
                copy_m4_m4(t->viewinv, rv3d->viewinv);
127
 
                copy_m4_m4(t->persmat, rv3d->persmat);
128
 
                copy_m4_m4(t->persinv, rv3d->persinv);
129
 
                t->persp = rv3d->persp;
130
 
        }
131
 
        else {
132
 
                unit_m4(t->viewmat);
133
 
                unit_m4(t->viewinv);
134
 
                unit_m4(t->persmat);
135
 
                unit_m4(t->persinv);
136
 
                t->persp = RV3D_ORTHO;
137
 
        }
138
 
 
139
 
        calculateCenter2D(t);
140
 
}
141
 
 
142
 
static void convertViewVec2D(View2D *v2d, float r_vec[3], int dx, int dy)
143
 
{
144
 
        float divx, divy;
145
 
        
146
 
        divx = BLI_rcti_size_x(&v2d->mask);
147
 
        divy = BLI_rcti_size_y(&v2d->mask);
148
 
 
149
 
        r_vec[0] = BLI_rctf_size_x(&v2d->cur) * dx / divx;
150
 
        r_vec[1] = BLI_rctf_size_y(&v2d->cur) * dy / divy;
151
 
        r_vec[2] = 0.0f;
152
 
}
153
 
 
154
 
static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
155
 
{
156
 
        float divx, divy;
157
 
        float mulx, muly;
158
 
 
159
 
        divx = BLI_rcti_size_x(&v2d->mask);
160
 
        divy = BLI_rcti_size_y(&v2d->mask);
161
 
 
162
 
        mulx = BLI_rctf_size_x(&v2d->cur);
163
 
        muly = BLI_rctf_size_y(&v2d->cur);
164
 
 
165
 
        /* difference with convertViewVec2D */
166
 
        /* clamp w/h, mask only */
167
 
        if (mulx / divx < muly / divy) {
168
 
                divy = divx;
169
 
                muly = mulx;
170
 
        }
171
 
        else {
172
 
                divx = divy;
173
 
                mulx = muly;
174
 
        }
175
 
        /* end difference */
176
 
 
177
 
        r_vec[0] = mulx * dx / divx;
178
 
        r_vec[1] = muly * dy / divy;
179
 
        r_vec[2] = 0.0f;
180
 
}
181
 
 
182
 
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
183
 
{
184
 
        if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
185
 
                const float mval_f[2] = {(float)dx, (float)dy};
186
 
                ED_view3d_win_to_delta(t->ar, mval_f, r_vec);
187
 
        }
188
 
        else if (t->spacetype == SPACE_IMAGE) {
189
 
                float aspx, aspy;
190
 
 
191
 
                if (t->options & CTX_MASK) {
192
 
 
193
 
                        convertViewVec2D_mask(t->view, r_vec, dx, dy);
194
 
                        ED_space_image_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
195
 
                }
196
 
                else {
197
 
                        convertViewVec2D(t->view, r_vec, dx, dy);
198
 
                        ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
199
 
                }
200
 
 
201
 
                r_vec[0] *= aspx;
202
 
                r_vec[1] *= aspy;
203
 
        }
204
 
        else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
205
 
                convertViewVec2D(t->view, r_vec, dx, dy);
206
 
        }
207
 
        else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) {
208
 
                convertViewVec2D(&t->ar->v2d, r_vec, dx, dy);
209
 
        }
210
 
        else if (t->spacetype == SPACE_CLIP) {
211
 
                float aspx, aspy;
212
 
 
213
 
                if (t->options & CTX_MASK) {
214
 
                        convertViewVec2D_mask(t->view, r_vec, dx, dy);
215
 
                }
216
 
                else {
217
 
                        convertViewVec2D(t->view, r_vec, dx, dy);
218
 
                }
219
 
 
220
 
                if (t->options & CTX_MOVIECLIP) {
221
 
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
222
 
                }
223
 
                else if (t->options & CTX_MASK) {
224
 
                        /* TODO - NOT WORKING, this isnt so bad since its only display aspect */
225
 
                        ED_space_clip_get_aspect(t->sa->spacedata.first, &aspx, &aspy);
226
 
                }
227
 
                else {
228
 
                        /* should never happen, quiet warnings */
229
 
                        BLI_assert(0);
230
 
                        aspx = aspy = 1.0f;
231
 
                }
232
 
 
233
 
                r_vec[0] *= aspx;
234
 
                r_vec[1] *= aspy;
235
 
        }
236
 
        else {
237
 
                printf("%s: called in an invalid context\n", __func__);
238
 
                zero_v3(r_vec);
239
 
        }
240
 
}
241
 
 
242
 
void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag)
243
 
{
244
 
        if (t->spacetype == SPACE_VIEW3D) {
245
 
                if (t->ar->regiontype == RGN_TYPE_WINDOW) {
246
 
                        if (ED_view3d_project_int_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
247
 
                                adr[0] = (int)2140000000.0f;  /* this is what was done in 2.64, perhaps we can be smarter? */
248
 
                                adr[1] = (int)2140000000.0f;
249
 
                        }
250
 
                }
251
 
        }
252
 
        else if (t->spacetype == SPACE_IMAGE) {
253
 
                SpaceImage *sima = t->sa->spacedata.first;
254
 
 
255
 
                if (t->options & CTX_MASK) {
256
 
                        /* not working quite right, TODO (see below too) */
257
 
                        float aspx, aspy;
258
 
                        float v[2];
259
 
 
260
 
                        ED_space_image_get_aspect(sima, &aspx, &aspy);
261
 
 
262
 
                        copy_v2_v2(v, vec);
263
 
 
264
 
                        v[0] = v[0] / aspx;
265
 
                        v[1] = v[1] / aspy;
266
 
 
267
 
                        BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
268
 
 
269
 
                        v[0] = v[0] / aspx;
270
 
                        v[1] = v[1] / aspy;
271
 
 
272
 
                        ED_image_point_pos__reverse(sima, t->ar, v, v);
273
 
 
274
 
                        adr[0] = v[0];
275
 
                        adr[1] = v[1];
276
 
                }
277
 
                else {
278
 
                        float aspx, aspy, v[2];
279
 
 
280
 
                        ED_space_image_get_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
281
 
                        v[0] = vec[0] / aspx;
282
 
                        v[1] = vec[1] / aspy;
283
 
 
284
 
                        UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
285
 
                }
286
 
        }
287
 
        else if (t->spacetype == SPACE_ACTION) {
288
 
                int out[2] = {0, 0};
289
 
#if 0
290
 
                SpaceAction *sact = t->sa->spacedata.first;
291
 
 
292
 
                if (sact->flag & SACTION_DRAWTIME) {
293
 
                        //vec[0] = vec[0]/((t->scene->r.frs_sec / t->scene->r.frs_sec_base));
294
 
                        /* same as below */
295
 
                        UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
296
 
                }
297
 
                else
298
 
#endif
299
 
                {
300
 
                        UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
301
 
                }
302
 
 
303
 
                adr[0] = out[0];
304
 
                adr[1] = out[1];
305
 
        }
306
 
        else if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
307
 
                int out[2] = {0, 0};
308
 
 
309
 
                UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
310
 
                adr[0] = out[0];
311
 
                adr[1] = out[1];
312
 
        }
313
 
        else if (t->spacetype == SPACE_SEQ) { /* XXX not tested yet, but should work */
314
 
                int out[2] = {0, 0};
315
 
 
316
 
                UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], out, out + 1);
317
 
                adr[0] = out[0];
318
 
                adr[1] = out[1];
319
 
        }
320
 
        else if (t->spacetype == SPACE_CLIP) {
321
 
                SpaceClip *sc = t->sa->spacedata.first;
322
 
 
323
 
                if (t->options & CTX_MASK) {
324
 
                        /* not working quite right, TODO (see above too) */
325
 
                        float aspx, aspy;
326
 
                        float v[2];
327
 
 
328
 
                        ED_space_clip_get_aspect(sc, &aspx, &aspy);
329
 
 
330
 
                        copy_v2_v2(v, vec);
331
 
 
332
 
                        v[0] = v[0] / aspx;
333
 
                        v[1] = v[1] / aspy;
334
 
 
335
 
                        BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
336
 
 
337
 
                        v[0] = v[0] / aspx;
338
 
                        v[1] = v[1] / aspy;
339
 
 
340
 
                        ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
341
 
 
342
 
                        adr[0] = v[0];
343
 
                        adr[1] = v[1];
344
 
                }
345
 
                else if (t->options & CTX_MOVIECLIP) {
346
 
                        float v[2], aspx, aspy;
347
 
 
348
 
                        copy_v2_v2(v, vec);
349
 
                        ED_space_clip_get_aspect_dimension_aware(t->sa->spacedata.first, &aspx, &aspy);
350
 
 
351
 
                        v[0] /= aspx;
352
 
                        v[1] /= aspy;
353
 
 
354
 
                        UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr + 1);
355
 
                }
356
 
                else {
357
 
                        BLI_assert(0);
358
 
                }
359
 
        }
360
 
        else if (t->spacetype == SPACE_NODE) {
361
 
                UI_view2d_to_region_no_clip((View2D *)t->view, vec[0], vec[1], adr, adr + 1);
362
 
        }
363
 
}
364
 
void projectIntView(TransInfo *t, const float vec[3], int adr[2])
365
 
{
366
 
        projectIntViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
367
 
}
368
 
 
369
 
void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag)
370
 
{
371
 
        switch (t->spacetype) {
372
 
                case SPACE_VIEW3D:
373
 
                {
374
 
                        if (t->ar->regiontype == RGN_TYPE_WINDOW) {
375
 
                                /* allow points behind the view [#33643] */
376
 
                                if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
377
 
                                        /* XXX, 2.64 and prior did this, weak! */
378
 
                                        adr[0] = t->ar->winx / 2.0f;
379
 
                                        adr[1] = t->ar->winy / 2.0f;
380
 
                                }
381
 
                                return;
382
 
                        }
383
 
                        break;
384
 
                }
385
 
                case SPACE_IMAGE:
386
 
                case SPACE_CLIP:
387
 
                case SPACE_IPO:
388
 
                case SPACE_NLA:
389
 
                {
390
 
                        int a[2];
391
 
                        projectIntView(t, vec, a);
392
 
                        adr[0] = a[0];
393
 
                        adr[1] = a[1];
394
 
                        return;
395
 
                }
396
 
        }
397
 
 
398
 
        zero_v2(adr);
399
 
}
400
 
void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
401
 
{
402
 
        projectFloatViewEx(t, vec, adr, V3D_PROJ_TEST_NOP);
403
 
}
404
 
 
405
 
void applyAspectRatio(TransInfo *t, float vec[2])
406
 
{
407
 
        if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
408
 
                SpaceImage *sima = t->sa->spacedata.first;
409
 
                float aspx, aspy;
410
 
 
411
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
412
 
                        int width, height;
413
 
                        ED_space_image_get_size(sima, &width, &height);
414
 
 
415
 
                        vec[0] *= width;
416
 
                        vec[1] *= height;
417
 
                }
418
 
 
419
 
                ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
420
 
                vec[0] /= aspx;
421
 
                vec[1] /= aspy;
422
 
        }
423
 
        else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
424
 
                if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
425
 
                        SpaceClip *sc = t->sa->spacedata.first;
426
 
                        float aspx, aspy;
427
 
 
428
 
 
429
 
                        if (t->options & CTX_MOVIECLIP) {
430
 
                                ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
431
 
 
432
 
                                vec[0] /= aspx;
433
 
                                vec[1] /= aspy;
434
 
                        }
435
 
                        else if (t->options & CTX_MASK) {
436
 
                                ED_space_clip_get_aspect(sc, &aspx, &aspy);
437
 
 
438
 
                                vec[0] /= aspx;
439
 
                                vec[1] /= aspy;
440
 
                        }
441
 
                }
442
 
        }
443
 
}
444
 
 
445
 
void removeAspectRatio(TransInfo *t, float vec[2])
446
 
{
447
 
        if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
448
 
                SpaceImage *sima = t->sa->spacedata.first;
449
 
                float aspx, aspy;
450
 
 
451
 
                if ((sima->flag & SI_COORDFLOATS) == 0) {
452
 
                        int width, height;
453
 
                        ED_space_image_get_size(sima, &width, &height);
454
 
 
455
 
                        vec[0] /= width;
456
 
                        vec[1] /= height;
457
 
                }
458
 
 
459
 
                ED_space_image_get_uv_aspect(sima, &aspx, &aspy);
460
 
                vec[0] *= aspx;
461
 
                vec[1] *= aspy;
462
 
        }
463
 
        else if ((t->spacetype == SPACE_CLIP) && (t->mode == TFM_TRANSLATION)) {
464
 
                if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
465
 
                        SpaceClip *sc = t->sa->spacedata.first;
466
 
                        float aspx = 1.0f, aspy = 1.0f;
467
 
 
468
 
                        if (t->options & CTX_MOVIECLIP) {
469
 
                                ED_space_clip_get_aspect_dimension_aware(sc, &aspx, &aspy);
470
 
                        }
471
 
                        else if (t->options & CTX_MASK) {
472
 
                                ED_space_clip_get_aspect(sc, &aspx, &aspy);
473
 
                        }
474
 
 
475
 
                        vec[0] *= aspx;
476
 
                        vec[1] *= aspy;
477
 
                }
478
 
        }
479
 
}
480
 
 
481
 
static void viewRedrawForce(const bContext *C, TransInfo *t)
482
 
{
483
 
        if (t->spacetype == SPACE_VIEW3D) {
484
 
                /* Do we need more refined tags? */
485
 
                if (t->flag & T_POSE)
486
 
                        WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
487
 
                else
488
 
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
489
 
 
490
 
                if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
491
 
                        WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
492
 
 
493
 
                /* for realtime animation record - send notifiers recognised by animation editors */
494
 
                // XXX: is this notifier a lame duck?
495
 
                if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
496
 
                        WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
497
 
                
498
 
        }
499
 
        else if (t->spacetype == SPACE_ACTION) {
500
 
                //SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
501
 
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
502
 
        }
503
 
        else if (t->spacetype == SPACE_IPO) {
504
 
                //SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
505
 
                WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
506
 
        }
507
 
        else if (t->spacetype == SPACE_NLA) {
508
 
                WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
509
 
        }
510
 
        else if (t->spacetype == SPACE_NODE) {
511
 
                //ED_area_tag_redraw(t->sa);
512
 
                WM_event_add_notifier(C, NC_SPACE | ND_SPACE_NODE_VIEW, NULL);
513
 
        }
514
 
        else if (t->spacetype == SPACE_SEQ) {
515
 
                WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, NULL);
516
 
        }
517
 
        else if (t->spacetype == SPACE_IMAGE) {
518
 
                if (t->options & CTX_MASK) {
519
 
                        Mask *mask = CTX_data_edit_mask(C);
520
 
 
521
 
                        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
522
 
                }
523
 
                else {
524
 
                        // XXX how to deal with lock?
525
 
                        SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
526
 
                        if (sima->lock) WM_event_add_notifier(C, NC_GEOM | ND_DATA, t->obedit->data);
527
 
                        else ED_area_tag_redraw(t->sa);
528
 
                }
529
 
        }
530
 
        else if (t->spacetype == SPACE_CLIP) {
531
 
                SpaceClip *sc = (SpaceClip *)t->sa->spacedata.first;
532
 
 
533
 
                if (ED_space_clip_check_show_trackedit(sc)) {
534
 
                        MovieClip *clip = ED_space_clip_get_clip(sc);
535
 
 
536
 
                        /* objects could be parented to tracking data, so send this for viewport refresh */
537
 
                        WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
538
 
 
539
 
                        WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
540
 
                }
541
 
                else if (ED_space_clip_check_show_maskedit(sc)) {
542
 
                        Mask *mask = CTX_data_edit_mask(C);
543
 
 
544
 
                        WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
545
 
                }
546
 
        }
547
 
}
548
 
 
549
 
static void viewRedrawPost(bContext *C, TransInfo *t)
550
 
{
551
 
        ED_area_headerprint(t->sa, NULL);
552
 
        
553
 
        if (t->spacetype == SPACE_VIEW3D) {
554
 
                /* if autokeying is enabled, send notifiers that keyframes were added */
555
 
                if (IS_AUTOKEY_ON(t->scene))
556
 
                        WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
557
 
 
558
 
                /* redraw UV editor */
559
 
                if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
560
 
                        WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
561
 
                
562
 
                /* XXX temp, first hack to get auto-render in compositor work (ton) */
563
 
                WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
564
 
 
565
 
        }
566
 
        
567
 
#if 0 // TRANSFORM_FIX_ME
568
 
        if (t->spacetype == SPACE_VIEW3D) {
569
 
                allqueue(REDRAWBUTSOBJECT, 0);
570
 
                allqueue(REDRAWVIEW3D, 0);
571
 
        }
572
 
        else if (t->spacetype == SPACE_IMAGE) {
573
 
                allqueue(REDRAWIMAGE, 0);
574
 
                allqueue(REDRAWVIEW3D, 0);
575
 
        }
576
 
        else if (ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
577
 
                allqueue(REDRAWVIEW3D, 0);
578
 
                allqueue(REDRAWACTION, 0);
579
 
                allqueue(REDRAWNLA, 0);
580
 
                allqueue(REDRAWIPO, 0);
581
 
                allqueue(REDRAWTIME, 0);
582
 
                allqueue(REDRAWBUTSOBJECT, 0);
583
 
        }
584
 
 
585
 
        scrarea_queue_headredraw(curarea);
586
 
#endif
587
 
}
588
 
 
589
 
/* ************************** TRANSFORMATIONS **************************** */
590
 
 
591
 
void BIF_selectOrientation(void)
592
 
{
593
 
#if 0 // TRANSFORM_FIX_ME
594
 
        short val;
595
 
        char *str_menu = BIF_menustringTransformOrientation("Orientation");
596
 
        val = pupmenu(str_menu);
597
 
        MEM_freeN(str_menu);
598
 
 
599
 
        if (val >= 0) {
600
 
                G.vd->twmode = val;
601
 
        }
602
 
#endif
603
 
}
604
 
 
605
 
static void view_editmove(unsigned short UNUSED(event))
606
 
{
607
 
#if 0 // TRANSFORM_FIX_ME
608
 
        int refresh = 0;
609
 
        /* Regular:   Zoom in */
610
 
        /* Shift:     Scroll up */
611
 
        /* Ctrl:      Scroll right */
612
 
        /* Alt-Shift: Rotate up */
613
 
        /* Alt-Ctrl:  Rotate right */
614
 
 
615
 
        /* only work in 3D window for now
616
 
         * In the end, will have to send to event to a 2D window handler instead
617
 
         */
618
 
        if (Trans.flag & T_2D_EDIT)
619
 
                return;
620
 
 
621
 
        switch (event) {
622
 
                case WHEELUPMOUSE:
623
 
 
624
 
                        if (G.qual & LR_SHIFTKEY) {
625
 
                                if (G.qual & LR_ALTKEY) {
626
 
                                        G.qual &= ~LR_SHIFTKEY;
627
 
                                        persptoetsen(PAD2);
628
 
                                        G.qual |= LR_SHIFTKEY;
629
 
                                }
630
 
                                else {
631
 
                                        persptoetsen(PAD2);
632
 
                                }
633
 
                        }
634
 
                        else if (G.qual & LR_CTRLKEY) {
635
 
                                if (G.qual & LR_ALTKEY) {
636
 
                                        G.qual &= ~LR_CTRLKEY;
637
 
                                        persptoetsen(PAD4);
638
 
                                        G.qual |= LR_CTRLKEY;
639
 
                                }
640
 
                                else {
641
 
                                        persptoetsen(PAD4);
642
 
                                }
643
 
                        }
644
 
                        else if (U.uiflag & USER_WHEELZOOMDIR)
645
 
                                persptoetsen(PADMINUS);
646
 
                        else
647
 
                                persptoetsen(PADPLUSKEY);
648
 
 
649
 
                        refresh = 1;
650
 
                        break;
651
 
                case WHEELDOWNMOUSE:
652
 
                        if (G.qual & LR_SHIFTKEY) {
653
 
                                if (G.qual & LR_ALTKEY) {
654
 
                                        G.qual &= ~LR_SHIFTKEY;
655
 
                                        persptoetsen(PAD8);
656
 
                                        G.qual |= LR_SHIFTKEY;
657
 
                                }
658
 
                                else {
659
 
                                        persptoetsen(PAD8);
660
 
                                }
661
 
                        }
662
 
                        else if (G.qual & LR_CTRLKEY) {
663
 
                                if (G.qual & LR_ALTKEY) {
664
 
                                        G.qual &= ~LR_CTRLKEY;
665
 
                                        persptoetsen(PAD6);
666
 
                                        G.qual |= LR_CTRLKEY;
667
 
                                }
668
 
                                else {
669
 
                                        persptoetsen(PAD6);
670
 
                                }
671
 
                        }
672
 
                        else if (U.uiflag & USER_WHEELZOOMDIR)
673
 
                                persptoetsen(PADPLUSKEY);
674
 
                        else
675
 
                                persptoetsen(PADMINUS);
676
 
 
677
 
                        refresh = 1;
678
 
                        break;
679
 
        }
680
 
 
681
 
        if (refresh)
682
 
                setTransformViewMatrices(&Trans);
683
 
#endif
684
 
}
685
 
 
686
 
/* ************************************************* */
687
 
 
688
 
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
689
 
#define TFM_MODAL_CANCEL        1
690
 
#define TFM_MODAL_CONFIRM       2
691
 
#define TFM_MODAL_TRANSLATE     3
692
 
#define TFM_MODAL_ROTATE        4
693
 
#define TFM_MODAL_RESIZE        5
694
 
#define TFM_MODAL_SNAP_INV_ON   6
695
 
#define TFM_MODAL_SNAP_INV_OFF  7
696
 
#define TFM_MODAL_SNAP_TOGGLE   8
697
 
#define TFM_MODAL_AXIS_X        9
698
 
#define TFM_MODAL_AXIS_Y        10
699
 
#define TFM_MODAL_AXIS_Z        11
700
 
#define TFM_MODAL_PLANE_X       12
701
 
#define TFM_MODAL_PLANE_Y       13
702
 
#define TFM_MODAL_PLANE_Z       14
703
 
#define TFM_MODAL_CONS_OFF      15
704
 
#define TFM_MODAL_ADD_SNAP      16
705
 
#define TFM_MODAL_REMOVE_SNAP   17
706
 
/*      18 and 19 used by numinput, defined in transform.h
707
 
 * */
708
 
#define TFM_MODAL_PROPSIZE_UP   20
709
 
#define TFM_MODAL_PROPSIZE_DOWN 21
710
 
#define TFM_MODAL_AUTOIK_LEN_INC 22
711
 
#define TFM_MODAL_AUTOIK_LEN_DEC 23
712
 
 
713
 
#define TFM_MODAL_EDGESLIDE_UP 24
714
 
#define TFM_MODAL_EDGESLIDE_DOWN 25
715
 
 
716
 
/* for analog input, like trackpad */
717
 
#define TFM_MODAL_PROPSIZE              26
718
 
 
719
 
/* called in transform_ops.c, on each regeneration of keymaps */
720
 
wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf)
721
 
{
722
 
        static EnumPropertyItem modal_items[] = {
723
 
                {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
724
 
                {TFM_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
725
 
                {TFM_MODAL_TRANSLATE, "TRANSLATE", 0, "Translate", ""},
726
 
                {TFM_MODAL_ROTATE, "ROTATE", 0, "Rotate", ""},
727
 
                {TFM_MODAL_RESIZE, "RESIZE", 0, "Resize", ""},
728
 
                {TFM_MODAL_SNAP_INV_ON, "SNAP_INV_ON", 0, "Invert Snap On", ""},
729
 
                {TFM_MODAL_SNAP_INV_OFF, "SNAP_INV_OFF", 0, "Invert Snap Off", ""},
730
 
                {TFM_MODAL_SNAP_TOGGLE, "SNAP_TOGGLE", 0, "Snap Toggle", ""},
731
 
                {TFM_MODAL_AXIS_X, "AXIS_X", 0, "Orientation X axis", ""},
732
 
                {TFM_MODAL_AXIS_Y, "AXIS_Y", 0, "Orientation Y axis", ""},
733
 
                {TFM_MODAL_AXIS_Z, "AXIS_Z", 0, "Orientation Z axis", ""},
734
 
                {TFM_MODAL_PLANE_X, "PLANE_X", 0, "Orientation X plane", ""},
735
 
                {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Orientation Y plane", ""},
736
 
                {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Orientation Z plane", ""},
737
 
                {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Remove Constraints", ""},
738
 
                {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""},
739
 
                {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""},
740
 
                {NUM_MODAL_INCREMENT_UP, "INCREMENT_UP", 0, "Numinput Increment Up", ""},
741
 
                {NUM_MODAL_INCREMENT_DOWN, "INCREMENT_DOWN", 0, "Numinput Increment Down", ""},
742
 
                {TFM_MODAL_PROPSIZE_UP, "PROPORTIONAL_SIZE_UP", 0, "Increase Proportional Influence", ""},
743
 
                {TFM_MODAL_PROPSIZE_DOWN, "PROPORTIONAL_SIZE_DOWN", 0, "Decrease Proportional Influence", ""},
744
 
                {TFM_MODAL_AUTOIK_LEN_INC, "AUTOIK_CHAIN_LEN_UP", 0, "Increase Max AutoIK Chain Length", ""},
745
 
                {TFM_MODAL_AUTOIK_LEN_DEC, "AUTOIK_CHAIN_LEN_DOWN", 0, "Decrease Max AutoIK Chain Length", ""},
746
 
                {TFM_MODAL_EDGESLIDE_UP, "EDGESLIDE_EDGE_NEXT", 0, "Select next Edge Slide Edge", ""},
747
 
                {TFM_MODAL_EDGESLIDE_DOWN, "EDGESLIDE_PREV_NEXT", 0, "Select previous Edge Slide Edge", ""},
748
 
                {TFM_MODAL_PROPSIZE, "PROPORTIONAL_SIZE", 0, "Adjust Proportional Influence", ""},
749
 
                {0, NULL, 0, NULL, NULL}
750
 
        };
751
 
        
752
 
        wmKeyMap *keymap = WM_modalkeymap_get(keyconf, "Transform Modal Map");
753
 
        
754
 
        /* this function is called for each spacetype, only needs to add map once */
755
 
        if (keymap && keymap->modal_items) return NULL;
756
 
        
757
 
        keymap = WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items);
758
 
        
759
 
        /* items for modal map */
760
 
        WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL);
761
 
        WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
762
 
        WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
763
 
        WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM);
764
 
 
765
 
        WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE);
766
 
        WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE);
767
 
        WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE);
768
 
        
769
 
        WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE);
770
 
 
771
 
        WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
772
 
        WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
773
 
 
774
 
        WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON);
775
 
        WM_modalkeymap_add_item(keymap, RIGHTCTRLKEY, KM_RELEASE, KM_ANY, 0, TFM_MODAL_SNAP_INV_OFF);
776
 
        
777
 
        WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, TFM_MODAL_ADD_SNAP);
778
 
        WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ALT, 0, TFM_MODAL_REMOVE_SNAP);
779
 
 
780
 
        WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
781
 
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
782
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_UP);
783
 
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, TFM_MODAL_PROPSIZE_DOWN);
784
 
        WM_modalkeymap_add_item(keymap, MOUSEPAN, 0, 0, 0, TFM_MODAL_PROPSIZE);
785
 
 
786
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_UP);
787
 
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_ALT, 0, TFM_MODAL_EDGESLIDE_DOWN);
788
 
        
789
 
        WM_modalkeymap_add_item(keymap, PAGEUPKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
790
 
        WM_modalkeymap_add_item(keymap, PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
791
 
        WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_INC);
792
 
        WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_AUTOIK_LEN_DEC);
793
 
        
794
 
        return keymap;
795
 
}
796
 
 
797
 
static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode)
798
 
{
799
 
        if (!(t->flag & T_NO_CONSTRAINT)) {
800
 
                int constraint_axis, constraint_plane;
801
 
                int edit_2d = (t->flag & T_2D_EDIT);
802
 
                const char *msg1 = "", *msg2 = "", *msg3 = "";
803
 
                char axis;
804
 
        
805
 
                /* Initialize */
806
 
                switch (key_type) {
807
 
                        case XKEY:
808
 
                                msg1 = IFACE_("along X");
809
 
                                msg2 = IFACE_("along %s X");
810
 
                                msg3 = IFACE_("locking %s X");
811
 
                                axis = 'X';
812
 
                                constraint_axis = CON_AXIS0;
813
 
                                break;
814
 
                        case YKEY:
815
 
                                msg1 = IFACE_("along Y");
816
 
                                msg2 = IFACE_("along %s Y");
817
 
                                msg3 = IFACE_("locking %s Y");
818
 
                                axis = 'Y';
819
 
                                constraint_axis = CON_AXIS1;
820
 
                                break;
821
 
                        case ZKEY:
822
 
                                msg1 = IFACE_("along Z");
823
 
                                msg2 = IFACE_("along %s Z");
824
 
                                msg3 = IFACE_("locking %s Z");
825
 
                                axis = 'Z';
826
 
                                constraint_axis = CON_AXIS2;
827
 
                                break;
828
 
                        default:
829
 
                                /* Invalid key */
830
 
                                return;
831
 
                }
832
 
                constraint_plane = ((CON_AXIS0 | CON_AXIS1 | CON_AXIS2) & (~constraint_axis));
833
 
 
834
 
                if (edit_2d && (key_type != ZKEY)) {
835
 
                        if (cmode == axis) {
836
 
                                stopConstraint(t);
837
 
                        }
838
 
                        else {
839
 
                                setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_axis, msg1);
840
 
                        }
841
 
                }
842
 
                else if (!edit_2d) {
843
 
                        if (cmode == axis) {
844
 
                                if (t->con.orientation != V3D_MANIP_GLOBAL) {
845
 
                                        stopConstraint(t);
846
 
                                }
847
 
                                else {
848
 
                                        short orientation = (t->current_orientation != V3D_MANIP_GLOBAL ?
849
 
                                                             t->current_orientation : V3D_MANIP_LOCAL);
850
 
                                        if (!(t->modifiers & MOD_CONSTRAINT_PLANE))
851
 
                                                setUserConstraint(t, orientation, constraint_axis, msg2);
852
 
                                        else if (t->modifiers & MOD_CONSTRAINT_PLANE)
853
 
                                                setUserConstraint(t, orientation, constraint_plane, msg3);
854
 
                                }
855
 
                        }
856
 
                        else {
857
 
                                if (!(t->modifiers & MOD_CONSTRAINT_PLANE))
858
 
                                        setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_axis, msg2);
859
 
                                else if (t->modifiers & MOD_CONSTRAINT_PLANE)
860
 
                                        setUserConstraint(t, V3D_MANIP_GLOBAL, constraint_plane, msg3);
861
 
                        }
862
 
                }
863
 
                t->redraw |= TREDRAW_HARD;
864
 
        }
865
 
}
866
 
 
867
 
int transformEvent(TransInfo *t, wmEvent *event)
868
 
{
869
 
        float mati[3][3] = MAT3_UNITY;
870
 
        char cmode = constraintModeToChar(t);
871
 
        int handled = 1;
872
 
        
873
 
        t->redraw |= handleMouseInput(t, &t->mouse, event);
874
 
 
875
 
        if (event->type == MOUSEMOVE) {
876
 
                if (t->modifiers & MOD_CONSTRAINT_SELECT)
877
 
                        t->con.mode |= CON_SELECT;
878
 
 
879
 
                copy_v2_v2_int(t->mval, event->mval);
880
 
 
881
 
                // t->redraw |= TREDRAW_SOFT; /* Use this for soft redraw. Might cause flicker in object mode */
882
 
                t->redraw |= TREDRAW_HARD;
883
 
 
884
 
 
885
 
                if (t->state == TRANS_STARTING) {
886
 
                        t->state = TRANS_RUNNING;
887
 
                }
888
 
 
889
 
                applyMouseInput(t, &t->mouse, t->mval, t->values);
890
 
 
891
 
                // Snapping mouse move events
892
 
                t->redraw |= handleSnapping(t, event);
893
 
        }
894
 
 
895
 
        /* handle modal keymap first */
896
 
        if (event->type == EVT_MODAL_MAP) {
897
 
                switch (event->val) {
898
 
                        case TFM_MODAL_CANCEL:
899
 
                                t->state = TRANS_CANCEL;
900
 
                                break;
901
 
                        case TFM_MODAL_CONFIRM:
902
 
                                t->state = TRANS_CONFIRM;
903
 
                                break;
904
 
                        case TFM_MODAL_TRANSLATE:
905
 
                                /* only switch when... */
906
 
                                if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
907
 
                                        if (t->mode == TFM_EDGE_SLIDE) {
908
 
                                                freeEdgeSlideVerts(t);
909
 
                                        }
910
 
                                        else if (t->mode == TFM_VERT_SLIDE) {
911
 
                                                freeVertSlideVerts(t);
912
 
                                        }
913
 
                                        resetTransRestrictions(t);
914
 
                                        restoreTransObjects(t);
915
 
                                        initTranslation(t);
916
 
                                        initSnapping(t, NULL); // need to reinit after mode change
917
 
                                        t->redraw |= TREDRAW_HARD;
918
 
                                        WM_event_add_mousemove(t->context);
919
 
                                }
920
 
                                else if (t->mode == TFM_SEQ_SLIDE) {
921
 
                                        t->flag ^= T_ALT_TRANSFORM;
922
 
                                        t->redraw |= TREDRAW_HARD;
923
 
                                }
924
 
                                else {
925
 
                                        if (t->obedit && t->obedit->type == OB_MESH) {
926
 
                                                if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
927
 
                                                        resetTransRestrictions(t);
928
 
                                                        restoreTransObjects(t);
929
 
 
930
 
                                                        /* first try edge slide */
931
 
                                                        initEdgeSlide(t);
932
 
                                                        /* if that fails, do vertex slide */
933
 
                                                        if (t->state == TRANS_CANCEL) {
934
 
                                                                t->state = TRANS_STARTING;
935
 
                                                                initVertSlide(t);
936
 
                                                        }
937
 
                                                        /* vert slide can fail on unconnected vertices (rare but possible) */
938
 
                                                        if (t->state == TRANS_CANCEL) {
939
 
                                                                t->state = TRANS_STARTING;
940
 
                                                                resetTransRestrictions(t);
941
 
                                                                restoreTransObjects(t);
942
 
                                                                initTranslation(t);
943
 
                                                        }
944
 
                                                        initSnapping(t, NULL); // need to reinit after mode change
945
 
                                                        t->redraw |= TREDRAW_HARD;
946
 
                                                        WM_event_add_mousemove(t->context);
947
 
                                                }
948
 
                                        }
949
 
                                        else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) {
950
 
                                                if (t->mode == TFM_TRANSLATION) {
951
 
                                                        restoreTransObjects(t);
952
 
 
953
 
                                                        t->flag ^= T_ALT_TRANSFORM;
954
 
                                                        t->redraw |= TREDRAW_HARD;
955
 
                                                }
956
 
                                        }
957
 
                                }
958
 
                                break;
959
 
                        case TFM_MODAL_ROTATE:
960
 
                                /* only switch when... */
961
 
                                if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
962
 
                                        if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
963
 
                                                
964
 
                                                resetTransRestrictions(t);
965
 
                                                
966
 
                                                if (t->mode == TFM_ROTATION) {
967
 
                                                        restoreTransObjects(t);
968
 
                                                        initTrackball(t);
969
 
                                                }
970
 
                                                else {
971
 
                                                        restoreTransObjects(t);
972
 
                                                        initRotation(t);
973
 
                                                }
974
 
                                                initSnapping(t, NULL); // need to reinit after mode change
975
 
                                                t->redraw |= TREDRAW_HARD;
976
 
                                        }
977
 
                                }
978
 
                                break;
979
 
                        case TFM_MODAL_RESIZE:
980
 
                                /* only switch when... */
981
 
                                if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
982
 
                                        resetTransRestrictions(t);
983
 
                                        restoreTransObjects(t);
984
 
                                        initResize(t);
985
 
                                        initSnapping(t, NULL); // need to reinit after mode change
986
 
                                        t->redraw |= TREDRAW_HARD;
987
 
                                }
988
 
                                else if (t->mode == TFM_SHRINKFATTEN) {
989
 
                                        t->flag ^= T_ALT_TRANSFORM;
990
 
                                        t->redraw |= TREDRAW_HARD;
991
 
                                }
992
 
                                else if (t->mode == TFM_RESIZE) {
993
 
                                        if (t->options & CTX_MOVIECLIP) {
994
 
                                                restoreTransObjects(t);
995
 
 
996
 
                                                t->flag ^= T_ALT_TRANSFORM;
997
 
                                                t->redraw |= TREDRAW_HARD;
998
 
                                        }
999
 
                                }
1000
 
                                break;
1001
 
                                
1002
 
                        case TFM_MODAL_SNAP_INV_ON:
1003
 
                                t->modifiers |= MOD_SNAP_INVERT;
1004
 
                                t->redraw |= TREDRAW_HARD;
1005
 
                                break;
1006
 
                        case TFM_MODAL_SNAP_INV_OFF:
1007
 
                                t->modifiers &= ~MOD_SNAP_INVERT;
1008
 
                                t->redraw |= TREDRAW_HARD;
1009
 
                                break;
1010
 
                        case TFM_MODAL_SNAP_TOGGLE:
1011
 
                                t->modifiers ^= MOD_SNAP;
1012
 
                                t->redraw |= TREDRAW_HARD;
1013
 
                                break;
1014
 
                        case TFM_MODAL_AXIS_X:
1015
 
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
1016
 
                                        if (cmode == 'X') {
1017
 
                                                stopConstraint(t);
1018
 
                                        }
1019
 
                                        else {
1020
 
                                                if (t->flag & T_2D_EDIT) {
1021
 
                                                        setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS0), IFACE_("along X"));
1022
 
                                                }
1023
 
                                                else {
1024
 
                                                        setUserConstraint(t, t->current_orientation, (CON_AXIS0), IFACE_("along %s X"));
1025
 
                                                }
1026
 
                                        }
1027
 
                                        t->redraw |= TREDRAW_HARD;
1028
 
                                }
1029
 
                                break;
1030
 
                        case TFM_MODAL_AXIS_Y:
1031
 
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
1032
 
                                        if (cmode == 'Y') {
1033
 
                                                stopConstraint(t);
1034
 
                                        }
1035
 
                                        else {
1036
 
                                                if (t->flag & T_2D_EDIT) {
1037
 
                                                        setUserConstraint(t, V3D_MANIP_GLOBAL, (CON_AXIS1), IFACE_("along Y"));
1038
 
                                                }
1039
 
                                                else {
1040
 
                                                        setUserConstraint(t, t->current_orientation, (CON_AXIS1), IFACE_("along %s Y"));
1041
 
                                                }
1042
 
                                        }
1043
 
                                        t->redraw |= TREDRAW_HARD;
1044
 
                                }
1045
 
                                break;
1046
 
                        case TFM_MODAL_AXIS_Z:
1047
 
                                if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1048
 
                                        if (cmode == 'Z') {
1049
 
                                                stopConstraint(t);
1050
 
                                        }
1051
 
                                        else {
1052
 
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS2), IFACE_("along %s Z"));
1053
 
                                        }
1054
 
                                        t->redraw |= TREDRAW_HARD;
1055
 
                                }
1056
 
                                break;
1057
 
                        case TFM_MODAL_PLANE_X:
1058
 
                                if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1059
 
                                        if (cmode == 'X') {
1060
 
                                                stopConstraint(t);
1061
 
                                        }
1062
 
                                        else {
1063
 
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS1 | CON_AXIS2), IFACE_("locking %s X"));
1064
 
                                        }
1065
 
                                        t->redraw |= TREDRAW_HARD;
1066
 
                                }
1067
 
                                break;
1068
 
                        case TFM_MODAL_PLANE_Y:
1069
 
                                if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1070
 
                                        if (cmode == 'Y') {
1071
 
                                                stopConstraint(t);
1072
 
                                        }
1073
 
                                        else {
1074
 
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS2), IFACE_("locking %s Y"));
1075
 
                                        }
1076
 
                                        t->redraw |= TREDRAW_HARD;
1077
 
                                }
1078
 
                                break;
1079
 
                        case TFM_MODAL_PLANE_Z:
1080
 
                                if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) {
1081
 
                                        if (cmode == 'Z') {
1082
 
                                                stopConstraint(t);
1083
 
                                        }
1084
 
                                        else {
1085
 
                                                setUserConstraint(t, t->current_orientation, (CON_AXIS0 | CON_AXIS1), IFACE_("locking %s Z"));
1086
 
                                        }
1087
 
                                        t->redraw |= TREDRAW_HARD;
1088
 
                                }
1089
 
                                break;
1090
 
                        case TFM_MODAL_CONS_OFF:
1091
 
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
1092
 
                                        stopConstraint(t);
1093
 
                                        t->redraw |= TREDRAW_HARD;
1094
 
                                }
1095
 
                                break;
1096
 
                        case TFM_MODAL_ADD_SNAP:
1097
 
                                addSnapPoint(t);
1098
 
                                t->redraw |= TREDRAW_HARD;
1099
 
                                break;
1100
 
                        case TFM_MODAL_REMOVE_SNAP:
1101
 
                                removeSnapPoint(t);
1102
 
                                t->redraw |= TREDRAW_HARD;
1103
 
                                break;
1104
 
                                
1105
 
                        case TFM_MODAL_PROPSIZE:
1106
 
                                /* MOUSEPAN usage... */
1107
 
                                if (t->flag & T_PROP_EDIT) {
1108
 
                                        float fac = 1.0f + 0.005f *(event->y - event->prevy);
1109
 
                                        t->prop_size *= fac;
1110
 
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
1111
 
                                                t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
1112
 
                                        calculatePropRatio(t);
1113
 
                                }
1114
 
                                t->redraw |= TREDRAW_HARD;
1115
 
                                break;
1116
 
                                
1117
 
                        case TFM_MODAL_PROPSIZE_UP:
1118
 
                                if (t->flag & T_PROP_EDIT) {
1119
 
                                        t->prop_size *= 1.1f;
1120
 
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
1121
 
                                                t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
1122
 
                                        calculatePropRatio(t);
1123
 
                                }
1124
 
                                t->redraw |= TREDRAW_HARD;
1125
 
                                break;
1126
 
                        case TFM_MODAL_PROPSIZE_DOWN:
1127
 
                                if (t->flag & T_PROP_EDIT) {
1128
 
                                        t->prop_size *= 0.90909090f;
1129
 
                                        calculatePropRatio(t);
1130
 
                                }
1131
 
                                t->redraw |= TREDRAW_HARD;
1132
 
                                break;
1133
 
                        case TFM_MODAL_EDGESLIDE_UP:
1134
 
                        case TFM_MODAL_EDGESLIDE_DOWN:
1135
 
                                t->redraw |= TREDRAW_HARD;
1136
 
                                break;
1137
 
                        case TFM_MODAL_AUTOIK_LEN_INC:
1138
 
                                if (t->flag & T_AUTOIK)
1139
 
                                        transform_autoik_update(t, 1);
1140
 
                                t->redraw |= TREDRAW_HARD;
1141
 
                                break;
1142
 
                        case TFM_MODAL_AUTOIK_LEN_DEC:
1143
 
                                if (t->flag & T_AUTOIK) 
1144
 
                                        transform_autoik_update(t, -1);
1145
 
                                t->redraw |= TREDRAW_HARD;
1146
 
                                break;
1147
 
                        default:
1148
 
                                handled = 0;
1149
 
                                break;
1150
 
                }
1151
 
 
1152
 
                // Modal numinput events
1153
 
                t->redraw |= handleNumInput(&(t->num), event);
1154
 
        }
1155
 
        /* else do non-mapped events */
1156
 
        else if (event->val == KM_PRESS) {
1157
 
                switch (event->type) {
1158
 
                        case RIGHTMOUSE:
1159
 
                                t->state = TRANS_CANCEL;
1160
 
                                break;
1161
 
                        /* enforce redraw of transform when modifiers are used */
1162
 
                        case LEFTSHIFTKEY:
1163
 
                        case RIGHTSHIFTKEY:
1164
 
                                t->modifiers |= MOD_CONSTRAINT_PLANE;
1165
 
                                t->redraw |= TREDRAW_HARD;
1166
 
                                break;
1167
 
 
1168
 
                        case SPACEKEY:
1169
 
                                if ((t->spacetype == SPACE_VIEW3D) && event->alt) {
1170
 
#if 0 // TRANSFORM_FIX_ME
1171
 
                                        int mval[2];
1172
 
 
1173
 
                                        getmouseco_sc(mval);
1174
 
                                        BIF_selectOrientation();
1175
 
                                        calc_manipulator_stats(curarea);
1176
 
                                        copy_m3_m4(t->spacemtx, G.vd->twmat);
1177
 
                                        warp_pointer(mval[0], mval[1]);
1178
 
#endif
1179
 
                                }
1180
 
                                else {
1181
 
                                        t->state = TRANS_CONFIRM;
1182
 
                                }
1183
 
                                break;
1184
 
 
1185
 
                        case MIDDLEMOUSE:
1186
 
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
1187
 
                                        /* exception for switching to dolly, or trackball, in camera view */
1188
 
                                        if (t->flag & T_CAMERA) {
1189
 
                                                if (t->mode == TFM_TRANSLATION)
1190
 
                                                        setLocalConstraint(t, (CON_AXIS2), IFACE_("along local Z"));
1191
 
                                                else if (t->mode == TFM_ROTATION) {
1192
 
                                                        restoreTransObjects(t);
1193
 
                                                        initTrackball(t);
1194
 
                                                }
1195
 
                                        }
1196
 
                                        else {
1197
 
                                                t->modifiers |= MOD_CONSTRAINT_SELECT;
1198
 
                                                if (t->con.mode & CON_APPLY) {
1199
 
                                                        stopConstraint(t);
1200
 
                                                }
1201
 
                                                else {
1202
 
                                                        if (event->shift) {
1203
 
                                                                initSelectConstraint(t, t->spacemtx);
1204
 
                                                        }
1205
 
                                                        else {
1206
 
                                                                /* bit hackish... but it prevents mmb select to print the orientation from menu */
1207
 
                                                                strcpy(t->spacename, "global");
1208
 
                                                                initSelectConstraint(t, mati);
1209
 
                                                        }
1210
 
                                                        postSelectConstraint(t);
1211
 
                                                }
1212
 
                                        }
1213
 
                                        t->redraw |= TREDRAW_HARD;
1214
 
                                }
1215
 
                                break;
1216
 
                        case ESCKEY:
1217
 
                                t->state = TRANS_CANCEL;
1218
 
                                break;
1219
 
                        case PADENTER:
1220
 
                        case RETKEY:
1221
 
                                t->state = TRANS_CONFIRM;
1222
 
                                break;
1223
 
                        case GKEY:
1224
 
                                /* only switch when... */
1225
 
                                if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
1226
 
                                        resetTransRestrictions(t);
1227
 
                                        restoreTransObjects(t);
1228
 
                                        initTranslation(t);
1229
 
                                        initSnapping(t, NULL); // need to reinit after mode change
1230
 
                                        t->redraw |= TREDRAW_HARD;
1231
 
                                }
1232
 
                                break;
1233
 
                        case SKEY:
1234
 
                                /* only switch when... */
1235
 
                                if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
1236
 
                                        resetTransRestrictions(t);
1237
 
                                        restoreTransObjects(t);
1238
 
                                        initResize(t);
1239
 
                                        initSnapping(t, NULL); // need to reinit after mode change
1240
 
                                        t->redraw |= TREDRAW_HARD;
1241
 
                                }
1242
 
                                break;
1243
 
                        case RKEY:
1244
 
                                /* only switch when... */
1245
 
                                if (!(t->options & CTX_TEXTURE)) {
1246
 
                                        if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
1247
 
 
1248
 
                                                resetTransRestrictions(t);
1249
 
 
1250
 
                                                if (t->mode == TFM_ROTATION) {
1251
 
                                                        restoreTransObjects(t);
1252
 
                                                        initTrackball(t);
1253
 
                                                }
1254
 
                                                else {
1255
 
                                                        restoreTransObjects(t);
1256
 
                                                        initRotation(t);
1257
 
                                                }
1258
 
                                                initSnapping(t, NULL); // need to reinit after mode change
1259
 
                                                t->redraw |= TREDRAW_HARD;
1260
 
                                        }
1261
 
                                }
1262
 
                                break;
1263
 
                        case CKEY:
1264
 
                                if (event->alt) {
1265
 
                                        t->flag ^= T_PROP_CONNECTED;
1266
 
                                        sort_trans_data_dist(t);
1267
 
                                        calculatePropRatio(t);
1268
 
                                        t->redraw = 1;
1269
 
                                }
1270
 
                                else {
1271
 
                                        stopConstraint(t);
1272
 
                                        t->redraw |= TREDRAW_HARD;
1273
 
                                }
1274
 
                                break;
1275
 
                        case XKEY:
1276
 
                        case YKEY:
1277
 
                        case ZKEY:
1278
 
                                transform_event_xyz_constraint(t, event->type, cmode);
1279
 
                                break;
1280
 
                        case OKEY:
1281
 
                                if (t->flag & T_PROP_EDIT && event->shift) {
1282
 
                                        t->prop_mode = (t->prop_mode + 1) % PROP_MODE_MAX;
1283
 
                                        calculatePropRatio(t);
1284
 
                                        t->redraw |= TREDRAW_HARD;
1285
 
                                }
1286
 
                                break;
1287
 
                        case PADPLUSKEY:
1288
 
                                if (event->alt && t->flag & T_PROP_EDIT) {
1289
 
                                        t->prop_size *= 1.1f;
1290
 
                                        if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO)
1291
 
                                                t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far);
1292
 
                                        calculatePropRatio(t);
1293
 
                                }
1294
 
                                t->redraw = 1;
1295
 
                                break;
1296
 
                        case PAGEUPKEY:
1297
 
                        case WHEELDOWNMOUSE:
1298
 
                                if (t->flag & T_AUTOIK) {
1299
 
                                        transform_autoik_update(t, 1);
1300
 
                                }
1301
 
                                else view_editmove(event->type);
1302
 
                                t->redraw = 1;
1303
 
                                break;
1304
 
                        case PADMINUS:
1305
 
                                if (event->alt && t->flag & T_PROP_EDIT) {
1306
 
                                        t->prop_size *= 0.90909090f;
1307
 
                                        calculatePropRatio(t);
1308
 
                                }
1309
 
                                t->redraw = 1;
1310
 
                                break;
1311
 
                        case PAGEDOWNKEY:
1312
 
                        case WHEELUPMOUSE:
1313
 
                                if (t->flag & T_AUTOIK) {
1314
 
                                        transform_autoik_update(t, -1);
1315
 
                                }
1316
 
                                else view_editmove(event->type);
1317
 
                                t->redraw = 1;
1318
 
                                break;
1319
 
                        case LEFTALTKEY:
1320
 
                        case RIGHTALTKEY:
1321
 
                                if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1322
 
                                        t->flag |= T_ALT_TRANSFORM;
1323
 
                                        t->redraw |= TREDRAW_HARD;
1324
 
                                }
1325
 
 
1326
 
                                break;
1327
 
                        default:
1328
 
                                handled = 0;
1329
 
                                break;
1330
 
                }
1331
 
 
1332
 
                // Numerical input events
1333
 
                t->redraw |= handleNumInput(&(t->num), event);
1334
 
 
1335
 
                // Snapping key events
1336
 
                t->redraw |= handleSnapping(t, event);
1337
 
 
1338
 
        }
1339
 
        else if (event->val == KM_RELEASE) {
1340
 
                switch (event->type) {
1341
 
                        case LEFTSHIFTKEY:
1342
 
                        case RIGHTSHIFTKEY:
1343
 
                                t->modifiers &= ~MOD_CONSTRAINT_PLANE;
1344
 
                                t->redraw |= TREDRAW_HARD;
1345
 
                                break;
1346
 
 
1347
 
                        case MIDDLEMOUSE:
1348
 
                                if ((t->flag & T_NO_CONSTRAINT) == 0) {
1349
 
                                        t->modifiers &= ~MOD_CONSTRAINT_SELECT;
1350
 
                                        postSelectConstraint(t);
1351
 
                                        t->redraw |= TREDRAW_HARD;
1352
 
                                }
1353
 
                                break;
1354
 
//              case LEFTMOUSE:
1355
 
//              case RIGHTMOUSE:
1356
 
//                      if (WM_modal_tweak_exit(event, t->event_type))
1357
 
////                    if (t->options & CTX_TWEAK)
1358
 
//                              t->state = TRANS_CONFIRM;
1359
 
//                      break;
1360
 
                        case LEFTALTKEY:
1361
 
                        case RIGHTALTKEY:
1362
 
                                if (ELEM(t->spacetype, SPACE_SEQ, SPACE_VIEW3D)) {
1363
 
                                        t->flag &= ~T_ALT_TRANSFORM;
1364
 
                                        t->redraw |= TREDRAW_HARD;
1365
 
                                }
1366
 
 
1367
 
                                break;
1368
 
                        default:
1369
 
                                handled = 0;
1370
 
                                break;
1371
 
                }
1372
 
 
1373
 
                /* confirm transform if launch key is released after mouse move */
1374
 
                if (t->flag & T_RELEASE_CONFIRM) {
1375
 
                        /* XXX Keyrepeat bug in Xorg fucks this up, will test when fixed */
1376
 
                        if (event->type == t->launch_event && (t->launch_event == LEFTMOUSE || t->launch_event == RIGHTMOUSE)) {
1377
 
                                t->state = TRANS_CONFIRM;
1378
 
                        }
1379
 
                }
1380
 
        }
1381
 
        else
1382
 
                handled = 0;
1383
 
 
1384
 
        // Per transform event, if present
1385
 
        if (t->handleEvent)
1386
 
                t->redraw |= t->handleEvent(t, event);
1387
 
 
1388
 
        if (handled || t->redraw) {
1389
 
                return 0;
1390
 
        }
1391
 
        else {
1392
 
                return OPERATOR_PASS_THROUGH;
1393
 
        }
1394
 
}
1395
 
 
1396
 
int calculateTransformCenter(bContext *C, int centerMode, float cent3d[3], int cent2d[2])
1397
 
{
1398
 
        TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data");
1399
 
        int success;
1400
 
 
1401
 
        t->state = TRANS_RUNNING;
1402
 
 
1403
 
        t->options = CTX_NONE;
1404
 
 
1405
 
        t->mode = TFM_DUMMY;
1406
 
 
1407
 
        initTransInfo(C, t, NULL, NULL);    // internal data, mouse, vectors
1408
 
 
1409
 
        createTransData(C, t);              // make TransData structs from selection
1410
 
 
1411
 
        t->around = centerMode;             // override userdefined mode
1412
 
 
1413
 
        if (t->total == 0) {
1414
 
                success = FALSE;
1415
 
        }
1416
 
        else {
1417
 
                success = TRUE;
1418
 
 
1419
 
                calculateCenter(t);
1420
 
 
1421
 
                if (cent2d) {
1422
 
                        copy_v2_v2_int(cent2d, t->center2d);
1423
 
                }
1424
 
 
1425
 
                if (cent3d) {
1426
 
                        // Copy center from constraint center. Transform center can be local
1427
 
                        copy_v3_v3(cent3d, t->con.center);
1428
 
                }
1429
 
        }
1430
 
 
1431
 
 
1432
 
        /* aftertrans does insert ipos and action channels, and clears base flags, doesnt read transdata */
1433
 
        special_aftertrans_update(C, t);
1434
 
 
1435
 
        postTrans(C, t);
1436
 
 
1437
 
        MEM_freeN(t);
1438
 
 
1439
 
        return success;
1440
 
}
1441
 
 
1442
 
typedef enum {
1443
 
        UP,
1444
 
        DOWN,
1445
 
        LEFT,
1446
 
        RIGHT
1447
 
} ArrowDirection;
1448
 
static void drawArrow(ArrowDirection d, short offset, short length, short size)
1449
 
{
1450
 
        switch (d) {
1451
 
                case LEFT:
1452
 
                        offset = -offset;
1453
 
                        length = -length;
1454
 
                        size = -size;
1455
 
                case RIGHT:
1456
 
                        glBegin(GL_LINES);
1457
 
                        glVertex2s(offset, 0);
1458
 
                        glVertex2s(offset + length, 0);
1459
 
                        glVertex2s(offset + length, 0);
1460
 
                        glVertex2s(offset + length - size, -size);
1461
 
                        glVertex2s(offset + length, 0);
1462
 
                        glVertex2s(offset + length - size,  size);
1463
 
                        glEnd();
1464
 
                        break;
1465
 
                case DOWN:
1466
 
                        offset = -offset;
1467
 
                        length = -length;
1468
 
                        size = -size;
1469
 
                case UP:
1470
 
                        glBegin(GL_LINES);
1471
 
                        glVertex2s(0, offset);
1472
 
                        glVertex2s(0, offset + length);
1473
 
                        glVertex2s(0, offset + length);
1474
 
                        glVertex2s(-size, offset + length - size);
1475
 
                        glVertex2s(0, offset + length);
1476
 
                        glVertex2s(size, offset + length - size);
1477
 
                        glEnd();
1478
 
                        break;
1479
 
        }
1480
 
}
1481
 
 
1482
 
static void drawArrowHead(ArrowDirection d, short size)
1483
 
{
1484
 
        switch (d) {
1485
 
                case LEFT:
1486
 
                        size = -size;
1487
 
                case RIGHT:
1488
 
                        glBegin(GL_LINES);
1489
 
                        glVertex2s(0, 0);
1490
 
                        glVertex2s(-size, -size);
1491
 
                        glVertex2s(0, 0);
1492
 
                        glVertex2s(-size,  size);
1493
 
                        glEnd();
1494
 
                        break;
1495
 
                case DOWN:
1496
 
                        size = -size;
1497
 
                case UP:
1498
 
                        glBegin(GL_LINES);
1499
 
                        glVertex2s(0, 0);
1500
 
                        glVertex2s(-size, -size);
1501
 
                        glVertex2s(0, 0);
1502
 
                        glVertex2s(size, -size);
1503
 
                        glEnd();
1504
 
                        break;
1505
 
        }
1506
 
}
1507
 
 
1508
 
static void drawArc(float size, float angle_start, float angle_end, int segments)
1509
 
{
1510
 
        float delta = (angle_end - angle_start) / segments;
1511
 
        float angle;
1512
 
        int a;
1513
 
 
1514
 
        glBegin(GL_LINE_STRIP);
1515
 
 
1516
 
        for (angle = angle_start, a = 0; a < segments; angle += delta, a++) {
1517
 
                glVertex2f(cosf(angle) * size, sinf(angle) * size);
1518
 
        }
1519
 
        glVertex2f(cosf(angle_end) * size, sinf(angle_end) * size);
1520
 
 
1521
 
        glEnd();
1522
 
}
1523
 
 
1524
 
static int helpline_poll(bContext *C)
1525
 
{
1526
 
        ARegion *ar = CTX_wm_region(C);
1527
 
        
1528
 
        if (ar && ar->regiontype == RGN_TYPE_WINDOW)
1529
 
                return 1;
1530
 
        return 0;
1531
 
}
1532
 
 
1533
 
static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
1534
 
{
1535
 
        TransInfo *t = (TransInfo *)customdata;
1536
 
 
1537
 
        if (t->helpline != HLP_NONE && !(t->flag & T_USES_MANIPULATOR)) {
1538
 
                float vecrot[3], cent[2];
1539
 
                int mval[2];
1540
 
 
1541
 
                mval[0] = x;
1542
 
                mval[1] = y;
1543
 
 
1544
 
                copy_v3_v3(vecrot, t->center);
1545
 
                if (t->flag & T_EDIT) {
1546
 
                        Object *ob = t->obedit;
1547
 
                        if (ob) mul_m4_v3(ob->obmat, vecrot);
1548
 
                }
1549
 
                else if (t->flag & T_POSE) {
1550
 
                        Object *ob = t->poseobj;
1551
 
                        if (ob) mul_m4_v3(ob->obmat, vecrot);
1552
 
                }
1553
 
 
1554
 
                projectFloatViewEx(t, vecrot, cent, V3D_PROJ_TEST_CLIP_ZERO);
1555
 
 
1556
 
                glPushMatrix();
1557
 
 
1558
 
                switch (t->helpline) {
1559
 
                        case HLP_SPRING:
1560
 
                                UI_ThemeColor(TH_WIRE);
1561
 
 
1562
 
                                setlinestyle(3);
1563
 
                                glBegin(GL_LINE_STRIP);
1564
 
                                glVertex2iv(t->mval);
1565
 
                                glVertex2fv(cent);
1566
 
                                glEnd();
1567
 
 
1568
 
                                glTranslatef(mval[0], mval[1], 0);
1569
 
                                glRotatef(-RAD2DEGF(atan2f(cent[0] - t->mval[0], cent[1] - t->mval[1])), 0, 0, 1);
1570
 
 
1571
 
                                setlinestyle(0);
1572
 
                                glLineWidth(3.0);
1573
 
                                drawArrow(UP, 5, 10, 5);
1574
 
                                drawArrow(DOWN, 5, 10, 5);
1575
 
                                glLineWidth(1.0);
1576
 
                                break;
1577
 
                        case HLP_HARROW:
1578
 
                                UI_ThemeColor(TH_WIRE);
1579
 
 
1580
 
                                glTranslatef(mval[0], mval[1], 0);
1581
 
 
1582
 
                                glLineWidth(3.0);
1583
 
                                drawArrow(RIGHT, 5, 10, 5);
1584
 
                                drawArrow(LEFT, 5, 10, 5);
1585
 
                                glLineWidth(1.0);
1586
 
                                break;
1587
 
                        case HLP_VARROW:
1588
 
                                UI_ThemeColor(TH_WIRE);
1589
 
 
1590
 
                                glTranslatef(mval[0], mval[1], 0);
1591
 
 
1592
 
                                glLineWidth(3.0);
1593
 
                                drawArrow(UP, 5, 10, 5);
1594
 
                                drawArrow(DOWN, 5, 10, 5);
1595
 
                                glLineWidth(1.0);
1596
 
                                break;
1597
 
                        case HLP_ANGLE:
1598
 
                        {
1599
 
                                float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
1600
 
                                float angle = atan2f(dy, dx);
1601
 
                                float dist = sqrtf(dx * dx + dy * dy);
1602
 
                                float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
1603
 
                                float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
1604
 
                                UI_ThemeColor(TH_WIRE);
1605
 
 
1606
 
                                setlinestyle(3);
1607
 
                                glBegin(GL_LINE_STRIP);
1608
 
                                glVertex2iv(t->mval);
1609
 
                                glVertex2fv(cent);
1610
 
                                glEnd();
1611
 
 
1612
 
                                glTranslatef(cent[0] - t->mval[0] + mval[0], cent[1] - t->mval[1] + mval[1], 0);
1613
 
 
1614
 
                                setlinestyle(0);
1615
 
                                glLineWidth(3.0);
1616
 
                                drawArc(dist, angle - delta_angle, angle - spacing_angle, 10);
1617
 
                                drawArc(dist, angle + spacing_angle, angle + delta_angle, 10);
1618
 
 
1619
 
                                glPushMatrix();
1620
 
 
1621
 
                                glTranslatef(cosf(angle - delta_angle) * dist, sinf(angle - delta_angle) * dist, 0);
1622
 
                                glRotatef(RAD2DEGF(angle - delta_angle), 0, 0, 1);
1623
 
 
1624
 
                                drawArrowHead(DOWN, 5);
1625
 
 
1626
 
                                glPopMatrix();
1627
 
 
1628
 
                                glTranslatef(cosf(angle + delta_angle) * dist, sinf(angle + delta_angle) * dist, 0);
1629
 
                                glRotatef(RAD2DEGF(angle + delta_angle), 0, 0, 1);
1630
 
 
1631
 
                                drawArrowHead(UP, 5);
1632
 
 
1633
 
                                glLineWidth(1.0);
1634
 
                                break;
1635
 
                        }
1636
 
                        case HLP_TRACKBALL:
1637
 
                        {
1638
 
                                unsigned char col[3], col2[3];
1639
 
                                UI_GetThemeColor3ubv(TH_GRID, col);
1640
 
 
1641
 
                                glTranslatef(mval[0], mval[1], 0);
1642
 
 
1643
 
                                glLineWidth(3.0);
1644
 
 
1645
 
                                UI_make_axis_color(col, col2, 'X');
1646
 
                                glColor3ubv((GLubyte *)col2);
1647
 
 
1648
 
                                drawArrow(RIGHT, 5, 10, 5);
1649
 
                                drawArrow(LEFT, 5, 10, 5);
1650
 
 
1651
 
                                UI_make_axis_color(col, col2, 'Y');
1652
 
                                glColor3ubv((GLubyte *)col2);
1653
 
 
1654
 
                                drawArrow(UP, 5, 10, 5);
1655
 
                                drawArrow(DOWN, 5, 10, 5);
1656
 
                                glLineWidth(1.0);
1657
 
                                break;
1658
 
                        }
1659
 
                }
1660
 
 
1661
 
                glPopMatrix();
1662
 
        }
1663
 
}
1664
 
 
1665
 
static void drawTransformView(const struct bContext *C, ARegion *UNUSED(ar), void *arg)
1666
 
{
1667
 
        TransInfo *t = arg;
1668
 
 
1669
 
        drawConstraint(t);
1670
 
        drawPropCircle(C, t);
1671
 
        drawSnapping(C, t);
1672
 
 
1673
 
        /* edge slide, vert slide */
1674
 
        drawEdgeSlide(C, t);
1675
 
        drawVertSlide(C, t);
1676
 
}
1677
 
 
1678
 
/* just draw a little warning message in the top-right corner of the viewport to warn that autokeying is enabled */
1679
 
static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
1680
 
{
1681
 
        rcti rect;
1682
 
        const char *printable = IFACE_("Auto Keying On");
1683
 
        float      printable_size[2];
1684
 
        int xco, yco;
1685
 
 
1686
 
        ED_region_visible_rect(ar, &rect);
1687
 
        
1688
 
        BLF_width_and_height_default(printable, &printable_size[0], &printable_size[1]);
1689
 
        
1690
 
        xco = rect.xmax - (int)printable_size[0] - 10;
1691
 
        yco = rect.ymax - (int)printable_size[1] - 10;
1692
 
        
1693
 
        /* warning text (to clarify meaning of overlays)
1694
 
         * - original color was red to match the icon, but that clashes badly with a less nasty border
1695
 
         */
1696
 
        UI_ThemeColorShade(TH_TEXT_HI, -50);
1697
 
#ifdef WITH_INTERNATIONAL
1698
 
        BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
1699
 
#else
1700
 
        BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, sizeof(printable));
1701
 
#endif
1702
 
        
1703
 
        /* autokey recording icon... */
1704
 
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1705
 
        glEnable(GL_BLEND);
1706
 
        
1707
 
        xco -= (ICON_DEFAULT_WIDTH + 2);
1708
 
        UI_icon_draw(xco, yco, ICON_REC);
1709
 
        
1710
 
        glDisable(GL_BLEND);
1711
 
}
1712
 
 
1713
 
static void drawTransformPixel(const struct bContext *UNUSED(C), ARegion *ar, void *arg)
1714
 
{       
1715
 
        TransInfo *t = arg;
1716
 
        Scene *scene = t->scene;
1717
 
        Object *ob = OBACT;
1718
 
        
1719
 
        /* draw autokeyframing hint in the corner 
1720
 
         * - only draw if enabled (advanced users may be distracted/annoyed), 
1721
 
         *   for objects that will be autokeyframed (no point ohterwise),
1722
 
         *   AND only for the active region (as showing all is too overwhelming)
1723
 
         */
1724
 
        if ((U.autokey_flag & AUTOKEY_FLAG_NOWARNING) == 0) {
1725
 
                if (ar == t->ar) {
1726
 
                        if (t->flag & (T_OBJECT | T_POSE)) {
1727
 
                                if (ob && autokeyframe_cfra_can_key(scene, &ob->id)) {
1728
 
                                        drawAutoKeyWarning(t, ar);
1729
 
                                }
1730
 
                        }
1731
 
                }
1732
 
        }
1733
 
}
1734
 
 
1735
 
void saveTransform(bContext *C, TransInfo *t, wmOperator *op)
1736
 
{
1737
 
        ToolSettings *ts = CTX_data_tool_settings(C);
1738
 
        int constraint_axis[3] = {0, 0, 0};
1739
 
        int proportional = 0;
1740
 
        PropertyRNA *prop;
1741
 
 
1742
 
        // Save back mode in case we're in the generic operator
1743
 
        if ((prop = RNA_struct_find_property(op->ptr, "mode"))) {
1744
 
                RNA_property_enum_set(op->ptr, prop, t->mode);
1745
 
        }
1746
 
 
1747
 
        if ((prop = RNA_struct_find_property(op->ptr, "value"))) {
1748
 
                float *values = (t->flag & T_AUTOVALUES) ? t->auto_values : t->values;
1749
 
                if (RNA_property_array_check(prop)) {
1750
 
                        RNA_property_float_set_array(op->ptr, prop, values);
1751
 
                }
1752
 
                else {
1753
 
                        RNA_property_float_set(op->ptr, prop, values[0]);
1754
 
                }
1755
 
        }
1756
 
 
1757
 
        /* convert flag to enum */
1758
 
        switch (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
1759
 
                case (T_PROP_EDIT | T_PROP_CONNECTED):
1760
 
                        proportional = PROP_EDIT_CONNECTED;
1761
 
                        break;
1762
 
                case T_PROP_EDIT:
1763
 
                        proportional = PROP_EDIT_ON;
1764
 
                        break;
1765
 
                default:
1766
 
                        proportional = PROP_EDIT_OFF;
1767
 
        }
1768
 
 
1769
 
        // If modal, save settings back in scene if not set as operator argument
1770
 
        if (t->flag & T_MODAL) {
1771
 
 
1772
 
                /* save settings if not set in operator */
1773
 
                if ((prop = RNA_struct_find_property(op->ptr, "proportional")) &&
1774
 
                    !RNA_property_is_set(op->ptr, prop))
1775
 
                {
1776
 
                        if (t->obedit)
1777
 
                                ts->proportional = proportional;
1778
 
                        else if (t->options & CTX_MASK)
1779
 
                                ts->proportional_mask = (proportional != PROP_EDIT_OFF);
1780
 
                        else
1781
 
                                ts->proportional_objects = (proportional != PROP_EDIT_OFF);
1782
 
                }
1783
 
 
1784
 
                if ((prop = RNA_struct_find_property(op->ptr, "proportional_size")) &&
1785
 
                    !RNA_property_is_set(op->ptr, prop))
1786
 
                {
1787
 
                        ts->proportional_size = t->prop_size;
1788
 
                }
1789
 
 
1790
 
                if ((prop = RNA_struct_find_property(op->ptr, "proportional_edit_falloff")) &&
1791
 
                    !RNA_property_is_set(op->ptr, prop))
1792
 
                {
1793
 
                        ts->prop_mode = t->prop_mode;
1794
 
                }
1795
 
                
1796
 
                /* do we check for parameter? */
1797
 
                if (t->modifiers & MOD_SNAP) {
1798
 
                        ts->snap_flag |= SCE_SNAP;
1799
 
                }
1800
 
                else {
1801
 
                        ts->snap_flag &= ~SCE_SNAP;
1802
 
                }
1803
 
 
1804
 
                if (t->spacetype == SPACE_VIEW3D) {
1805
 
                        if ((prop = RNA_struct_find_property(op->ptr, "constraint_orientation")) &&
1806
 
                            !RNA_property_is_set(op->ptr, prop))
1807
 
                        {
1808
 
                                View3D *v3d = t->view;
1809
 
 
1810
 
                                v3d->twmode = t->current_orientation;
1811
 
                        }
1812
 
                }
1813
 
        }
1814
 
        
1815
 
        if (RNA_struct_find_property(op->ptr, "proportional")) {
1816
 
                RNA_enum_set(op->ptr, "proportional", proportional);
1817
 
                RNA_enum_set(op->ptr, "proportional_edit_falloff", t->prop_mode);
1818
 
                RNA_float_set(op->ptr, "proportional_size", t->prop_size);
1819
 
        }
1820
 
 
1821
 
        if ((prop = RNA_struct_find_property(op->ptr, "axis"))) {
1822
 
                RNA_property_float_set_array(op->ptr, prop, t->axis);
1823
 
        }
1824
 
 
1825
 
        if ((prop = RNA_struct_find_property(op->ptr, "mirror"))) {
1826
 
                RNA_property_boolean_set(op->ptr, prop, t->flag & T_MIRROR);
1827
 
        }
1828
 
 
1829
 
        if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) {
1830
 
                /* constraint orientation can be global, event if user selects something else
1831
 
                 * so use the orientation in the constraint if set
1832
 
                 * */
1833
 
                if (t->con.mode & CON_APPLY) {
1834
 
                        RNA_enum_set(op->ptr, "constraint_orientation", t->con.orientation);
1835
 
                }
1836
 
                else {
1837
 
                        RNA_enum_set(op->ptr, "constraint_orientation", t->current_orientation);
1838
 
                }
1839
 
 
1840
 
                if (t->con.mode & CON_APPLY) {
1841
 
                        if (t->con.mode & CON_AXIS0) {
1842
 
                                constraint_axis[0] = 1;
1843
 
                        }
1844
 
                        if (t->con.mode & CON_AXIS1) {
1845
 
                                constraint_axis[1] = 1;
1846
 
                        }
1847
 
                        if (t->con.mode & CON_AXIS2) {
1848
 
                                constraint_axis[2] = 1;
1849
 
                        }
1850
 
                }
1851
 
 
1852
 
                RNA_property_boolean_set_array(op->ptr, prop, constraint_axis);
1853
 
        }
1854
 
}
1855
 
 
1856
 
/* note: caller needs to free 't' on a 0 return */
1857
 
int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int mode)
1858
 
{
1859
 
        int options = 0;
1860
 
        PropertyRNA *prop;
1861
 
 
1862
 
        t->context = C;
1863
 
 
1864
 
        /* added initialize, for external calls to set stuff in TransInfo, like undo string */
1865
 
 
1866
 
        t->state = TRANS_STARTING;
1867
 
 
1868
 
        if ((prop = RNA_struct_find_property(op->ptr, "texture_space")) && RNA_property_is_set(op->ptr, prop)) {
1869
 
                if (RNA_property_boolean_get(op->ptr, prop)) {
1870
 
                        options |= CTX_TEXTURE;
1871
 
                }
1872
 
        }
1873
 
        
1874
 
        t->options = options;
1875
 
 
1876
 
        t->mode = mode;
1877
 
 
1878
 
        t->launch_event = event ? event->type : -1;
1879
 
 
1880
 
        if (t->launch_event == EVT_TWEAK_R) {
1881
 
                t->launch_event = RIGHTMOUSE;
1882
 
        }
1883
 
        else if (t->launch_event == EVT_TWEAK_L) {
1884
 
                t->launch_event = LEFTMOUSE;
1885
 
        }
1886
 
 
1887
 
        // XXX Remove this when wm_operator_call_internal doesn't use window->eventstate (which can have type = 0)
1888
 
        // For manipulator only, so assume LEFTMOUSE
1889
 
        if (t->launch_event == 0) {
1890
 
                t->launch_event = LEFTMOUSE;
1891
 
        }
1892
 
 
1893
 
        if (!initTransInfo(C, t, op, event)) {  /* internal data, mouse, vectors */
1894
 
                return 0;
1895
 
        }
1896
 
 
1897
 
        if (t->spacetype == SPACE_VIEW3D) {
1898
 
                //calc_manipulator_stats(curarea);
1899
 
                initTransformOrientation(C, t);
1900
 
 
1901
 
                t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
1902
 
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
1903
 
                t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
1904
 
                t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
1905
 
        }
1906
 
        else if (t->spacetype == SPACE_IMAGE) {
1907
 
                unit_m3(t->spacemtx);
1908
 
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
1909
 
                //t->draw_handle_pixel = ED_region_draw_cb_activate(t->ar->type, drawTransformPixel, t, REGION_DRAW_POST_PIXEL);
1910
 
                t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);
1911
 
        }
1912
 
        else if (t->spacetype == SPACE_CLIP) {
1913
 
                unit_m3(t->spacemtx);
1914
 
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
1915
 
        }
1916
 
        else if (t->spacetype == SPACE_NODE) {
1917
 
                unit_m3(t->spacemtx);
1918
 
                /*t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);*/
1919
 
                t->draw_handle_view = ED_region_draw_cb_activate(t->ar->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
1920
 
                /*t->draw_handle_cursor = WM_paint_cursor_activate(CTX_wm_manager(C), helpline_poll, drawHelpline, t);*/
1921
 
        }
1922
 
        else
1923
 
                unit_m3(t->spacemtx);
1924
 
 
1925
 
        createTransData(C, t);          // make TransData structs from selection
1926
 
 
1927
 
        if (t->total == 0) {
1928
 
                postTrans(C, t);
1929
 
                return 0;
1930
 
        }
1931
 
 
1932
 
        /* Stupid code to have Ctrl-Click on manipulator work ok */
1933
 
        if (event) {
1934
 
                /* do this only for translation/rotation/resize due to only this
1935
 
                 * moded are available from manipulator and doing such check could
1936
 
                 * lead to keymap conflicts for other modes (see #31584)
1937
 
                 */
1938
 
                if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
1939
 
                        wmKeyMap *keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1940
 
                        wmKeyMapItem *kmi;
1941
 
 
1942
 
                        for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
1943
 
                                if (kmi->propvalue == TFM_MODAL_SNAP_INV_ON && kmi->val == KM_PRESS) {
1944
 
                                        if ((ELEM(kmi->type, LEFTCTRLKEY, RIGHTCTRLKEY) &&   event->ctrl)  ||
1945
 
                                            (ELEM(kmi->type, LEFTSHIFTKEY, RIGHTSHIFTKEY) && event->shift) ||
1946
 
                                            (ELEM(kmi->type, LEFTALTKEY, RIGHTALTKEY) &&     event->alt)   ||
1947
 
                                            ((kmi->type == OSKEY) &&                         event->oskey) )
1948
 
                                        {
1949
 
                                                t->modifiers |= MOD_SNAP_INVERT;
1950
 
                                        }
1951
 
                                        break;
1952
 
                                }
1953
 
                        }
1954
 
                }
1955
 
 
1956
 
        }
1957
 
 
1958
 
        t->keymap = WM_keymap_active(CTX_wm_manager(C), op->type->modalkeymap);
1959
 
 
1960
 
        initSnapping(t, op); // Initialize snapping data AFTER mode flags
1961
 
 
1962
 
        /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
1963
 
        /* EVIL2: we gave as argument also texture space context bit... was cleared */
1964
 
        /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
1965
 
        mode = t->mode;
1966
 
 
1967
 
        calculatePropRatio(t);
1968
 
        calculateCenter(t);
1969
 
 
1970
 
        initMouseInput(t, &t->mouse, t->center2d, t->imval);
1971
 
 
1972
 
        switch (mode) {
1973
 
                case TFM_TRANSLATION:
1974
 
                        initTranslation(t);
1975
 
                        break;
1976
 
                case TFM_ROTATION:
1977
 
                        initRotation(t);
1978
 
                        break;
1979
 
                case TFM_RESIZE:
1980
 
                        initResize(t);
1981
 
                        break;
1982
 
                case TFM_SKIN_RESIZE:
1983
 
                        initSkinResize(t);
1984
 
                        break;
1985
 
                case TFM_TOSPHERE:
1986
 
                        initToSphere(t);
1987
 
                        break;
1988
 
                case TFM_SHEAR:
1989
 
                        initShear(t);
1990
 
                        break;
1991
 
                case TFM_WARP:
1992
 
                        initWarp(t);
1993
 
                        break;
1994
 
                case TFM_SHRINKFATTEN:
1995
 
                        initShrinkFatten(t);
1996
 
                        break;
1997
 
                case TFM_TILT:
1998
 
                        initTilt(t);
1999
 
                        break;
2000
 
                case TFM_CURVE_SHRINKFATTEN:
2001
 
                        initCurveShrinkFatten(t);
2002
 
                        break;
2003
 
                case TFM_MASK_SHRINKFATTEN:
2004
 
                        initMaskShrinkFatten(t);
2005
 
                        break;
2006
 
                case TFM_TRACKBALL:
2007
 
                        initTrackball(t);
2008
 
                        break;
2009
 
                case TFM_PUSHPULL:
2010
 
                        initPushPull(t);
2011
 
                        break;
2012
 
                case TFM_CREASE:
2013
 
                        initCrease(t);
2014
 
                        break;
2015
 
                case TFM_BONESIZE:
2016
 
                {   /* used for both B-Bone width (bonesize) as for deform-dist (envelope) */
2017
 
                        bArmature *arm = t->poseobj->data;
2018
 
                        if (arm->drawtype == ARM_ENVELOPE)
2019
 
                                initBoneEnvelope(t);
2020
 
                        else
2021
 
                                initBoneSize(t);
2022
 
                }
2023
 
                break;
2024
 
                case TFM_BONE_ENVELOPE:
2025
 
                        initBoneEnvelope(t);
2026
 
                        break;
2027
 
                case TFM_EDGE_SLIDE:
2028
 
                        initEdgeSlide(t);
2029
 
                        break;
2030
 
                case TFM_VERT_SLIDE:
2031
 
                        initVertSlide(t);
2032
 
                        break;
2033
 
                case TFM_BONE_ROLL:
2034
 
                        initBoneRoll(t);
2035
 
                        break;
2036
 
                case TFM_TIME_TRANSLATE:
2037
 
                        initTimeTranslate(t);
2038
 
                        break;
2039
 
                case TFM_TIME_SLIDE:
2040
 
                        initTimeSlide(t);
2041
 
                        break;
2042
 
                case TFM_TIME_SCALE:
2043
 
                        initTimeScale(t);
2044
 
                        break;
2045
 
                case TFM_TIME_DUPLICATE:
2046
 
                        /* same as TFM_TIME_EXTEND, but we need the mode info for later
2047
 
                         * so that duplicate-culling will work properly
2048
 
                         */
2049
 
                        if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA))
2050
 
                                initTranslation(t);
2051
 
                        else
2052
 
                                initTimeTranslate(t);
2053
 
                        t->mode = mode;
2054
 
                        break;
2055
 
                case TFM_TIME_EXTEND:
2056
 
                        /* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
2057
 
                         * Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
2058
 
                         * (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
2059
 
                         * depending on which editor this was called from
2060
 
                         */
2061
 
                        if (ELEM(t->spacetype, SPACE_IPO, SPACE_NLA))
2062
 
                                initTranslation(t);
2063
 
                        else
2064
 
                                initTimeTranslate(t);
2065
 
                        break;
2066
 
                case TFM_BAKE_TIME:
2067
 
                        initBakeTime(t);
2068
 
                        break;
2069
 
                case TFM_MIRROR:
2070
 
                        initMirror(t);
2071
 
                        break;
2072
 
                case TFM_BEVEL:
2073
 
                        initBevel(t);
2074
 
                        break;
2075
 
                case TFM_BWEIGHT:
2076
 
                        initBevelWeight(t);
2077
 
                        break;
2078
 
                case TFM_ALIGN:
2079
 
                        initAlign(t);
2080
 
                        break;
2081
 
                case TFM_SEQ_SLIDE:
2082
 
                        initSeqSlide(t);
2083
 
                        break;
2084
 
        }
2085
 
 
2086
 
        if (t->state == TRANS_CANCEL) {
2087
 
                postTrans(C, t);
2088
 
                return 0;
2089
 
        }
2090
 
 
2091
 
 
2092
 
        /* overwrite initial values if operator supplied a non-null vector */
2093
 
        if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) {
2094
 
                float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory  */
2095
 
 
2096
 
                if (RNA_property_array_check(prop)) {
2097
 
                        RNA_float_get_array(op->ptr, "value", values);
2098
 
                }
2099
 
                else {
2100
 
                        values[0] = RNA_float_get(op->ptr, "value");
2101
 
                }
2102
 
 
2103
 
                copy_v4_v4(t->values, values);
2104
 
                copy_v4_v4(t->auto_values, values);
2105
 
                t->flag |= T_AUTOVALUES;
2106
 
        }
2107
 
 
2108
 
        /* Transformation axis from operator */
2109
 
        if ((prop = RNA_struct_find_property(op->ptr, "axis")) && RNA_property_is_set(op->ptr, prop)) {
2110
 
                RNA_property_float_get_array(op->ptr, prop, t->axis);
2111
 
                normalize_v3(t->axis);
2112
 
                copy_v3_v3(t->axis_orig, t->axis);
2113
 
        }
2114
 
 
2115
 
        /* Constraint init from operator */
2116
 
        if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && RNA_property_is_set(op->ptr, prop)) {
2117
 
                int constraint_axis[3];
2118
 
 
2119
 
                RNA_property_boolean_get_array(op->ptr, prop, constraint_axis);
2120
 
 
2121
 
                if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) {
2122
 
                        t->con.mode |= CON_APPLY;
2123
 
 
2124
 
                        if (constraint_axis[0]) {
2125
 
                                t->con.mode |= CON_AXIS0;
2126
 
                        }
2127
 
                        if (constraint_axis[1]) {
2128
 
                                t->con.mode |= CON_AXIS1;
2129
 
                        }
2130
 
                        if (constraint_axis[2]) {
2131
 
                                t->con.mode |= CON_AXIS2;
2132
 
                        }
2133
 
 
2134
 
                        setUserConstraint(t, t->current_orientation, t->con.mode, "%s");
2135
 
                }
2136
 
        }
2137
 
 
2138
 
        t->context = NULL;
2139
 
 
2140
 
        return 1;
2141
 
}
2142
 
 
2143
 
void transformApply(bContext *C, TransInfo *t)
2144
 
{
2145
 
        t->context = C;
2146
 
 
2147
 
        if ((t->redraw & TREDRAW_HARD) || (t->draw_handle_apply == NULL && (t->redraw & TREDRAW_SOFT))) {
2148
 
                selectConstraint(t);
2149
 
                if (t->transform) {
2150
 
                        t->transform(t, t->mval);  // calls recalcData()
2151
 
                        viewRedrawForce(C, t);
2152
 
                }
2153
 
                t->redraw = TREDRAW_NOTHING;
2154
 
        }
2155
 
        else if (t->redraw & TREDRAW_SOFT) {
2156
 
                viewRedrawForce(C, t);
2157
 
        }
2158
 
 
2159
 
        /* If auto confirm is on, break after one pass */
2160
 
        if (t->options & CTX_AUTOCONFIRM) {
2161
 
                t->state = TRANS_CONFIRM;
2162
 
        }
2163
 
 
2164
 
        t->context = NULL;
2165
 
}
2166
 
 
2167
 
static void drawTransformApply(const bContext *C, ARegion *UNUSED(ar), void *arg)
2168
 
{
2169
 
        TransInfo *t = arg;
2170
 
 
2171
 
        if (t->redraw & TREDRAW_SOFT) {
2172
 
                t->redraw |= TREDRAW_HARD;
2173
 
                transformApply((bContext *)C, t);
2174
 
        }
2175
 
}
2176
 
 
2177
 
int transformEnd(bContext *C, TransInfo *t)
2178
 
{
2179
 
        int exit_code = OPERATOR_RUNNING_MODAL;
2180
 
 
2181
 
        t->context = C;
2182
 
 
2183
 
        if (t->state != TRANS_STARTING && t->state != TRANS_RUNNING) {
2184
 
                /* handle restoring objects */
2185
 
                if (t->state == TRANS_CANCEL) {
2186
 
                        /* exception, edge slide transformed UVs too */
2187
 
                        if (t->mode == TFM_EDGE_SLIDE)
2188
 
                                doEdgeSlide(t, 0.0f);
2189
 
                        
2190
 
                        exit_code = OPERATOR_CANCELLED;
2191
 
                        restoreTransObjects(t); // calls recalcData()
2192
 
                }
2193
 
                else {
2194
 
                        exit_code = OPERATOR_FINISHED;
2195
 
                }
2196
 
 
2197
 
                /* aftertrans does insert keyframes, and clears base flags, doesnt read transdata */
2198
 
                special_aftertrans_update(C, t);
2199
 
 
2200
 
                /* free data */
2201
 
                postTrans(C, t);
2202
 
 
2203
 
                /* send events out for redraws */
2204
 
                viewRedrawPost(C, t);
2205
 
 
2206
 
                /*  Undo as last, certainly after special_trans_update! */
2207
 
 
2208
 
                if (t->state == TRANS_CANCEL) {
2209
 
//                      if (t->undostr) ED_undo_push(C, t->undostr);
2210
 
                }
2211
 
                else {
2212
 
//                      if (t->undostr) ED_undo_push(C, t->undostr);
2213
 
//                      else ED_undo_push(C, transform_to_undostr(t));
2214
 
                }
2215
 
                t->undostr = NULL;
2216
 
 
2217
 
                viewRedrawForce(C, t);
2218
 
        }
2219
 
 
2220
 
        t->context = NULL;
2221
 
 
2222
 
        return exit_code;
2223
 
}
2224
 
 
2225
 
/* ************************** TRANSFORM LOCKS **************************** */
2226
 
 
2227
 
static void protectedTransBits(short protectflag, float *vec)
2228
 
{
2229
 
        if (protectflag & OB_LOCK_LOCX)
2230
 
                vec[0] = 0.0f;
2231
 
        if (protectflag & OB_LOCK_LOCY)
2232
 
                vec[1] = 0.0f;
2233
 
        if (protectflag & OB_LOCK_LOCZ)
2234
 
                vec[2] = 0.0f;
2235
 
}
2236
 
 
2237
 
static void protectedSizeBits(short protectflag, float *size)
2238
 
{
2239
 
        if (protectflag & OB_LOCK_SCALEX)
2240
 
                size[0] = 1.0f;
2241
 
        if (protectflag & OB_LOCK_SCALEY)
2242
 
                size[1] = 1.0f;
2243
 
        if (protectflag & OB_LOCK_SCALEZ)
2244
 
                size[2] = 1.0f;
2245
 
}
2246
 
 
2247
 
static void protectedRotateBits(short protectflag, float *eul, float *oldeul)
2248
 
{
2249
 
        if (protectflag & OB_LOCK_ROTX)
2250
 
                eul[0] = oldeul[0];
2251
 
        if (protectflag & OB_LOCK_ROTY)
2252
 
                eul[1] = oldeul[1];
2253
 
        if (protectflag & OB_LOCK_ROTZ)
2254
 
                eul[2] = oldeul[2];
2255
 
}
2256
 
 
2257
 
 
2258
 
/* this function only does the delta rotation */
2259
 
/* axis-angle is usually internally stored as quats... */
2260
 
static void protectedAxisAngleBits(short protectflag, float axis[3], float *angle, float oldAxis[3], float oldAngle)
2261
 
{
2262
 
        /* check that protection flags are set */
2263
 
        if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0)
2264
 
                return;
2265
 
        
2266
 
        if (protectflag & OB_LOCK_ROT4D) {
2267
 
                /* axis-angle getting limited as 4D entities that they are... */
2268
 
                if (protectflag & OB_LOCK_ROTW)
2269
 
                        *angle = oldAngle;
2270
 
                if (protectflag & OB_LOCK_ROTX)
2271
 
                        axis[0] = oldAxis[0];
2272
 
                if (protectflag & OB_LOCK_ROTY)
2273
 
                        axis[1] = oldAxis[1];
2274
 
                if (protectflag & OB_LOCK_ROTZ)
2275
 
                        axis[2] = oldAxis[2];
2276
 
        }
2277
 
        else {
2278
 
                /* axis-angle get limited with euler... */
2279
 
                float eul[3], oldeul[3];
2280
 
                
2281
 
                axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, axis, *angle);
2282
 
                axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, oldAxis, oldAngle);
2283
 
                
2284
 
                if (protectflag & OB_LOCK_ROTX)
2285
 
                        eul[0] = oldeul[0];
2286
 
                if (protectflag & OB_LOCK_ROTY)
2287
 
                        eul[1] = oldeul[1];
2288
 
                if (protectflag & OB_LOCK_ROTZ)
2289
 
                        eul[2] = oldeul[2];
2290
 
                
2291
 
                eulO_to_axis_angle(axis, angle, eul, EULER_ORDER_DEFAULT);
2292
 
                
2293
 
                /* when converting to axis-angle, we need a special exception for the case when there is no axis */
2294
 
                if (IS_EQF(axis[0], axis[1]) && IS_EQF(axis[1], axis[2])) {
2295
 
                        /* for now, rotate around y-axis then (so that it simply becomes the roll) */
2296
 
                        axis[1] = 1.0f;
2297
 
                }
2298
 
        }
2299
 
}
2300
 
 
2301
 
/* this function only does the delta rotation */
2302
 
static void protectedQuaternionBits(short protectflag, float *quat, float *oldquat)
2303
 
{
2304
 
        /* check that protection flags are set */
2305
 
        if ((protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) == 0)
2306
 
                return;
2307
 
        
2308
 
        if (protectflag & OB_LOCK_ROT4D) {
2309
 
                /* quaternions getting limited as 4D entities that they are... */
2310
 
                if (protectflag & OB_LOCK_ROTW)
2311
 
                        quat[0] = oldquat[0];
2312
 
                if (protectflag & OB_LOCK_ROTX)
2313
 
                        quat[1] = oldquat[1];
2314
 
                if (protectflag & OB_LOCK_ROTY)
2315
 
                        quat[2] = oldquat[2];
2316
 
                if (protectflag & OB_LOCK_ROTZ)
2317
 
                        quat[3] = oldquat[3];
2318
 
        }
2319
 
        else {
2320
 
                /* quaternions get limited with euler... (compatibility mode) */
2321
 
                float eul[3], oldeul[3], nquat[4], noldquat[4];
2322
 
                float qlen;
2323
 
 
2324
 
                qlen = normalize_qt_qt(nquat, quat);
2325
 
                normalize_qt_qt(noldquat, oldquat);
2326
 
 
2327
 
                quat_to_eul(eul, nquat);
2328
 
                quat_to_eul(oldeul, noldquat);
2329
 
 
2330
 
                if (protectflag & OB_LOCK_ROTX)
2331
 
                        eul[0] = oldeul[0];
2332
 
                if (protectflag & OB_LOCK_ROTY)
2333
 
                        eul[1] = oldeul[1];
2334
 
                if (protectflag & OB_LOCK_ROTZ)
2335
 
                        eul[2] = oldeul[2];
2336
 
 
2337
 
                eul_to_quat(quat, eul);
2338
 
 
2339
 
                /* restore original quat size */
2340
 
                mul_qt_fl(quat, qlen);
2341
 
                
2342
 
                /* quaternions flip w sign to accumulate rotations correctly */
2343
 
                if ((nquat[0] < 0.0f && quat[0] > 0.0f) ||
2344
 
                    (nquat[0] > 0.0f && quat[0] < 0.0f))
2345
 
                {
2346
 
                        mul_qt_fl(quat, -1.0f);
2347
 
                }
2348
 
        }
2349
 
}
2350
 
 
2351
 
/* ******************* TRANSFORM LIMITS ********************** */
2352
 
 
2353
 
static void constraintTransLim(TransInfo *t, TransData *td)
2354
 
{
2355
 
        if (td->con) {
2356
 
                bConstraintTypeInfo *ctiLoc = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_LOCLIMIT);
2357
 
                bConstraintTypeInfo *ctiDist = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_DISTLIMIT);
2358
 
                
2359
 
                bConstraintOb cob = {NULL};
2360
 
                bConstraint *con;
2361
 
                float ctime = (float)(t->scene->r.cfra);
2362
 
                
2363
 
                /* Make a temporary bConstraintOb for using these limit constraints
2364
 
                 *  - they only care that cob->matrix is correctly set ;-)
2365
 
                 *      - current space should be local
2366
 
                 */
2367
 
                unit_m4(cob.matrix);
2368
 
                copy_v3_v3(cob.matrix[3], td->loc);
2369
 
                
2370
 
                /* Evaluate valid constraints */
2371
 
                for (con = td->con; con; con = con->next) {
2372
 
                        bConstraintTypeInfo *cti = NULL;
2373
 
                        ListBase targets = {NULL, NULL};
2374
 
                        
2375
 
                        /* only consider constraint if enabled */
2376
 
                        if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
2377
 
                        if (con->enforce == 0.0f) continue;
2378
 
                        
2379
 
                        /* only use it if it's tagged for this purpose (and the right type) */
2380
 
                        if (con->type == CONSTRAINT_TYPE_LOCLIMIT) {
2381
 
                                bLocLimitConstraint *data = con->data;
2382
 
                                
2383
 
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
2384
 
                                        continue;
2385
 
                                cti = ctiLoc;
2386
 
                        }
2387
 
                        else if (con->type == CONSTRAINT_TYPE_DISTLIMIT) {
2388
 
                                bDistLimitConstraint *data = con->data;
2389
 
                                
2390
 
                                if ((data->flag & LIMITDIST_TRANSFORM) == 0)
2391
 
                                        continue;
2392
 
                                cti = ctiDist;
2393
 
                        }
2394
 
                        
2395
 
                        if (cti) {
2396
 
                                /* do space conversions */
2397
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2398
 
                                        /* just multiply by td->mtx (this should be ok) */
2399
 
                                        mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
2400
 
                                }
2401
 
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
2402
 
                                        /* skip... incompatable spacetype */
2403
 
                                        continue;
2404
 
                                }
2405
 
                                
2406
 
                                /* get constraint targets if needed */
2407
 
                                BKE_get_constraint_targets_for_solving(con, &cob, &targets, ctime);
2408
 
                                
2409
 
                                /* do constraint */
2410
 
                                cti->evaluate_constraint(con, &cob, &targets);
2411
 
                                
2412
 
                                /* convert spaces again */
2413
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2414
 
                                        /* just multiply by td->smtx (this should be ok) */
2415
 
                                        mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
2416
 
                                }
2417
 
                                
2418
 
                                /* free targets list */
2419
 
                                BLI_freelistN(&targets);
2420
 
                        }
2421
 
                }
2422
 
                
2423
 
                /* copy results from cob->matrix */
2424
 
                copy_v3_v3(td->loc, cob.matrix[3]);
2425
 
        }
2426
 
}
2427
 
 
2428
 
static void constraintob_from_transdata(bConstraintOb *cob, TransData *td)
2429
 
{
2430
 
        /* Make a temporary bConstraintOb for use by limit constraints
2431
 
         *  - they only care that cob->matrix is correctly set ;-)
2432
 
         *      - current space should be local
2433
 
         */
2434
 
        memset(cob, 0, sizeof(bConstraintOb));
2435
 
        if (td->ext) {
2436
 
                if (td->ext->rotOrder == ROT_MODE_QUAT) {
2437
 
                        /* quats */
2438
 
                        /* objects and bones do normalization first too, otherwise
2439
 
                         * we don't necessarily end up with a rotation matrix, and
2440
 
                         * then conversion back to quat gives a different result */
2441
 
                        float quat[4];
2442
 
                        normalize_qt_qt(quat, td->ext->quat);
2443
 
                        quat_to_mat4(cob->matrix, quat);
2444
 
                }
2445
 
                else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2446
 
                        /* axis angle */
2447
 
                        axis_angle_to_mat4(cob->matrix, &td->ext->quat[1], td->ext->quat[0]);
2448
 
                }
2449
 
                else {
2450
 
                        /* eulers */
2451
 
                        eulO_to_mat4(cob->matrix, td->ext->rot, td->ext->rotOrder);
2452
 
                }
2453
 
        }
2454
 
}
2455
 
 
2456
 
static void constraintRotLim(TransInfo *UNUSED(t), TransData *td)
2457
 
{
2458
 
        if (td->con) {
2459
 
                bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_ROTLIMIT);
2460
 
                bConstraintOb cob;
2461
 
                bConstraint *con;
2462
 
                int do_limit = FALSE;
2463
 
 
2464
 
                /* Evaluate valid constraints */
2465
 
                for (con = td->con; con; con = con->next) {
2466
 
                        /* only consider constraint if enabled */
2467
 
                        if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
2468
 
                        if (con->enforce == 0.0f) continue;
2469
 
 
2470
 
                        /* we're only interested in Limit-Rotation constraints */
2471
 
                        if (con->type == CONSTRAINT_TYPE_ROTLIMIT) {
2472
 
                                bRotLimitConstraint *data = con->data;
2473
 
 
2474
 
                                /* only use it if it's tagged for this purpose */
2475
 
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
2476
 
                                        continue;
2477
 
 
2478
 
                                /* skip incompatable spacetypes */
2479
 
                                if (!ELEM(con->ownspace, CONSTRAINT_SPACE_WORLD, CONSTRAINT_SPACE_LOCAL))
2480
 
                                        continue;
2481
 
 
2482
 
                                /* only do conversion if necessary, to preserve quats and eulers */
2483
 
                                if (do_limit == FALSE) {
2484
 
                                        constraintob_from_transdata(&cob, td);
2485
 
                                        do_limit = TRUE;
2486
 
                                }
2487
 
 
2488
 
                                /* do space conversions */
2489
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2490
 
                                        /* just multiply by td->mtx (this should be ok) */
2491
 
                                        mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
2492
 
                                }
2493
 
                                
2494
 
                                /* do constraint */
2495
 
                                cti->evaluate_constraint(con, &cob, NULL);
2496
 
                                
2497
 
                                /* convert spaces again */
2498
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2499
 
                                        /* just multiply by td->smtx (this should be ok) */
2500
 
                                        mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
2501
 
                                }
2502
 
                        }
2503
 
                }
2504
 
                
2505
 
                if (do_limit) {
2506
 
                        /* copy results from cob->matrix */
2507
 
                        if (td->ext->rotOrder == ROT_MODE_QUAT) {
2508
 
                                /* quats */
2509
 
                                mat4_to_quat(td->ext->quat, cob.matrix);
2510
 
                        }
2511
 
                        else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
2512
 
                                /* axis angle */
2513
 
                                mat4_to_axis_angle(&td->ext->quat[1], &td->ext->quat[0], cob.matrix);
2514
 
                        }
2515
 
                        else {
2516
 
                                /* eulers */
2517
 
                                mat4_to_eulO(td->ext->rot, td->ext->rotOrder, cob.matrix);
2518
 
                        }
2519
 
                }
2520
 
        }
2521
 
}
2522
 
 
2523
 
static void constraintSizeLim(TransInfo *t, TransData *td)
2524
 
{
2525
 
        if (td->con && td->ext) {
2526
 
                bConstraintTypeInfo *cti = BKE_get_constraint_typeinfo(CONSTRAINT_TYPE_SIZELIMIT);
2527
 
                bConstraintOb cob = {NULL};
2528
 
                bConstraint *con;
2529
 
                float size_sign[3], size_abs[3];
2530
 
                int i;
2531
 
                
2532
 
                /* Make a temporary bConstraintOb for using these limit constraints
2533
 
                 *  - they only care that cob->matrix is correctly set ;-)
2534
 
                 *      - current space should be local
2535
 
                 */
2536
 
                if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
2537
 
                        /* scale val and reset size */
2538
 
                        return; // TODO: fix this case
2539
 
                }
2540
 
                else {
2541
 
                        /* Reset val if SINGLESIZE but using a constraint */
2542
 
                        if (td->flag & TD_SINGLESIZE)
2543
 
                                return;
2544
 
 
2545
 
                        /* separate out sign to apply back later */
2546
 
                        for (i = 0; i < 3; i++) {
2547
 
                                size_sign[i] = signf(td->ext->size[i]);
2548
 
                                size_abs[i] = fabsf(td->ext->size[i]);
2549
 
                        }
2550
 
                        
2551
 
                        size_to_mat4(cob.matrix, size_abs);
2552
 
                }
2553
 
                
2554
 
                /* Evaluate valid constraints */
2555
 
                for (con = td->con; con; con = con->next) {
2556
 
                        /* only consider constraint if enabled */
2557
 
                        if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) continue;
2558
 
                        if (con->enforce == 0.0f) continue;
2559
 
                        
2560
 
                        /* we're only interested in Limit-Scale constraints */
2561
 
                        if (con->type == CONSTRAINT_TYPE_SIZELIMIT) {
2562
 
                                bSizeLimitConstraint *data = con->data;
2563
 
                                
2564
 
                                /* only use it if it's tagged for this purpose */
2565
 
                                if ((data->flag2 & LIMIT_TRANSFORM) == 0)
2566
 
                                        continue;
2567
 
                                
2568
 
                                /* do space conversions */
2569
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2570
 
                                        /* just multiply by td->mtx (this should be ok) */
2571
 
                                        mul_m4_m3m4(cob.matrix, td->mtx, cob.matrix);
2572
 
                                }
2573
 
                                else if (con->ownspace != CONSTRAINT_SPACE_LOCAL) {
2574
 
                                        /* skip... incompatible spacetype */
2575
 
                                        continue;
2576
 
                                }
2577
 
                                
2578
 
                                /* do constraint */
2579
 
                                cti->evaluate_constraint(con, &cob, NULL);
2580
 
                                
2581
 
                                /* convert spaces again */
2582
 
                                if (con->ownspace == CONSTRAINT_SPACE_WORLD) {
2583
 
                                        /* just multiply by td->smtx (this should be ok) */
2584
 
                                        mul_m4_m3m4(cob.matrix, td->smtx, cob.matrix);
2585
 
                                }
2586
 
                        }
2587
 
                }
2588
 
 
2589
 
                /* copy results from cob->matrix */
2590
 
                if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
2591
 
                        /* scale val and reset size */
2592
 
                        return; // TODO: fix this case
2593
 
                }
2594
 
                else {
2595
 
                        /* Reset val if SINGLESIZE but using a constraint */
2596
 
                        if (td->flag & TD_SINGLESIZE)
2597
 
                                return;
2598
 
 
2599
 
                        /* extrace scale from matrix and apply back sign */
2600
 
                        mat4_to_size(td->ext->size, cob.matrix);
2601
 
                        mul_v3_v3(td->ext->size, size_sign);
2602
 
                }
2603
 
        }
2604
 
}
2605
 
 
2606
 
/* ************************** WARP *************************** */
2607
 
 
2608
 
static void postInputWarp(TransInfo *t, float values[3])
2609
 
{
2610
 
        mul_v3_fl(values, (float)(M_PI * 2));
2611
 
 
2612
 
        if (t->customData) { /* non-null value indicates reversed input */
2613
 
                negate_v3(values);
2614
 
        }
2615
 
}
2616
 
 
2617
 
void initWarp(TransInfo *t)
2618
 
{
2619
 
        float max[3], min[3];
2620
 
        int i;
2621
 
        
2622
 
        t->mode = TFM_WARP;
2623
 
        t->transform = Warp;
2624
 
        t->handleEvent = handleEventWarp;
2625
 
        
2626
 
        setInputPostFct(&t->mouse, postInputWarp);
2627
 
        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
2628
 
        
2629
 
        t->idx_max = 0;
2630
 
        t->num.idx_max = 0;
2631
 
        t->snap[0] = 0.0f;
2632
 
        t->snap[1] = 5.0f / 180.0f * (float)M_PI;
2633
 
        t->snap[2] = 1.0f / 180.0f * (float)M_PI;
2634
 
        
2635
 
        t->num.increment = 1.0f;
2636
 
 
2637
 
        t->flag |= T_NO_CONSTRAINT;
2638
 
        
2639
 
        /* we need min/max in view space */
2640
 
        for (i = 0; i < t->total; i++) {
2641
 
                float center[3];
2642
 
                copy_v3_v3(center, t->data[i].center);
2643
 
                mul_m3_v3(t->data[i].mtx, center);
2644
 
                mul_m4_v3(t->viewmat, center);
2645
 
                sub_v3_v3(center, t->viewmat[3]);
2646
 
                if (i) {
2647
 
                        minmax_v3v3_v3(min, max, center);
2648
 
                }
2649
 
                else {
2650
 
                        copy_v3_v3(max, center);
2651
 
                        copy_v3_v3(min, center);
2652
 
                }
2653
 
        }
2654
 
 
2655
 
        mid_v3_v3v3(t->center, min, max);
2656
 
 
2657
 
        if (max[0] == min[0]) max[0] += 0.1f;  /* not optimal, but flipping is better than invalid garbage (i.e. division by zero!) */
2658
 
        t->val = (max[0] - min[0]) / 2.0f; /* t->val is X dimension projected boundbox */
2659
 
}
2660
 
 
2661
 
int handleEventWarp(TransInfo *t, wmEvent *event)
2662
 
{
2663
 
        int status = 0;
2664
 
        
2665
 
        if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
2666
 
                // Use customData pointer to signal warp direction
2667
 
                if (t->customData == NULL)
2668
 
                        t->customData = (void *)1;
2669
 
                else
2670
 
                        t->customData = NULL;
2671
 
                
2672
 
                status = 1;
2673
 
        }
2674
 
        
2675
 
        return status;
2676
 
}
2677
 
 
2678
 
int Warp(TransInfo *t, const int UNUSED(mval[2]))
2679
 
{
2680
 
        TransData *td = t->data;
2681
 
        float vec[3], circumfac, dist, phi0, co, si, cursor[3], gcursor[3];
2682
 
        const float *curs;
2683
 
        int i;
2684
 
        char str[50];
2685
 
        
2686
 
        curs = give_cursor(t->scene, t->view);
2687
 
        /*
2688
 
         * gcursor is the one used for helpline.
2689
 
         * It has to be in the same space as the drawing loop
2690
 
         * (that means it needs to be in the object's space when in edit mode and
2691
 
         *  in global space in object mode)
2692
 
         *
2693
 
         * cursor is used for calculations.
2694
 
         * It needs to be in view space, but we need to take object's offset
2695
 
         * into account if in Edit mode.
2696
 
         */
2697
 
        copy_v3_v3(cursor, curs);
2698
 
        copy_v3_v3(gcursor, cursor);
2699
 
        if (t->flag & T_EDIT) {
2700
 
                sub_v3_v3(cursor, t->obedit->obmat[3]);
2701
 
                sub_v3_v3(gcursor, t->obedit->obmat[3]);
2702
 
                mul_m3_v3(t->data->smtx, gcursor);
2703
 
        }
2704
 
        mul_m4_v3(t->viewmat, cursor);
2705
 
        sub_v3_v3(cursor, t->viewmat[3]);
2706
 
        
2707
 
        /* amount of radians for warp */
2708
 
        circumfac = t->values[0];
2709
 
        
2710
 
        snapGrid(t, &circumfac);
2711
 
        applyNumInput(&t->num, &circumfac);
2712
 
        
2713
 
        /* header print for NumInput */
2714
 
        if (hasNumInput(&t->num)) {
2715
 
                char c[NUM_STR_REP_LEN];
2716
 
                
2717
 
                outputNumInput(&(t->num), c);
2718
 
                
2719
 
                sprintf(str, IFACE_("Warp: %s"), c);
2720
 
 
2721
 
                circumfac = DEG2RADF(circumfac);
2722
 
        }
2723
 
        else {
2724
 
                /* default header print */
2725
 
                sprintf(str, IFACE_("Warp: %.3f"), RAD2DEGF(circumfac));
2726
 
        }
2727
 
        
2728
 
        t->values[0] = circumfac;
2729
 
 
2730
 
        circumfac /= 2; /* only need 180 on each side to make 360 */
2731
 
        
2732
 
        for (i = 0; i < t->total; i++, td++) {
2733
 
                float loc[3];
2734
 
                if (td->flag & TD_NOACTION)
2735
 
                        break;
2736
 
                
2737
 
                if (td->flag & TD_SKIP)
2738
 
                        continue;
2739
 
                
2740
 
                /* translate point to center, rotate in such a way that outline==distance */
2741
 
                copy_v3_v3(vec, td->iloc);
2742
 
                mul_m3_v3(td->mtx, vec);
2743
 
                mul_m4_v3(t->viewmat, vec);
2744
 
                sub_v3_v3(vec, t->viewmat[3]);
2745
 
                
2746
 
                dist = vec[0] - cursor[0];
2747
 
                
2748
 
                /* t->val is X dimension projected boundbox */
2749
 
                phi0 = (circumfac * dist / t->val);
2750
 
                
2751
 
                vec[1] = (vec[1] - cursor[1]);
2752
 
                
2753
 
                co = (float)cos(phi0);
2754
 
                si = (float)sin(phi0);
2755
 
                loc[0] = -si * vec[1] + cursor[0];
2756
 
                loc[1] = co * vec[1] + cursor[1];
2757
 
                loc[2] = vec[2];
2758
 
                
2759
 
                mul_m4_v3(t->viewinv, loc);
2760
 
                sub_v3_v3(loc, t->viewinv[3]);
2761
 
                mul_m3_v3(td->smtx, loc);
2762
 
                
2763
 
                sub_v3_v3(loc, td->iloc);
2764
 
                mul_v3_fl(loc, td->factor);
2765
 
                add_v3_v3v3(td->loc, td->iloc, loc);
2766
 
        }
2767
 
        
2768
 
        recalcData(t);
2769
 
        
2770
 
        ED_area_headerprint(t->sa, str);
2771
 
        
2772
 
        return 1;
2773
 
}
2774
 
 
2775
 
/* ************************** SHEAR *************************** */
2776
 
 
2777
 
static void postInputShear(TransInfo *UNUSED(t), float values[3])
2778
 
{
2779
 
        mul_v3_fl(values, 0.05f);
2780
 
}
2781
 
 
2782
 
void initShear(TransInfo *t)
2783
 
{
2784
 
        t->mode = TFM_SHEAR;
2785
 
        t->transform = Shear;
2786
 
        t->handleEvent = handleEventShear;
2787
 
        
2788
 
        setInputPostFct(&t->mouse, postInputShear);
2789
 
        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
2790
 
        
2791
 
        t->idx_max = 0;
2792
 
        t->num.idx_max = 0;
2793
 
        t->snap[0] = 0.0f;
2794
 
        t->snap[1] = 0.1f;
2795
 
        t->snap[2] = t->snap[1] * 0.1f;
2796
 
        
2797
 
        t->num.increment = 0.1f;
2798
 
 
2799
 
        t->flag |= T_NO_CONSTRAINT;
2800
 
}
2801
 
 
2802
 
int handleEventShear(TransInfo *t, wmEvent *event)
2803
 
{
2804
 
        int status = 0;
2805
 
        
2806
 
        if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
2807
 
                // Use customData pointer to signal Shear direction
2808
 
                if (t->customData == NULL) {
2809
 
                        initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
2810
 
                        t->customData = (void *)1;
2811
 
                }
2812
 
                else {
2813
 
                        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
2814
 
                        t->customData = NULL;
2815
 
                }
2816
 
 
2817
 
                status = 1;
2818
 
        }
2819
 
        else if (event->type == XKEY && event->val == KM_PRESS) {
2820
 
                initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
2821
 
                t->customData = NULL;
2822
 
                
2823
 
                status = 1;
2824
 
        }
2825
 
        else if (event->type == YKEY && event->val == KM_PRESS) {
2826
 
                initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
2827
 
                t->customData = (void *)1;
2828
 
                
2829
 
                status = 1;
2830
 
        }
2831
 
        
2832
 
        return status;
2833
 
}
2834
 
 
2835
 
 
2836
 
int Shear(TransInfo *t, const int UNUSED(mval[2]))
2837
 
{
2838
 
        TransData *td = t->data;
2839
 
        float vec[3];
2840
 
        float smat[3][3], tmat[3][3], totmat[3][3], persmat[3][3], persinv[3][3];
2841
 
        float value;
2842
 
        int i;
2843
 
        char str[50];
2844
 
        
2845
 
        copy_m3_m4(persmat, t->viewmat);
2846
 
        invert_m3_m3(persinv, persmat);
2847
 
        
2848
 
        value = t->values[0];
2849
 
        
2850
 
        snapGrid(t, &value);
2851
 
        
2852
 
        applyNumInput(&t->num, &value);
2853
 
        
2854
 
        /* header print for NumInput */
2855
 
        if (hasNumInput(&t->num)) {
2856
 
                char c[NUM_STR_REP_LEN];
2857
 
                
2858
 
                outputNumInput(&(t->num), c);
2859
 
                
2860
 
                sprintf(str, IFACE_("Shear: %s %s"), c, t->proptext);
2861
 
        }
2862
 
        else {
2863
 
                /* default header print */
2864
 
                sprintf(str, IFACE_("Shear: %.3f %s (Press X or Y to set shear axis)"), value, t->proptext);
2865
 
        }
2866
 
        
2867
 
        t->values[0] = value;
2868
 
 
2869
 
        unit_m3(smat);
2870
 
        
2871
 
        // Custom data signals shear direction
2872
 
        if (t->customData == NULL)
2873
 
                smat[1][0] = value;
2874
 
        else
2875
 
                smat[0][1] = value;
2876
 
        
2877
 
        mul_m3_m3m3(tmat, smat, persmat);
2878
 
        mul_m3_m3m3(totmat, persinv, tmat);
2879
 
        
2880
 
        for (i = 0; i < t->total; i++, td++) {
2881
 
                if (td->flag & TD_NOACTION)
2882
 
                        break;
2883
 
                
2884
 
                if (td->flag & TD_SKIP)
2885
 
                        continue;
2886
 
                
2887
 
                if (t->obedit) {
2888
 
                        float mat3[3][3];
2889
 
                        mul_m3_m3m3(mat3, totmat, td->mtx);
2890
 
                        mul_m3_m3m3(tmat, td->smtx, mat3);
2891
 
                }
2892
 
                else {
2893
 
                        copy_m3_m3(tmat, totmat);
2894
 
                }
2895
 
                sub_v3_v3v3(vec, td->center, t->center);
2896
 
                
2897
 
                mul_m3_v3(tmat, vec);
2898
 
                
2899
 
                add_v3_v3(vec, t->center);
2900
 
                sub_v3_v3(vec, td->center);
2901
 
                
2902
 
                mul_v3_fl(vec, td->factor);
2903
 
                
2904
 
                add_v3_v3v3(td->loc, td->iloc, vec);
2905
 
        }
2906
 
        
2907
 
        recalcData(t);
2908
 
        
2909
 
        ED_area_headerprint(t->sa, str);
2910
 
 
2911
 
        return 1;
2912
 
}
2913
 
 
2914
 
/* ************************** RESIZE *************************** */
2915
 
 
2916
 
void initResize(TransInfo *t)
2917
 
{
2918
 
        t->mode = TFM_RESIZE;
2919
 
        t->transform = Resize;
2920
 
        
2921
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
2922
 
        
2923
 
        t->flag |= T_NULL_ONE;
2924
 
        t->num.flag |= NUM_NULL_ONE;
2925
 
        t->num.flag |= NUM_AFFECT_ALL;
2926
 
        if (!t->obedit) {
2927
 
                t->flag |= T_NO_ZERO;
2928
 
                t->num.flag |= NUM_NO_ZERO;
2929
 
        }
2930
 
        
2931
 
        t->idx_max = 2;
2932
 
        t->num.idx_max = 2;
2933
 
        t->snap[0] = 0.0f;
2934
 
        t->snap[1] = 0.1f;
2935
 
        t->snap[2] = t->snap[1] * 0.1f;
2936
 
 
2937
 
        t->num.increment = t->snap[1];
2938
 
}
2939
 
 
2940
 
static void headerResize(TransInfo *t, float vec[3], char *str)
2941
 
{
2942
 
        char tvec[NUM_STR_REP_LEN * 3];
2943
 
        char *spos = str;
2944
 
        if (hasNumInput(&t->num)) {
2945
 
                outputNumInput(&(t->num), tvec);
2946
 
        }
2947
 
        else {
2948
 
                BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
2949
 
                BLI_snprintf(&tvec[NUM_STR_REP_LEN], NUM_STR_REP_LEN, "%.4f", vec[1]);
2950
 
                BLI_snprintf(&tvec[NUM_STR_REP_LEN * 2], NUM_STR_REP_LEN, "%.4f", vec[2]);
2951
 
        }
2952
 
        
2953
 
        if (t->con.mode & CON_APPLY) {
2954
 
                switch (t->num.idx_max) {
2955
 
                        case 0:
2956
 
                                spos += sprintf(spos, IFACE_("Scale: %s%s %s"), &tvec[0], t->con.text, t->proptext);
2957
 
                                break;
2958
 
                        case 1:
2959
 
                                spos += sprintf(spos, IFACE_("Scale: %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
2960
 
                                                t->con.text, t->proptext);
2961
 
                                break;
2962
 
                        case 2:
2963
 
                                spos += sprintf(spos, IFACE_("Scale: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
2964
 
                                                &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
2965
 
                }
2966
 
        }
2967
 
        else {
2968
 
                if (t->flag & T_2D_EDIT) {
2969
 
                        spos += sprintf(spos, IFACE_("Scale X: %s   Y: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
2970
 
                                        t->con.text, t->proptext);
2971
 
                }
2972
 
                else {
2973
 
                        spos += sprintf(spos, IFACE_("Scale X: %s   Y: %s  Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
2974
 
                                        &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
2975
 
                }
2976
 
        }
2977
 
        
2978
 
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
2979
 
                spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
2980
 
        }
2981
 
 
2982
 
        (void)spos;
2983
 
}
2984
 
 
2985
 
/* FLT_EPSILON is too small [#29633], 0.0000001f starts to flip */
2986
 
#define TX_FLIP_EPS 0.00001f
2987
 
BLI_INLINE int tx_sign(const float a)
2988
 
{
2989
 
        return (a < -TX_FLIP_EPS ? 1 : a > TX_FLIP_EPS ? 2 : 3);
2990
 
}
2991
 
BLI_INLINE int tx_vec_sign_flip(const float a[3], const float b[3])
2992
 
{
2993
 
        return ((tx_sign(a[0]) & tx_sign(b[0])) == 0 ||
2994
 
                (tx_sign(a[1]) & tx_sign(b[1])) == 0 ||
2995
 
                (tx_sign(a[2]) & tx_sign(b[2])) == 0);
2996
 
}
2997
 
 
2998
 
/* smat is reference matrix, only scaled */
2999
 
static void TransMat3ToSize(float mat[3][3], float smat[3][3], float size[3])
3000
 
{
3001
 
        float vec[3];
3002
 
        
3003
 
        copy_v3_v3(vec, mat[0]);
3004
 
        size[0] = normalize_v3(vec);
3005
 
        copy_v3_v3(vec, mat[1]);
3006
 
        size[1] = normalize_v3(vec);
3007
 
        copy_v3_v3(vec, mat[2]);
3008
 
        size[2] = normalize_v3(vec);
3009
 
        
3010
 
        /* first tried with dotproduct... but the sign flip is crucial */
3011
 
        if (tx_vec_sign_flip(mat[0], smat[0]) ) size[0] = -size[0];
3012
 
        if (tx_vec_sign_flip(mat[1], smat[1]) ) size[1] = -size[1];
3013
 
        if (tx_vec_sign_flip(mat[2], smat[2]) ) size[2] = -size[2];
3014
 
}
3015
 
 
3016
 
 
3017
 
static void ElementResize(TransInfo *t, TransData *td, float mat[3][3])
3018
 
{
3019
 
        float tmat[3][3], smat[3][3], center[3];
3020
 
        float vec[3];
3021
 
        
3022
 
        if (t->flag & T_EDIT) {
3023
 
                mul_m3_m3m3(smat, mat, td->mtx);
3024
 
                mul_m3_m3m3(tmat, td->smtx, smat);
3025
 
        }
3026
 
        else {
3027
 
                copy_m3_m3(tmat, mat);
3028
 
        }
3029
 
        
3030
 
        if (t->con.applySize) {
3031
 
                t->con.applySize(t, td, tmat);
3032
 
        }
3033
 
        
3034
 
        /* local constraint shouldn't alter center */
3035
 
        if (transdata_check_local_center(t)) {
3036
 
                copy_v3_v3(center, td->center);
3037
 
        }
3038
 
        else if (t->options & CTX_MOVIECLIP) {
3039
 
                copy_v3_v3(center, td->center);
3040
 
        }
3041
 
        else {
3042
 
                copy_v3_v3(center, t->center);
3043
 
        }
3044
 
 
3045
 
        if (td->ext) {
3046
 
                float fsize[3];
3047
 
                
3048
 
                if (t->flag & (T_OBJECT | T_TEXTURE | T_POSE)) {
3049
 
                        float obsizemat[3][3];
3050
 
                        /* Reorient the size mat to fit the oriented object. */
3051
 
                        mul_m3_m3m3(obsizemat, tmat, td->axismtx);
3052
 
                        /* print_m3("obsizemat", obsizemat); */
3053
 
                        TransMat3ToSize(obsizemat, td->axismtx, fsize);
3054
 
                        /* print_v3("fsize", fsize); */
3055
 
                }
3056
 
                else {
3057
 
                        mat3_to_size(fsize, tmat);
3058
 
                }
3059
 
                
3060
 
                protectedSizeBits(td->protectflag, fsize);
3061
 
                
3062
 
                if ((t->flag & T_V3D_ALIGN) == 0) {   /* align mode doesn't resize objects itself */
3063
 
                        if ((td->flag & TD_SINGLESIZE) && !(t->con.mode & CON_APPLY)) {
3064
 
                                /* scale val and reset size */
3065
 
                                *td->val = td->ival * (1 + (fsize[0] - 1) * td->factor);
3066
 
                                
3067
 
                                td->ext->size[0] = td->ext->isize[0];
3068
 
                                td->ext->size[1] = td->ext->isize[1];
3069
 
                                td->ext->size[2] = td->ext->isize[2];
3070
 
                        }
3071
 
                        else {
3072
 
                                /* Reset val if SINGLESIZE but using a constraint */
3073
 
                                if (td->flag & TD_SINGLESIZE)
3074
 
                                        *td->val = td->ival;
3075
 
                                
3076
 
                                td->ext->size[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
3077
 
                                td->ext->size[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
3078
 
                                td->ext->size[2] = td->ext->isize[2] * (1 + (fsize[2] - 1) * td->factor);
3079
 
                        }
3080
 
                }
3081
 
                
3082
 
                constraintSizeLim(t, td);
3083
 
        }
3084
 
 
3085
 
        /* For individual element center, Editmode need to use iloc */
3086
 
        if (t->flag & T_POINTS)
3087
 
                sub_v3_v3v3(vec, td->iloc, center);
3088
 
        else
3089
 
                sub_v3_v3v3(vec, td->center, center);
3090
 
        
3091
 
        mul_m3_v3(tmat, vec);
3092
 
        
3093
 
        add_v3_v3(vec, center);
3094
 
        if (t->flag & T_POINTS)
3095
 
                sub_v3_v3(vec, td->iloc);
3096
 
        else
3097
 
                sub_v3_v3(vec, td->center);
3098
 
        
3099
 
        mul_v3_fl(vec, td->factor);
3100
 
        
3101
 
        if (t->flag & (T_OBJECT | T_POSE)) {
3102
 
                mul_m3_v3(td->smtx, vec);
3103
 
        }
3104
 
        
3105
 
        protectedTransBits(td->protectflag, vec);
3106
 
        add_v3_v3v3(td->loc, td->iloc, vec);
3107
 
        
3108
 
        constraintTransLim(t, td);
3109
 
}
3110
 
 
3111
 
int Resize(TransInfo *t, const int mval[2])
3112
 
{
3113
 
        TransData *td;
3114
 
        float size[3], mat[3][3];
3115
 
        float ratio;
3116
 
        int i;
3117
 
        char str[200];
3118
 
 
3119
 
        /* for manipulator, center handle, the scaling can't be done relative to center */
3120
 
        if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
3121
 
                ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1])) / 100.0f;
3122
 
        }
3123
 
        else {
3124
 
                ratio = t->values[0];
3125
 
        }
3126
 
        
3127
 
        size[0] = size[1] = size[2] = ratio;
3128
 
        
3129
 
        snapGrid(t, size);
3130
 
        
3131
 
        if (hasNumInput(&t->num)) {
3132
 
                applyNumInput(&t->num, size);
3133
 
                constraintNumInput(t, size);
3134
 
        }
3135
 
        
3136
 
        applySnapping(t, size);
3137
 
        
3138
 
        if (t->flag & T_AUTOVALUES) {
3139
 
                copy_v3_v3(size, t->auto_values);
3140
 
        }
3141
 
        
3142
 
        copy_v3_v3(t->values, size);
3143
 
        
3144
 
        size_to_mat3(mat, size);
3145
 
        
3146
 
        if (t->con.applySize) {
3147
 
                t->con.applySize(t, NULL, mat);
3148
 
        }
3149
 
        
3150
 
        copy_m3_m3(t->mat, mat);    // used in manipulator
3151
 
        
3152
 
        headerResize(t, size, str);
3153
 
        
3154
 
        for (i = 0, td = t->data; i < t->total; i++, td++) {
3155
 
                if (td->flag & TD_NOACTION)
3156
 
                        break;
3157
 
                
3158
 
                if (td->flag & TD_SKIP)
3159
 
                        continue;
3160
 
                
3161
 
                ElementResize(t, td, mat);
3162
 
        }
3163
 
        
3164
 
        /* evil hack - redo resize if cliping needed */
3165
 
        if (t->flag & T_CLIP_UV && clipUVTransform(t, size, 1)) {
3166
 
                size_to_mat3(mat, size);
3167
 
                
3168
 
                if (t->con.applySize)
3169
 
                        t->con.applySize(t, NULL, mat);
3170
 
                
3171
 
                for (i = 0, td = t->data; i < t->total; i++, td++)
3172
 
                        ElementResize(t, td, mat);
3173
 
 
3174
 
                /* In proportional edit it can happen that */
3175
 
                /* vertices in the radius of the brush end */
3176
 
                /* outside the clipping area               */
3177
 
                /* XXX HACK - dg */
3178
 
                if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
3179
 
                        clipUVData(t);
3180
 
                }
3181
 
        }
3182
 
        
3183
 
        recalcData(t);
3184
 
        
3185
 
        ED_area_headerprint(t->sa, str);
3186
 
        
3187
 
        return 1;
3188
 
}
3189
 
 
3190
 
/* ************************** SKIN *************************** */
3191
 
 
3192
 
void initSkinResize(TransInfo *t)
3193
 
{
3194
 
        t->mode = TFM_SKIN_RESIZE;
3195
 
        t->transform = SkinResize;
3196
 
        
3197
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
3198
 
        
3199
 
        t->flag |= T_NULL_ONE;
3200
 
        t->num.flag |= NUM_NULL_ONE;
3201
 
        t->num.flag |= NUM_AFFECT_ALL;
3202
 
        if (!t->obedit) {
3203
 
                t->flag |= T_NO_ZERO;
3204
 
                t->num.flag |= NUM_NO_ZERO;
3205
 
        }
3206
 
        
3207
 
        t->idx_max = 2;
3208
 
        t->num.idx_max = 2;
3209
 
        t->snap[0] = 0.0f;
3210
 
        t->snap[1] = 0.1f;
3211
 
        t->snap[2] = t->snap[1] * 0.1f;
3212
 
 
3213
 
        t->num.increment = t->snap[1];
3214
 
}
3215
 
 
3216
 
int SkinResize(TransInfo *t, const int UNUSED(mval[2]))
3217
 
{
3218
 
        TransData *td;
3219
 
        float size[3], mat[3][3];
3220
 
        float ratio;
3221
 
        int i;
3222
 
        char str[200];
3223
 
        
3224
 
        ratio = t->values[0];
3225
 
        size[0] = size[1] = size[2] = ratio;
3226
 
        
3227
 
        snapGrid(t, size);
3228
 
        
3229
 
        if (hasNumInput(&t->num)) {
3230
 
                applyNumInput(&t->num, size);
3231
 
                constraintNumInput(t, size);
3232
 
        }
3233
 
        
3234
 
        applySnapping(t, size);
3235
 
        
3236
 
        if (t->flag & T_AUTOVALUES) {
3237
 
                copy_v3_v3(size, t->auto_values);
3238
 
        }
3239
 
        
3240
 
        copy_v3_v3(t->values, size);
3241
 
        
3242
 
        size_to_mat3(mat, size);
3243
 
        
3244
 
        headerResize(t, size, str);
3245
 
        
3246
 
        for (i = 0, td = t->data; i < t->total; i++, td++) {
3247
 
                float tmat[3][3], smat[3][3];
3248
 
                float fsize[3];
3249
 
                
3250
 
                if (td->flag & TD_NOACTION)
3251
 
                        break;
3252
 
                
3253
 
                if (td->flag & TD_SKIP)
3254
 
                        continue;
3255
 
 
3256
 
                if (t->flag & T_EDIT) {
3257
 
                        mul_m3_m3m3(smat, mat, td->mtx);
3258
 
                        mul_m3_m3m3(tmat, td->smtx, smat);
3259
 
                }
3260
 
                else {
3261
 
                        copy_m3_m3(tmat, mat);
3262
 
                }
3263
 
        
3264
 
                if (t->con.applySize) {
3265
 
                        t->con.applySize(t, NULL, tmat);
3266
 
                }
3267
 
 
3268
 
                mat3_to_size(fsize, tmat);
3269
 
                td->val[0] = td->ext->isize[0] * (1 + (fsize[0] - 1) * td->factor);
3270
 
                td->val[1] = td->ext->isize[1] * (1 + (fsize[1] - 1) * td->factor);
3271
 
        }
3272
 
        
3273
 
        recalcData(t);
3274
 
        
3275
 
        ED_area_headerprint(t->sa, str);
3276
 
        
3277
 
        return 1;
3278
 
}
3279
 
 
3280
 
/* ************************** TOSPHERE *************************** */
3281
 
 
3282
 
void initToSphere(TransInfo *t)
3283
 
{
3284
 
        TransData *td = t->data;
3285
 
        int i;
3286
 
        
3287
 
        t->mode = TFM_TOSPHERE;
3288
 
        t->transform = ToSphere;
3289
 
        
3290
 
        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_RATIO);
3291
 
        
3292
 
        t->idx_max = 0;
3293
 
        t->num.idx_max = 0;
3294
 
        t->snap[0] = 0.0f;
3295
 
        t->snap[1] = 0.1f;
3296
 
        t->snap[2] = t->snap[1] * 0.1f;
3297
 
        
3298
 
        t->num.increment = t->snap[1];
3299
 
 
3300
 
        t->num.flag |= NUM_NULL_ONE | NUM_NO_NEGATIVE;
3301
 
        t->flag |= T_NO_CONSTRAINT;
3302
 
        
3303
 
        // Calculate average radius
3304
 
        for (i = 0; i < t->total; i++, td++) {
3305
 
                t->val += len_v3v3(t->center, td->iloc);
3306
 
        }
3307
 
        
3308
 
        t->val /= (float)t->total;
3309
 
}
3310
 
 
3311
 
int ToSphere(TransInfo *t, const int UNUSED(mval[2]))
3312
 
{
3313
 
        float vec[3];
3314
 
        float ratio, radius;
3315
 
        int i;
3316
 
        char str[64];
3317
 
        TransData *td = t->data;
3318
 
        
3319
 
        ratio = t->values[0];
3320
 
        
3321
 
        snapGrid(t, &ratio);
3322
 
        
3323
 
        applyNumInput(&t->num, &ratio);
3324
 
        
3325
 
        if (ratio < 0)
3326
 
                ratio = 0.0f;
3327
 
        else if (ratio > 1)
3328
 
                ratio = 1.0f;
3329
 
        
3330
 
        t->values[0] = ratio;
3331
 
 
3332
 
        /* header print for NumInput */
3333
 
        if (hasNumInput(&t->num)) {
3334
 
                char c[NUM_STR_REP_LEN];
3335
 
                
3336
 
                outputNumInput(&(t->num), c);
3337
 
                
3338
 
                sprintf(str, IFACE_("To Sphere: %s %s"), c, t->proptext);
3339
 
        }
3340
 
        else {
3341
 
                /* default header print */
3342
 
                sprintf(str, IFACE_("To Sphere: %.4f %s"), ratio, t->proptext);
3343
 
        }
3344
 
        
3345
 
        
3346
 
        for (i = 0; i < t->total; i++, td++) {
3347
 
                float tratio;
3348
 
                if (td->flag & TD_NOACTION)
3349
 
                        break;
3350
 
                
3351
 
                if (td->flag & TD_SKIP)
3352
 
                        continue;
3353
 
                
3354
 
                sub_v3_v3v3(vec, td->iloc, t->center);
3355
 
                
3356
 
                radius = normalize_v3(vec);
3357
 
                
3358
 
                tratio = ratio * td->factor;
3359
 
                
3360
 
                mul_v3_fl(vec, radius * (1.0f - tratio) + t->val * tratio);
3361
 
                
3362
 
                add_v3_v3v3(td->loc, t->center, vec);
3363
 
        }
3364
 
        
3365
 
        
3366
 
        recalcData(t);
3367
 
        
3368
 
        ED_area_headerprint(t->sa, str);
3369
 
        
3370
 
        return 1;
3371
 
}
3372
 
 
3373
 
/* ************************** ROTATION *************************** */
3374
 
 
3375
 
 
3376
 
static void postInputRotation(TransInfo *t, float values[3])
3377
 
{
3378
 
        if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
3379
 
                t->con.applyRot(t, NULL, t->axis, values);
3380
 
        }
3381
 
}
3382
 
 
3383
 
void initRotation(TransInfo *t)
3384
 
{
3385
 
        t->mode = TFM_ROTATION;
3386
 
        t->transform = Rotation;
3387
 
        
3388
 
        setInputPostFct(&t->mouse, postInputRotation);
3389
 
        initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
3390
 
        
3391
 
        t->idx_max = 0;
3392
 
        t->num.idx_max = 0;
3393
 
        t->snap[0] = 0.0f;
3394
 
        t->snap[1] = (float)((5.0 / 180) * M_PI);
3395
 
        t->snap[2] = t->snap[1] * 0.2f;
3396
 
        
3397
 
        t->num.increment = 1.0f;
3398
 
 
3399
 
        if (t->flag & T_2D_EDIT)
3400
 
                t->flag |= T_NO_CONSTRAINT;
3401
 
 
3402
 
        negate_v3_v3(t->axis, t->viewinv[2]);
3403
 
        normalize_v3(t->axis);
3404
 
 
3405
 
        copy_v3_v3(t->axis_orig, t->axis);
3406
 
}
3407
 
 
3408
 
static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around)
3409
 
{
3410
 
        float vec[3], totmat[3][3], smat[3][3];
3411
 
        float eul[3], fmat[3][3], quat[4];
3412
 
        const float *center;
3413
 
 
3414
 
        /* local constraint shouldn't alter center */
3415
 
        if (transdata_check_local_center(t) ||
3416
 
            ((around == V3D_LOCAL) && (t->options & CTX_MOVIECLIP)))
3417
 
        {
3418
 
                center = td->center;
3419
 
        }
3420
 
        else {
3421
 
                center = t->center;
3422
 
        }
3423
 
 
3424
 
        if (t->flag & T_POINTS) {
3425
 
                mul_m3_m3m3(totmat, mat, td->mtx);
3426
 
                mul_m3_m3m3(smat, td->smtx, totmat);
3427
 
                
3428
 
                sub_v3_v3v3(vec, td->iloc, center);
3429
 
                mul_m3_v3(smat, vec);
3430
 
                
3431
 
                add_v3_v3v3(td->loc, vec, center);
3432
 
                
3433
 
                sub_v3_v3v3(vec, td->loc, td->iloc);
3434
 
                protectedTransBits(td->protectflag, vec);
3435
 
                add_v3_v3v3(td->loc, td->iloc, vec);
3436
 
                
3437
 
                
3438
 
                if (td->flag & TD_USEQUAT) {
3439
 
                        mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
3440
 
                        mat3_to_quat(quat, fmat);   // Actual transform
3441
 
                        
3442
 
                        if (td->ext->quat) {
3443
 
                                mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
3444
 
                                
3445
 
                                /* is there a reason not to have this here? -jahka */
3446
 
                                protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
3447
 
                        }
3448
 
                }
3449
 
        }
3450
 
        /**
3451
 
         * HACK WARNING
3452
 
         *
3453
 
         * This is some VERY ugly special case to deal with pose mode.
3454
 
         *
3455
 
         * The problem is that mtx and smtx include each bone orientation.
3456
 
         *
3457
 
         * That is needed to rotate each bone properly, HOWEVER, to calculate
3458
 
         * the translation component, we only need the actual armature object's
3459
 
         * matrix (and inverse). That is not all though. Once the proper translation
3460
 
         * has been computed, it has to be converted back into the bone's space.
3461
 
         */
3462
 
        else if (t->flag & T_POSE) {
3463
 
                float pmtx[3][3], imtx[3][3];
3464
 
                
3465
 
                // Extract and invert armature object matrix
3466
 
                copy_m3_m4(pmtx, t->poseobj->obmat);
3467
 
                invert_m3_m3(imtx, pmtx);
3468
 
                
3469
 
                if ((td->flag & TD_NO_LOC) == 0) {
3470
 
                        sub_v3_v3v3(vec, td->center, center);
3471
 
                        
3472
 
                        mul_m3_v3(pmtx, vec);   // To Global space
3473
 
                        mul_m3_v3(mat, vec);        // Applying rotation
3474
 
                        mul_m3_v3(imtx, vec);   // To Local space
3475
 
                        
3476
 
                        add_v3_v3(vec, center);
3477
 
                        /* vec now is the location where the object has to be */
3478
 
                        
3479
 
                        sub_v3_v3v3(vec, vec, td->center); // Translation needed from the initial location
3480
 
                        
3481
 
                        /* special exception, see TD_PBONE_LOCAL_MTX definition comments */
3482
 
                        if (td->flag & TD_PBONE_LOCAL_MTX_P) {
3483
 
                                /* do nothing */
3484
 
                        }
3485
 
                        else if (td->flag & TD_PBONE_LOCAL_MTX_C) {
3486
 
                                mul_m3_v3(pmtx, vec);   // To Global space
3487
 
                                mul_m3_v3(td->ext->l_smtx, vec); // To Pose space (Local Location)
3488
 
                        }
3489
 
                        else {
3490
 
                                mul_m3_v3(pmtx, vec);   // To Global space
3491
 
                                mul_m3_v3(td->smtx, vec); // To Pose space
3492
 
                        }
3493
 
 
3494
 
                        protectedTransBits(td->protectflag, vec);
3495
 
                        
3496
 
                        add_v3_v3v3(td->loc, td->iloc, vec);
3497
 
                        
3498
 
                        constraintTransLim(t, td);
3499
 
                }
3500
 
                
3501
 
                /* rotation */
3502
 
                /* MORE HACK: as in some cases the matrix to apply location and rot/scale is not the same,
3503
 
                 * and ElementRotation() might be called in Translation context (with align snapping),
3504
 
                 * we need to be sure to actually use the *rotation* matrix here...
3505
 
                 * So no other way than storing it in some dedicated members of td->ext! */
3506
 
                if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */
3507
 
                        /* euler or quaternion/axis-angle? */
3508
 
                        if (td->ext->rotOrder == ROT_MODE_QUAT) {
3509
 
                                mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
3510
 
                                
3511
 
                                mat3_to_quat(quat, fmat); /* Actual transform */
3512
 
                                
3513
 
                                mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
3514
 
                                /* this function works on end result */
3515
 
                                protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
3516
 
                                
3517
 
                        }
3518
 
                        else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
3519
 
                                /* calculate effect based on quats */
3520
 
                                float iquat[4], tquat[4];
3521
 
                                
3522
 
                                axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
3523
 
                                
3524
 
                                mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
3525
 
                                mat3_to_quat(quat, fmat); /* Actual transform */
3526
 
                                mul_qt_qtqt(tquat, quat, iquat);
3527
 
                                
3528
 
                                quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
3529
 
                                
3530
 
                                /* this function works on end result */
3531
 
                                protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
3532
 
                        }
3533
 
                        else {
3534
 
                                float eulmat[3][3];
3535
 
                                
3536
 
                                mul_m3_m3m3(totmat, mat, td->ext->r_mtx);
3537
 
                                mul_m3_m3m3(smat, td->ext->r_smtx, totmat);
3538
 
                                
3539
 
                                /* calculate the total rotatation in eulers */
3540
 
                                copy_v3_v3(eul, td->ext->irot);
3541
 
                                eulO_to_mat3(eulmat, eul, td->ext->rotOrder);
3542
 
                                
3543
 
                                /* mat = transform, obmat = bone rotation */
3544
 
                                mul_m3_m3m3(fmat, smat, eulmat);
3545
 
                                
3546
 
                                mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
3547
 
                                
3548
 
                                /* and apply (to end result only) */
3549
 
                                protectedRotateBits(td->protectflag, eul, td->ext->irot);
3550
 
                                copy_v3_v3(td->ext->rot, eul);
3551
 
                        }
3552
 
                        
3553
 
                        constraintRotLim(t, td);
3554
 
                }
3555
 
        }
3556
 
        else {
3557
 
                if ((td->flag & TD_NO_LOC) == 0) {
3558
 
                        /* translation */
3559
 
                        sub_v3_v3v3(vec, td->center, center);
3560
 
                        mul_m3_v3(mat, vec);
3561
 
                        add_v3_v3(vec, center);
3562
 
                        /* vec now is the location where the object has to be */
3563
 
                        sub_v3_v3(vec, td->center);
3564
 
                        mul_m3_v3(td->smtx, vec);
3565
 
                        
3566
 
                        protectedTransBits(td->protectflag, vec);
3567
 
                        
3568
 
                        add_v3_v3v3(td->loc, td->iloc, vec);
3569
 
                }
3570
 
                
3571
 
                
3572
 
                constraintTransLim(t, td);
3573
 
                
3574
 
                /* rotation */
3575
 
                if ((t->flag & T_V3D_ALIGN) == 0) { // align mode doesn't rotate objects itself
3576
 
                        /* euler or quaternion? */
3577
 
                        if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
3578
 
                                mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
3579
 
                                mat3_to_quat(quat, fmat);   // Actual transform
3580
 
                                
3581
 
                                mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
3582
 
                                /* this function works on end result */
3583
 
                                protectedQuaternionBits(td->protectflag, td->ext->quat, td->ext->iquat);
3584
 
                        }
3585
 
                        else if (td->ext->rotOrder == ROT_MODE_AXISANGLE) {
3586
 
                                /* calculate effect based on quats */
3587
 
                                float iquat[4], tquat[4];
3588
 
                                
3589
 
                                axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
3590
 
                                
3591
 
                                mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
3592
 
                                mat3_to_quat(quat, fmat);   // Actual transform
3593
 
                                mul_qt_qtqt(tquat, quat, iquat);
3594
 
                                
3595
 
                                quat_to_axis_angle(td->ext->rotAxis, td->ext->rotAngle, tquat);
3596
 
                                
3597
 
                                /* this function works on end result */
3598
 
                                protectedAxisAngleBits(td->protectflag, td->ext->rotAxis, td->ext->rotAngle, td->ext->irotAxis, td->ext->irotAngle);
3599
 
                        }
3600
 
                        else {
3601
 
                                float obmat[3][3];
3602
 
                                
3603
 
                                mul_m3_m3m3(totmat, mat, td->mtx);
3604
 
                                mul_m3_m3m3(smat, td->smtx, totmat);
3605
 
                                
3606
 
                                /* calculate the total rotatation in eulers */
3607
 
                                add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
3608
 
                                eulO_to_mat3(obmat, eul, td->ext->rotOrder);
3609
 
                                /* mat = transform, obmat = object rotation */
3610
 
                                mul_m3_m3m3(fmat, smat, obmat);
3611
 
                                
3612
 
                                mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
3613
 
                                
3614
 
                                /* correct back for delta rot */
3615
 
                                sub_v3_v3v3(eul, eul, td->ext->drot);
3616
 
                                
3617
 
                                /* and apply */
3618
 
                                protectedRotateBits(td->protectflag, eul, td->ext->irot);
3619
 
                                copy_v3_v3(td->ext->rot, eul);
3620
 
                        }
3621
 
                        
3622
 
                        constraintRotLim(t, td);
3623
 
                }
3624
 
        }
3625
 
}
3626
 
 
3627
 
static void applyRotation(TransInfo *t, float angle, float axis[3])
3628
 
{
3629
 
        TransData *td = t->data;
3630
 
        float mat[3][3];
3631
 
        int i;
3632
 
        
3633
 
        vec_rot_to_mat3(mat, axis, angle);
3634
 
        
3635
 
        for (i = 0; i < t->total; i++, td++) {
3636
 
                
3637
 
                if (td->flag & TD_NOACTION)
3638
 
                        break;
3639
 
                
3640
 
                if (td->flag & TD_SKIP)
3641
 
                        continue;
3642
 
                
3643
 
                if (t->con.applyRot) {
3644
 
                        t->con.applyRot(t, td, axis, NULL);
3645
 
                        vec_rot_to_mat3(mat, axis, angle * td->factor);
3646
 
                }
3647
 
                else if (t->flag & T_PROP_EDIT) {
3648
 
                        vec_rot_to_mat3(mat, axis, angle * td->factor);
3649
 
                }
3650
 
                
3651
 
                ElementRotation(t, td, mat, t->around);
3652
 
        }
3653
 
}
3654
 
 
3655
 
int Rotation(TransInfo *t, const int UNUSED(mval[2]))
3656
 
{
3657
 
        char str[128], *spos = str;
3658
 
        
3659
 
        float final;
3660
 
 
3661
 
        final = t->values[0];
3662
 
        
3663
 
        snapGrid(t, &final);
3664
 
        
3665
 
        if ((t->con.mode & CON_APPLY) && t->con.applyRot) {
3666
 
                t->con.applyRot(t, NULL, t->axis, NULL);
3667
 
        }
3668
 
        else {
3669
 
                /* reset axis if constraint is not set */
3670
 
                copy_v3_v3(t->axis, t->axis_orig);
3671
 
        }
3672
 
        
3673
 
        applySnapping(t, &final);
3674
 
        
3675
 
        if (hasNumInput(&t->num)) {
3676
 
                char c[NUM_STR_REP_LEN];
3677
 
                
3678
 
                applyNumInput(&t->num, &final);
3679
 
                
3680
 
                outputNumInput(&(t->num), c);
3681
 
                
3682
 
                spos += sprintf(spos, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
3683
 
 
3684
 
                /* Clamp between -180 and 180 */
3685
 
                final = angle_wrap_rad(DEG2RADF(final));
3686
 
        }
3687
 
        else {
3688
 
                spos += sprintf(spos, IFACE_("Rot: %.2f%s %s"), RAD2DEGF(final), t->con.text, t->proptext);
3689
 
        }
3690
 
        
3691
 
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
3692
 
                spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
3693
 
        }
3694
 
        (void)spos;
3695
 
 
3696
 
        t->values[0] = final;
3697
 
        
3698
 
        applyRotation(t, final, t->axis);
3699
 
        
3700
 
        recalcData(t);
3701
 
        
3702
 
        ED_area_headerprint(t->sa, str);
3703
 
        
3704
 
        return 1;
3705
 
}
3706
 
 
3707
 
 
3708
 
/* ************************** TRACKBALL *************************** */
3709
 
 
3710
 
void initTrackball(TransInfo *t)
3711
 
{
3712
 
        t->mode = TFM_TRACKBALL;
3713
 
        t->transform = Trackball;
3714
 
 
3715
 
        initMouseInputMode(t, &t->mouse, INPUT_TRACKBALL);
3716
 
 
3717
 
        t->idx_max = 1;
3718
 
        t->num.idx_max = 1;
3719
 
        t->snap[0] = 0.0f;
3720
 
        t->snap[1] = (float)((5.0 / 180) * M_PI);
3721
 
        t->snap[2] = t->snap[1] * 0.2f;
3722
 
 
3723
 
        t->num.increment = 1.0f;
3724
 
 
3725
 
        t->flag |= T_NO_CONSTRAINT;
3726
 
}
3727
 
 
3728
 
static void applyTrackball(TransInfo *t, float axis1[3], float axis2[3], float angles[2])
3729
 
{
3730
 
        TransData *td = t->data;
3731
 
        float mat[3][3], smat[3][3], totmat[3][3];
3732
 
        int i;
3733
 
 
3734
 
        vec_rot_to_mat3(smat, axis1, angles[0]);
3735
 
        vec_rot_to_mat3(totmat, axis2, angles[1]);
3736
 
 
3737
 
        mul_m3_m3m3(mat, smat, totmat);
3738
 
 
3739
 
        for (i = 0; i < t->total; i++, td++) {
3740
 
                if (td->flag & TD_NOACTION)
3741
 
                        break;
3742
 
 
3743
 
                if (td->flag & TD_SKIP)
3744
 
                        continue;
3745
 
 
3746
 
                if (t->flag & T_PROP_EDIT) {
3747
 
                        vec_rot_to_mat3(smat, axis1, td->factor * angles[0]);
3748
 
                        vec_rot_to_mat3(totmat, axis2, td->factor * angles[1]);
3749
 
 
3750
 
                        mul_m3_m3m3(mat, smat, totmat);
3751
 
                }
3752
 
 
3753
 
                ElementRotation(t, td, mat, t->around);
3754
 
        }
3755
 
}
3756
 
 
3757
 
int Trackball(TransInfo *t, const int UNUSED(mval[2]))
3758
 
{
3759
 
        char str[128], *spos = str;
3760
 
        float axis1[3], axis2[3];
3761
 
        float mat[3][3], totmat[3][3], smat[3][3];
3762
 
        float phi[2];
3763
 
 
3764
 
        copy_v3_v3(axis1, t->persinv[0]);
3765
 
        copy_v3_v3(axis2, t->persinv[1]);
3766
 
        normalize_v3(axis1);
3767
 
        normalize_v3(axis2);
3768
 
 
3769
 
        phi[0] = t->values[0];
3770
 
        phi[1] = t->values[1];
3771
 
 
3772
 
        snapGrid(t, phi);
3773
 
 
3774
 
        if (hasNumInput(&t->num)) {
3775
 
                char c[NUM_STR_REP_LEN * 2];
3776
 
 
3777
 
                applyNumInput(&t->num, phi);
3778
 
 
3779
 
                outputNumInput(&(t->num), c);
3780
 
 
3781
 
                spos += sprintf(spos, IFACE_("Trackball: %s %s %s"), &c[0], &c[NUM_STR_REP_LEN], t->proptext);
3782
 
 
3783
 
                phi[0] = DEG2RADF(phi[0]);
3784
 
                phi[1] = DEG2RADF(phi[1]);
3785
 
        }
3786
 
        else {
3787
 
                spos += sprintf(spos, IFACE_("Trackball: %.2f %.2f %s"), RAD2DEGF(phi[0]), RAD2DEGF(phi[1]), t->proptext);
3788
 
        }
3789
 
 
3790
 
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
3791
 
                spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
3792
 
        }
3793
 
        (void)spos;
3794
 
 
3795
 
        vec_rot_to_mat3(smat, axis1, phi[0]);
3796
 
        vec_rot_to_mat3(totmat, axis2, phi[1]);
3797
 
 
3798
 
        mul_m3_m3m3(mat, smat, totmat);
3799
 
 
3800
 
        // TRANSFORM_FIX_ME
3801
 
        //copy_m3_m3(t->mat, mat);      // used in manipulator
3802
 
 
3803
 
        applyTrackball(t, axis1, axis2, phi);
3804
 
 
3805
 
        recalcData(t);
3806
 
 
3807
 
        ED_area_headerprint(t->sa, str);
3808
 
 
3809
 
        return 1;
3810
 
}
3811
 
 
3812
 
/* ************************** TRANSLATION *************************** */
3813
 
 
3814
 
void initTranslation(TransInfo *t)
3815
 
{
3816
 
        if (t->spacetype == SPACE_ACTION) {
3817
 
                /* this space uses time translate */
3818
 
                t->state = TRANS_CANCEL;
3819
 
        }
3820
 
 
3821
 
        t->mode = TFM_TRANSLATION;
3822
 
        t->transform = Translation;
3823
 
 
3824
 
        initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
3825
 
 
3826
 
        t->idx_max = (t->flag & T_2D_EDIT) ? 1 : 2;
3827
 
        t->num.flag = 0;
3828
 
        t->num.idx_max = t->idx_max;
3829
 
 
3830
 
        if (t->spacetype == SPACE_VIEW3D) {
3831
 
                RegionView3D *rv3d = t->ar->regiondata;
3832
 
 
3833
 
                if (rv3d) {
3834
 
                        t->snap[0] = 0.0f;
3835
 
                        t->snap[1] = rv3d->gridview * 1.0f;
3836
 
                        t->snap[2] = t->snap[1] * 0.1f;
3837
 
                }
3838
 
        }
3839
 
        else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP)) {
3840
 
                t->snap[0] = 0.0f;
3841
 
                t->snap[1] = 0.125f;
3842
 
                t->snap[2] = 0.0625f;
3843
 
        }
3844
 
        else if (t->spacetype == SPACE_NODE) {
3845
 
                t->snap[0] = 0.0f;
3846
 
                t->snap[1] = 125.0f;
3847
 
                t->snap[2] = 25.0f;
3848
 
        }
3849
 
        else {
3850
 
                t->snap[0] = 0.0f;
3851
 
                t->snap[1] = t->snap[2] = 1.0f;
3852
 
        }
3853
 
 
3854
 
        t->num.increment = t->snap[1];
3855
 
}
3856
 
 
3857
 
static void headerTranslation(TransInfo *t, float vec[3], char *str)
3858
 
{
3859
 
        char *spos = str;
3860
 
        char tvec[NUM_STR_REP_LEN * 3];
3861
 
        char distvec[NUM_STR_REP_LEN];
3862
 
        char autoik[NUM_STR_REP_LEN];
3863
 
        float dist;
3864
 
 
3865
 
        if (hasNumInput(&t->num)) {
3866
 
                outputNumInput(&(t->num), tvec);
3867
 
                dist = len_v3(t->num.val);
3868
 
        }
3869
 
        else {
3870
 
                float dvec[3];
3871
 
 
3872
 
                copy_v3_v3(dvec, vec);
3873
 
                applyAspectRatio(t, dvec);
3874
 
 
3875
 
                dist = len_v3(vec);
3876
 
                if (!(t->flag & T_2D_EDIT) && t->scene->unit.system) {
3877
 
                        int i, do_split = t->scene->unit.flag & USER_UNIT_OPT_SPLIT ? 1 : 0;
3878
 
 
3879
 
                        for (i = 0; i < 3; i++) {
3880
 
                                bUnit_AsString(&tvec[i * NUM_STR_REP_LEN], NUM_STR_REP_LEN, dvec[i] * t->scene->unit.scale_length,
3881
 
                                               4, t->scene->unit.system, B_UNIT_LENGTH, do_split, 1);
3882
 
                        }
3883
 
                }
3884
 
                else {
3885
 
                        sprintf(&tvec[0], "%.4f", dvec[0]);
3886
 
                        sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", dvec[1]);
3887
 
                        sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", dvec[2]);
3888
 
                }
3889
 
        }
3890
 
 
3891
 
        if (!(t->flag & T_2D_EDIT) && t->scene->unit.system)
3892
 
                bUnit_AsString(distvec, sizeof(distvec), dist * t->scene->unit.scale_length, 4, t->scene->unit.system, B_UNIT_LENGTH, t->scene->unit.flag & USER_UNIT_OPT_SPLIT, 0);
3893
 
        else if (dist > 1e10f || dist < -1e10f)     /* prevent string buffer overflow */
3894
 
                sprintf(distvec, "%.4e", dist);
3895
 
        else
3896
 
                sprintf(distvec, "%.4f", dist);
3897
 
 
3898
 
        if (t->flag & T_AUTOIK) {
3899
 
                short chainlen = t->settings->autoik_chainlen;
3900
 
 
3901
 
                if (chainlen)
3902
 
                        sprintf(autoik, IFACE_("AutoIK-Len: %d"), chainlen);
3903
 
                else
3904
 
                        autoik[0] = '\0';
3905
 
        }
3906
 
        else
3907
 
                autoik[0] = '\0';
3908
 
 
3909
 
        if (t->con.mode & CON_APPLY) {
3910
 
                switch (t->num.idx_max) {
3911
 
                        case 0:
3912
 
                                spos += sprintf(spos, "D: %s (%s)%s %s  %s", &tvec[0], distvec, t->con.text, t->proptext, &autoik[0]);
3913
 
                                break;
3914
 
                        case 1:
3915
 
                                spos += sprintf(spos, "D: %s   D: %s (%s)%s %s  %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
3916
 
                                                distvec, t->con.text, t->proptext, &autoik[0]);
3917
 
                                break;
3918
 
                        case 2:
3919
 
                                spos += sprintf(spos, "D: %s   D: %s  D: %s (%s)%s %s  %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
3920
 
                                                &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]);
3921
 
                }
3922
 
        }
3923
 
        else {
3924
 
                if (t->flag & T_2D_EDIT) {
3925
 
                        spos += sprintf(spos, "Dx: %s   Dy: %s (%s)%s %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
3926
 
                                        distvec, t->con.text, t->proptext);
3927
 
                }
3928
 
                else {
3929
 
                        spos += sprintf(spos, "Dx: %s   Dy: %s  Dz: %s (%s)%s %s  %s", &tvec[0], &tvec[NUM_STR_REP_LEN],
3930
 
                                        &tvec[NUM_STR_REP_LEN * 2], distvec, t->con.text, t->proptext, &autoik[0]);
3931
 
                }
3932
 
        }
3933
 
        
3934
 
        if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
3935
 
                spos += sprintf(spos, IFACE_(" Proportional size: %.2f"), t->prop_size);
3936
 
        }
3937
 
        (void)spos;
3938
 
}
3939
 
 
3940
 
static void applyTranslation(TransInfo *t, float vec[3])
3941
 
{
3942
 
        TransData *td = t->data;
3943
 
        float tvec[3];
3944
 
        int i;
3945
 
 
3946
 
        for (i = 0; i < t->total; i++, td++) {
3947
 
                if (td->flag & TD_NOACTION)
3948
 
                        break;
3949
 
                
3950
 
                if (td->flag & TD_SKIP)
3951
 
                        continue;
3952
 
                
3953
 
                /* handle snapping rotation before doing the translation */
3954
 
                if (usingSnappingNormal(t)) {
3955
 
                        if (validSnappingNormal(t)) {
3956
 
                                float *original_normal;
3957
 
                                float axis[3];
3958
 
                                float quat[4];
3959
 
                                float mat[3][3];
3960
 
                                float angle;
3961
 
                                
3962
 
                                /* In pose mode, we want to align normals with Y axis of bones... */
3963
 
                                if (t->flag & T_POSE)
3964
 
                                        original_normal = td->axismtx[1];
3965
 
                                else
3966
 
                                        original_normal = td->axismtx[2];
3967
 
                                
3968
 
                                cross_v3_v3v3(axis, original_normal, t->tsnap.snapNormal);
3969
 
                                angle = saacos(dot_v3v3(original_normal, t->tsnap.snapNormal));
3970
 
                                
3971
 
                                axis_angle_to_quat(quat, axis, angle);
3972
 
                                
3973
 
                                quat_to_mat3(mat, quat);
3974
 
                                
3975
 
                                ElementRotation(t, td, mat, V3D_LOCAL);
3976
 
                        }
3977
 
                        else {
3978
 
                                float mat[3][3];
3979
 
                                
3980
 
                                unit_m3(mat);
3981
 
                                
3982
 
                                ElementRotation(t, td, mat, V3D_LOCAL);
3983
 
                        }
3984
 
                }
3985
 
                
3986
 
                if (t->con.applyVec) {
3987
 
                        float pvec[3];
3988
 
                        t->con.applyVec(t, td, vec, tvec, pvec);
3989
 
                }
3990
 
                else {
3991
 
                        copy_v3_v3(tvec, vec);
3992
 
                }
3993
 
                
3994
 
                mul_m3_v3(td->smtx, tvec);
3995
 
                mul_v3_fl(tvec, td->factor);
3996
 
                
3997
 
                protectedTransBits(td->protectflag, tvec);
3998
 
                
3999
 
                if (td->loc)
4000
 
                        add_v3_v3v3(td->loc, td->iloc, tvec);
4001
 
                
4002
 
                constraintTransLim(t, td);
4003
 
        }
4004
 
}
4005
 
 
4006
 
/* uses t->vec to store actual translation in */
4007
 
int Translation(TransInfo *t, const int UNUSED(mval[2]))
4008
 
{
4009
 
        char str[250];
4010
 
 
4011
 
        if (t->con.mode & CON_APPLY) {
4012
 
                float pvec[3] = {0.0f, 0.0f, 0.0f};
4013
 
                float tvec[3];
4014
 
                if (hasNumInput(&t->num)) {
4015
 
                        removeAspectRatio(t, t->values);
4016
 
                }
4017
 
                applySnapping(t, t->values);
4018
 
                t->con.applyVec(t, NULL, t->values, tvec, pvec);
4019
 
                copy_v3_v3(t->values, tvec);
4020
 
                headerTranslation(t, pvec, str);
4021
 
        }
4022
 
        else {
4023
 
                snapGrid(t, t->values);
4024
 
                applyNumInput(&t->num, t->values);
4025
 
                if (hasNumInput(&t->num)) {
4026
 
                        removeAspectRatio(t, t->values);
4027
 
                }
4028
 
                applySnapping(t, t->values);
4029
 
                headerTranslation(t, t->values, str);
4030
 
        }
4031
 
 
4032
 
        applyTranslation(t, t->values);
4033
 
 
4034
 
        /* evil hack - redo translation if clipping needed */
4035
 
        if (t->flag & T_CLIP_UV && clipUVTransform(t, t->values, 0)) {
4036
 
                applyTranslation(t, t->values);
4037
 
 
4038
 
                /* In proportional edit it can happen that */
4039
 
                /* vertices in the radius of the brush end */
4040
 
                /* outside the clipping area               */
4041
 
                /* XXX HACK - dg */
4042
 
                if (t->flag & (T_PROP_EDIT | T_PROP_CONNECTED)) {
4043
 
                        clipUVData(t);
4044
 
                }
4045
 
        }
4046
 
 
4047
 
        recalcData(t);
4048
 
 
4049
 
        ED_area_headerprint(t->sa, str);
4050
 
 
4051
 
        return 1;
4052
 
}
4053
 
 
4054
 
/* ************************** SHRINK/FATTEN *************************** */
4055
 
 
4056
 
void initShrinkFatten(TransInfo *t)
4057
 
{
4058
 
        // If not in mesh edit mode, fallback to Resize
4059
 
        if (t->obedit == NULL || t->obedit->type != OB_MESH) {
4060
 
                initResize(t);
4061
 
        }
4062
 
        else {
4063
 
                t->mode = TFM_SHRINKFATTEN;
4064
 
                t->transform = ShrinkFatten;
4065
 
 
4066
 
                initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
4067
 
 
4068
 
                t->idx_max = 0;
4069
 
                t->num.idx_max = 0;
4070
 
                t->snap[0] = 0.0f;
4071
 
                t->snap[1] = 1.0f;
4072
 
                t->snap[2] = t->snap[1] * 0.1f;
4073
 
 
4074
 
                t->num.increment = t->snap[1];
4075
 
 
4076
 
                t->flag |= T_NO_CONSTRAINT;
4077
 
        }
4078
 
}
4079
 
 
4080
 
 
4081
 
int ShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
4082
 
{
4083
 
        float distance;
4084
 
        int i;
4085
 
        char str[128];
4086
 
        char *str_p;
4087
 
        TransData *td = t->data;
4088
 
 
4089
 
        distance = -t->values[0];
4090
 
 
4091
 
        snapGrid(t, &distance);
4092
 
 
4093
 
        applyNumInput(&t->num, &distance);
4094
 
 
4095
 
        /* header print for NumInput */
4096
 
        str_p = str;
4097
 
        str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Shrink/Fatten:"));
4098
 
        if (hasNumInput(&t->num)) {
4099
 
                char c[NUM_STR_REP_LEN];
4100
 
                outputNumInput(&(t->num), c);
4101
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", c);
4102
 
        }
4103
 
        else {
4104
 
                /* default header print */
4105
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %.4f", distance);
4106
 
        }
4107
 
 
4108
 
        if (t->proptext[0]) {
4109
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), " %s", t->proptext);
4110
 
        }
4111
 
        str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), ", (");
4112
 
 
4113
 
        {
4114
 
                wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_RESIZE);
4115
 
                if (kmi) {
4116
 
                        str_p += WM_keymap_item_to_string(kmi, str_p, sizeof(str) - (str_p - str));
4117
 
                }
4118
 
        }
4119
 
        str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_(" or Alt) Even Thickness %s"),
4120
 
                              (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
4121
 
        /* done with header string */
4122
 
 
4123
 
 
4124
 
        t->values[0] = -distance;
4125
 
 
4126
 
        for (i = 0; i < t->total; i++, td++) {
4127
 
                float tdistance;  /* temp dist */
4128
 
                if (td->flag & TD_NOACTION)
4129
 
                        break;
4130
 
 
4131
 
                if (td->flag & TD_SKIP)
4132
 
                        continue;
4133
 
 
4134
 
                /* get the final offset */
4135
 
                tdistance = distance * td->factor;
4136
 
                if (td->ext && (t->flag & T_ALT_TRANSFORM)) {
4137
 
                        tdistance *= td->ext->isize[0];  /* shell factor */
4138
 
                }
4139
 
 
4140
 
                madd_v3_v3v3fl(td->loc, td->iloc, td->axismtx[2], tdistance);
4141
 
        }
4142
 
 
4143
 
        recalcData(t);
4144
 
 
4145
 
        ED_area_headerprint(t->sa, str);
4146
 
 
4147
 
        return 1;
4148
 
}
4149
 
 
4150
 
/* ************************** TILT *************************** */
4151
 
 
4152
 
void initTilt(TransInfo *t)
4153
 
{
4154
 
        t->mode = TFM_TILT;
4155
 
        t->transform = Tilt;
4156
 
 
4157
 
        initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
4158
 
 
4159
 
        t->idx_max = 0;
4160
 
        t->num.idx_max = 0;
4161
 
        t->snap[0] = 0.0f;
4162
 
        t->snap[1] = (float)((5.0 / 180) * M_PI);
4163
 
        t->snap[2] = t->snap[1] * 0.2f;
4164
 
 
4165
 
        t->num.increment = t->snap[1];
4166
 
 
4167
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
4168
 
}
4169
 
 
4170
 
 
4171
 
 
4172
 
int Tilt(TransInfo *t, const int UNUSED(mval[2]))
4173
 
{
4174
 
        TransData *td = t->data;
4175
 
        int i;
4176
 
        char str[50];
4177
 
 
4178
 
        float final;
4179
 
 
4180
 
        final = t->values[0];
4181
 
 
4182
 
        snapGrid(t, &final);
4183
 
 
4184
 
        if (hasNumInput(&t->num)) {
4185
 
                char c[NUM_STR_REP_LEN];
4186
 
 
4187
 
                applyNumInput(&t->num, &final);
4188
 
 
4189
 
                outputNumInput(&(t->num), c);
4190
 
 
4191
 
                sprintf(str, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
4192
 
 
4193
 
                final = DEG2RADF(final);
4194
 
 
4195
 
                /* XXX For some reason, this seems needed for this op, else RNA prop is not updated... :/ */
4196
 
                t->values[0] = final;
4197
 
        }
4198
 
        else {
4199
 
                sprintf(str, IFACE_("Tilt: %.2f° %s"), RAD2DEGF(final), t->proptext);
4200
 
        }
4201
 
 
4202
 
        for (i = 0; i < t->total; i++, td++) {
4203
 
                if (td->flag & TD_NOACTION)
4204
 
                        break;
4205
 
 
4206
 
                if (td->flag & TD_SKIP)
4207
 
                        continue;
4208
 
 
4209
 
                if (td->val) {
4210
 
                        *td->val = td->ival + final * td->factor;
4211
 
                }
4212
 
        }
4213
 
 
4214
 
        recalcData(t);
4215
 
 
4216
 
        ED_area_headerprint(t->sa, str);
4217
 
 
4218
 
        return 1;
4219
 
}
4220
 
 
4221
 
 
4222
 
/* ******************** Curve Shrink/Fatten *************** */
4223
 
 
4224
 
void initCurveShrinkFatten(TransInfo *t)
4225
 
{
4226
 
        t->mode = TFM_CURVE_SHRINKFATTEN;
4227
 
        t->transform = CurveShrinkFatten;
4228
 
 
4229
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
4230
 
 
4231
 
        t->idx_max = 0;
4232
 
        t->num.idx_max = 0;
4233
 
        t->snap[0] = 0.0f;
4234
 
        t->snap[1] = 0.1f;
4235
 
        t->snap[2] = t->snap[1] * 0.1f;
4236
 
 
4237
 
        t->num.increment = t->snap[1];
4238
 
 
4239
 
        t->flag |= T_NO_ZERO;
4240
 
        t->num.flag |= NUM_NO_ZERO;
4241
 
 
4242
 
        t->flag |= T_NO_CONSTRAINT;
4243
 
}
4244
 
 
4245
 
int CurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
4246
 
{
4247
 
        TransData *td = t->data;
4248
 
        float ratio;
4249
 
        int i;
4250
 
        char str[50];
4251
 
 
4252
 
        ratio = t->values[0];
4253
 
 
4254
 
        snapGrid(t, &ratio);
4255
 
 
4256
 
        applyNumInput(&t->num, &ratio);
4257
 
 
4258
 
        /* header print for NumInput */
4259
 
        if (hasNumInput(&t->num)) {
4260
 
                char c[NUM_STR_REP_LEN];
4261
 
 
4262
 
                outputNumInput(&(t->num), c);
4263
 
                sprintf(str, IFACE_("Shrink/Fatten: %s"), c);
4264
 
        }
4265
 
        else {
4266
 
                sprintf(str, IFACE_("Shrink/Fatten: %3f"), ratio);
4267
 
        }
4268
 
 
4269
 
        for (i = 0; i < t->total; i++, td++) {
4270
 
                if (td->flag & TD_NOACTION)
4271
 
                        break;
4272
 
 
4273
 
                if (td->flag & TD_SKIP)
4274
 
                        continue;
4275
 
 
4276
 
                if (td->val) {
4277
 
                        *td->val = td->ival * ratio;
4278
 
                        /* apply PET */
4279
 
                        *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
4280
 
                        if (*td->val <= 0.0f) *td->val = 0.001f;
4281
 
                }
4282
 
        }
4283
 
 
4284
 
        recalcData(t);
4285
 
 
4286
 
        ED_area_headerprint(t->sa, str);
4287
 
 
4288
 
        return 1;
4289
 
}
4290
 
 
4291
 
 
4292
 
void initMaskShrinkFatten(TransInfo *t)
4293
 
{
4294
 
        t->mode = TFM_MASK_SHRINKFATTEN;
4295
 
        t->transform = MaskShrinkFatten;
4296
 
 
4297
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
4298
 
 
4299
 
        t->idx_max = 0;
4300
 
        t->num.idx_max = 0;
4301
 
        t->snap[0] = 0.0f;
4302
 
        t->snap[1] = 0.1f;
4303
 
        t->snap[2] = t->snap[1] * 0.1f;
4304
 
 
4305
 
        t->num.increment = t->snap[1];
4306
 
 
4307
 
        t->flag |= T_NO_ZERO;
4308
 
        t->num.flag |= NUM_NO_ZERO;
4309
 
 
4310
 
        t->flag |= T_NO_CONSTRAINT;
4311
 
}
4312
 
 
4313
 
int MaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
4314
 
{
4315
 
        TransData *td;
4316
 
        float ratio;
4317
 
        int i, initial_feather = FALSE;
4318
 
        char str[50];
4319
 
 
4320
 
        ratio = t->values[0];
4321
 
 
4322
 
        snapGrid(t, &ratio);
4323
 
 
4324
 
        applyNumInput(&t->num, &ratio);
4325
 
 
4326
 
        /* header print for NumInput */
4327
 
        if (hasNumInput(&t->num)) {
4328
 
                char c[NUM_STR_REP_LEN];
4329
 
 
4330
 
                outputNumInput(&(t->num), c);
4331
 
                sprintf(str, IFACE_("Feather Shrink/Fatten: %s"), c);
4332
 
        }
4333
 
        else {
4334
 
                sprintf(str, IFACE_("Feather Shrink/Fatten: %3f"), ratio);
4335
 
        }
4336
 
 
4337
 
        /* detect if no points have feather yet */
4338
 
        if (ratio > 1.0f) {
4339
 
                initial_feather = TRUE;
4340
 
 
4341
 
                for (td = t->data, i = 0; i < t->total; i++, td++) {
4342
 
                        if (td->flag & TD_NOACTION)
4343
 
                                break;
4344
 
 
4345
 
                        if (td->flag & TD_SKIP)
4346
 
                                continue;
4347
 
 
4348
 
                        if (td->ival >= 0.001f)
4349
 
                                initial_feather = FALSE;
4350
 
                }
4351
 
        }
4352
 
 
4353
 
        /* apply shrink/fatten */
4354
 
        for (td = t->data, i = 0; i < t->total; i++, td++) {
4355
 
                if (td->flag & TD_NOACTION)
4356
 
                        break;
4357
 
 
4358
 
                if (td->flag & TD_SKIP)
4359
 
                        continue;
4360
 
 
4361
 
                if (td->val) {
4362
 
                        if (initial_feather)
4363
 
                                *td->val = td->ival + (ratio - 1.0f) * 0.01f;
4364
 
                        else
4365
 
                                *td->val = td->ival * ratio;
4366
 
 
4367
 
                        /* apply PET */
4368
 
                        *td->val = (*td->val * td->factor) + ((1.0f - td->factor) * td->ival);
4369
 
                        if (*td->val <= 0.0f) *td->val = 0.001f;
4370
 
                }
4371
 
        }
4372
 
 
4373
 
        recalcData(t);
4374
 
 
4375
 
        ED_area_headerprint(t->sa, str);
4376
 
 
4377
 
        return 1;
4378
 
}
4379
 
 
4380
 
/* ************************** PUSH/PULL *************************** */
4381
 
 
4382
 
void initPushPull(TransInfo *t)
4383
 
{
4384
 
        t->mode = TFM_PUSHPULL;
4385
 
        t->transform = PushPull;
4386
 
 
4387
 
        initMouseInputMode(t, &t->mouse, INPUT_VERTICAL_ABSOLUTE);
4388
 
 
4389
 
        t->idx_max = 0;
4390
 
        t->num.idx_max = 0;
4391
 
        t->snap[0] = 0.0f;
4392
 
        t->snap[1] = 1.0f;
4393
 
        t->snap[2] = t->snap[1] * 0.1f;
4394
 
 
4395
 
        t->num.increment = t->snap[1];
4396
 
}
4397
 
 
4398
 
 
4399
 
int PushPull(TransInfo *t, const int UNUSED(mval[2]))
4400
 
{
4401
 
        float vec[3], axis[3];
4402
 
        float distance;
4403
 
        int i;
4404
 
        char str[128];
4405
 
        TransData *td = t->data;
4406
 
 
4407
 
        distance = t->values[0];
4408
 
 
4409
 
        snapGrid(t, &distance);
4410
 
 
4411
 
        applyNumInput(&t->num, &distance);
4412
 
 
4413
 
        /* header print for NumInput */
4414
 
        if (hasNumInput(&t->num)) {
4415
 
                char c[NUM_STR_REP_LEN];
4416
 
 
4417
 
                outputNumInput(&(t->num), c);
4418
 
 
4419
 
                sprintf(str, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
4420
 
        }
4421
 
        else {
4422
 
                /* default header print */
4423
 
                sprintf(str, IFACE_("Push/Pull: %.4f%s %s"), distance, t->con.text, t->proptext);
4424
 
        }
4425
 
 
4426
 
        t->values[0] = distance;
4427
 
 
4428
 
        if (t->con.applyRot && t->con.mode & CON_APPLY) {
4429
 
                t->con.applyRot(t, NULL, axis, NULL);
4430
 
        }
4431
 
 
4432
 
        for (i = 0; i < t->total; i++, td++) {
4433
 
                if (td->flag & TD_NOACTION)
4434
 
                        break;
4435
 
 
4436
 
                if (td->flag & TD_SKIP)
4437
 
                        continue;
4438
 
 
4439
 
                sub_v3_v3v3(vec, t->center, td->center);
4440
 
                if (t->con.applyRot && t->con.mode & CON_APPLY) {
4441
 
                        t->con.applyRot(t, td, axis, NULL);
4442
 
                        if (isLockConstraint(t)) {
4443
 
                                float dvec[3];
4444
 
                                project_v3_v3v3(dvec, vec, axis);
4445
 
                                sub_v3_v3(vec, dvec);
4446
 
                        }
4447
 
                        else {
4448
 
                                project_v3_v3v3(vec, vec, axis);
4449
 
                        }
4450
 
                }
4451
 
                normalize_v3(vec);
4452
 
                mul_v3_fl(vec, distance);
4453
 
                mul_v3_fl(vec, td->factor);
4454
 
 
4455
 
                add_v3_v3v3(td->loc, td->iloc, vec);
4456
 
        }
4457
 
 
4458
 
        recalcData(t);
4459
 
 
4460
 
        ED_area_headerprint(t->sa, str);
4461
 
 
4462
 
        return 1;
4463
 
}
4464
 
 
4465
 
/* ************************** BEVEL **************************** */
4466
 
 
4467
 
void initBevel(TransInfo *t)
4468
 
{
4469
 
        t->transform = Bevel;
4470
 
        t->handleEvent = handleEventBevel;
4471
 
 
4472
 
        initMouseInputMode(t, &t->mouse, INPUT_HORIZONTAL_ABSOLUTE);
4473
 
 
4474
 
        t->mode = TFM_BEVEL;
4475
 
        t->flag |= T_NO_CONSTRAINT;
4476
 
        t->num.flag |= NUM_NO_NEGATIVE;
4477
 
 
4478
 
        t->idx_max = 0;
4479
 
        t->num.idx_max = 0;
4480
 
        t->snap[0] = 0.0f;
4481
 
        t->snap[1] = 0.1f;
4482
 
        t->snap[2] = t->snap[1] * 0.1f;
4483
 
 
4484
 
        t->num.increment = t->snap[1];
4485
 
 
4486
 
        /* DON'T KNOW WHY THIS IS NEEDED */
4487
 
        if (G.editBMesh->imval[0] == 0 && G.editBMesh->imval[1] == 0) {
4488
 
                /* save the initial mouse co */
4489
 
                G.editBMesh->imval[0] = t->imval[0];
4490
 
                G.editBMesh->imval[1] = t->imval[1];
4491
 
        }
4492
 
        else {
4493
 
                /* restore the mouse co from a previous call to initTransform() */
4494
 
                t->imval[0] = G.editBMesh->imval[0];
4495
 
                t->imval[1] = G.editBMesh->imval[1];
4496
 
        }
4497
 
}
4498
 
 
4499
 
int handleEventBevel(TransInfo *t, wmEvent *event)
4500
 
{
4501
 
        if (event->val == KM_PRESS) {
4502
 
                if (!G.editBMesh) return 0;
4503
 
 
4504
 
                switch (event->type) {
4505
 
                        case MIDDLEMOUSE:
4506
 
                                G.editBMesh->options ^= BME_BEVEL_VERT;
4507
 
                                t->state = TRANS_CANCEL;
4508
 
                                return 1;
4509
 
                        //case PADPLUSKEY:
4510
 
                        //      G.editBMesh->options ^= BME_BEVEL_RES;
4511
 
                        //      G.editBMesh->res += 1;
4512
 
                        //      if (G.editBMesh->res > 4) {
4513
 
                        //              G.editBMesh->res = 4;
4514
 
                        //      }
4515
 
                        //      t->state = TRANS_CANCEL;
4516
 
                        //      return 1;
4517
 
                        //case PADMINUS:
4518
 
                        //      G.editBMesh->options ^= BME_BEVEL_RES;
4519
 
                        //      G.editBMesh->res -= 1;
4520
 
                        //      if (G.editBMesh->res < 0) {
4521
 
                        //              G.editBMesh->res = 0;
4522
 
                        //      }
4523
 
                        //      t->state = TRANS_CANCEL;
4524
 
                        //      return 1;
4525
 
                        default:
4526
 
                                return 0;
4527
 
                }
4528
 
        }
4529
 
        return 0;
4530
 
}
4531
 
 
4532
 
int Bevel(TransInfo *t, const int UNUSED(mval[2]))
4533
 
{
4534
 
        float distance, d;
4535
 
        int i;
4536
 
        char str[128];
4537
 
        const char *mode;
4538
 
        TransData *td = t->data;
4539
 
 
4540
 
        mode = (G.editBMesh->options & BME_BEVEL_VERT) ? IFACE_("verts only") : IFACE_("normal");
4541
 
        distance = t->values[0] / 4; /* 4 just seemed a nice value to me, nothing special */
4542
 
 
4543
 
        distance = fabs(distance);
4544
 
 
4545
 
        snapGrid(t, &distance);
4546
 
 
4547
 
        applyNumInput(&t->num, &distance);
4548
 
 
4549
 
        /* header print for NumInput */
4550
 
        if (hasNumInput(&t->num)) {
4551
 
                char c[NUM_STR_REP_LEN];
4552
 
 
4553
 
                outputNumInput(&(t->num), c);
4554
 
 
4555
 
                sprintf(str, IFACE_("Bevel - Dist: %s, Mode: %s (MMB to toggle))"), c, mode);
4556
 
        }
4557
 
        else {
4558
 
                /* default header print */
4559
 
                sprintf(str, IFACE_("Bevel - Dist: %.4f, Mode: %s (MMB to toggle))"), distance, mode);
4560
 
        }
4561
 
 
4562
 
        if (distance < 0) distance = -distance;
4563
 
        for (i = 0; i < t->total; i++, td++) {
4564
 
                if (td->axismtx[1][0] > 0 && distance > td->axismtx[1][0]) {
4565
 
                        d = td->axismtx[1][0];
4566
 
                }
4567
 
                else {
4568
 
                        d = distance;
4569
 
                }
4570
 
                madd_v3_v3v3fl(td->loc, td->center, td->axismtx[0], (*td->val) * d);
4571
 
        }
4572
 
 
4573
 
        recalcData(t);
4574
 
 
4575
 
        ED_area_headerprint(t->sa, str);
4576
 
 
4577
 
        return 1;
4578
 
}
4579
 
 
4580
 
/* ************************** BEVEL WEIGHT *************************** */
4581
 
 
4582
 
void initBevelWeight(TransInfo *t)
4583
 
{
4584
 
        t->mode = TFM_BWEIGHT;
4585
 
        t->transform = BevelWeight;
4586
 
 
4587
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
4588
 
 
4589
 
        t->idx_max = 0;
4590
 
        t->num.idx_max = 0;
4591
 
        t->snap[0] = 0.0f;
4592
 
        t->snap[1] = 0.1f;
4593
 
        t->snap[2] = t->snap[1] * 0.1f;
4594
 
 
4595
 
        t->num.increment = t->snap[1];
4596
 
 
4597
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
4598
 
}
4599
 
 
4600
 
int BevelWeight(TransInfo *t, const int UNUSED(mval[2]))
4601
 
{
4602
 
        TransData *td = t->data;
4603
 
        float weight;
4604
 
        int i;
4605
 
        char str[50];
4606
 
 
4607
 
        weight = t->values[0];
4608
 
 
4609
 
        weight -= 1.0f;
4610
 
        if (weight > 1.0f) weight = 1.0f;
4611
 
 
4612
 
        snapGrid(t, &weight);
4613
 
 
4614
 
        applyNumInput(&t->num, &weight);
4615
 
 
4616
 
        /* header print for NumInput */
4617
 
        if (hasNumInput(&t->num)) {
4618
 
                char c[NUM_STR_REP_LEN];
4619
 
 
4620
 
                outputNumInput(&(t->num), c);
4621
 
 
4622
 
                if (weight >= 0.0f)
4623
 
                        sprintf(str, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
4624
 
                else
4625
 
                        sprintf(str, IFACE_("Bevel Weight: %s %s"), c, t->proptext);
4626
 
        }
4627
 
        else {
4628
 
                /* default header print */
4629
 
                if (weight >= 0.0f)
4630
 
                        sprintf(str, IFACE_("Bevel Weight: +%.3f %s"), weight, t->proptext);
4631
 
                else
4632
 
                        sprintf(str, IFACE_("Bevel Weight: %.3f %s"), weight, t->proptext);
4633
 
        }
4634
 
 
4635
 
        for (i = 0; i < t->total; i++, td++) {
4636
 
                if (td->flag & TD_NOACTION)
4637
 
                        break;
4638
 
 
4639
 
                if (td->val) {
4640
 
                        *td->val = td->ival + weight * td->factor;
4641
 
                        if (*td->val < 0.0f) *td->val = 0.0f;
4642
 
                        if (*td->val > 1.0f) *td->val = 1.0f;
4643
 
                }
4644
 
        }
4645
 
 
4646
 
        recalcData(t);
4647
 
 
4648
 
        ED_area_headerprint(t->sa, str);
4649
 
 
4650
 
        return 1;
4651
 
}
4652
 
 
4653
 
/* ************************** CREASE *************************** */
4654
 
 
4655
 
void initCrease(TransInfo *t)
4656
 
{
4657
 
        t->mode = TFM_CREASE;
4658
 
        t->transform = Crease;
4659
 
 
4660
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
4661
 
 
4662
 
        t->idx_max = 0;
4663
 
        t->num.idx_max = 0;
4664
 
        t->snap[0] = 0.0f;
4665
 
        t->snap[1] = 0.1f;
4666
 
        t->snap[2] = t->snap[1] * 0.1f;
4667
 
 
4668
 
        t->num.increment = t->snap[1];
4669
 
 
4670
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
4671
 
}
4672
 
 
4673
 
int Crease(TransInfo *t, const int UNUSED(mval[2]))
4674
 
{
4675
 
        TransData *td = t->data;
4676
 
        float crease;
4677
 
        int i;
4678
 
        char str[50];
4679
 
 
4680
 
        crease = t->values[0];
4681
 
 
4682
 
        crease -= 1.0f;
4683
 
        if (crease > 1.0f) crease = 1.0f;
4684
 
 
4685
 
        snapGrid(t, &crease);
4686
 
 
4687
 
        applyNumInput(&t->num, &crease);
4688
 
 
4689
 
        /* header print for NumInput */
4690
 
        if (hasNumInput(&t->num)) {
4691
 
                char c[NUM_STR_REP_LEN];
4692
 
 
4693
 
                outputNumInput(&(t->num), c);
4694
 
 
4695
 
                if (crease >= 0.0f)
4696
 
                        sprintf(str, IFACE_("Crease: +%s %s"), c, t->proptext);
4697
 
                else
4698
 
                        sprintf(str, IFACE_("Crease: %s %s"), c, t->proptext);
4699
 
        }
4700
 
        else {
4701
 
                /* default header print */
4702
 
                if (crease >= 0.0f)
4703
 
                        sprintf(str, IFACE_("Crease: +%.3f %s"), crease, t->proptext);
4704
 
                else
4705
 
                        sprintf(str, IFACE_("Crease: %.3f %s"), crease, t->proptext);
4706
 
        }
4707
 
 
4708
 
        for (i = 0; i < t->total; i++, td++) {
4709
 
                if (td->flag & TD_NOACTION)
4710
 
                        break;
4711
 
 
4712
 
                if (td->flag & TD_SKIP)
4713
 
                        continue;
4714
 
 
4715
 
                if (td->val) {
4716
 
                        *td->val = td->ival + crease * td->factor;
4717
 
                        if (*td->val < 0.0f) *td->val = 0.0f;
4718
 
                        if (*td->val > 1.0f) *td->val = 1.0f;
4719
 
                }
4720
 
        }
4721
 
 
4722
 
        recalcData(t);
4723
 
 
4724
 
        ED_area_headerprint(t->sa, str);
4725
 
 
4726
 
        return 1;
4727
 
}
4728
 
 
4729
 
/* ******************** EditBone (B-bone) width scaling *************** */
4730
 
 
4731
 
void initBoneSize(TransInfo *t)
4732
 
{
4733
 
        t->mode = TFM_BONESIZE;
4734
 
        t->transform = BoneSize;
4735
 
 
4736
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
4737
 
 
4738
 
        t->idx_max = 2;
4739
 
        t->num.idx_max = 2;
4740
 
        t->num.flag |= NUM_NULL_ONE;
4741
 
        t->num.flag |= NUM_AFFECT_ALL;
4742
 
        t->snap[0] = 0.0f;
4743
 
        t->snap[1] = 0.1f;
4744
 
        t->snap[2] = t->snap[1] * 0.1f;
4745
 
 
4746
 
        t->num.increment = t->snap[1];
4747
 
}
4748
 
 
4749
 
static void headerBoneSize(TransInfo *t, float vec[3], char *str)
4750
 
{
4751
 
        char tvec[NUM_STR_REP_LEN * 3];
4752
 
        if (hasNumInput(&t->num)) {
4753
 
                outputNumInput(&(t->num), tvec);
4754
 
        }
4755
 
        else {
4756
 
                sprintf(&tvec[0], "%.4f", vec[0]);
4757
 
                sprintf(&tvec[NUM_STR_REP_LEN], "%.4f", vec[1]);
4758
 
                sprintf(&tvec[NUM_STR_REP_LEN * 2], "%.4f", vec[2]);
4759
 
        }
4760
 
 
4761
 
        /* hmm... perhaps the y-axis values don't need to be shown? */
4762
 
        if (t->con.mode & CON_APPLY) {
4763
 
                if (t->num.idx_max == 0)
4764
 
                        sprintf(str, IFACE_("ScaleB: %s%s %s"), &tvec[0], t->con.text, t->proptext);
4765
 
                else
4766
 
                        sprintf(str, IFACE_("ScaleB: %s : %s : %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
4767
 
                                &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
4768
 
        }
4769
 
        else {
4770
 
                sprintf(str, IFACE_("ScaleB X: %s  Y: %s  Z: %s%s %s"), &tvec[0], &tvec[NUM_STR_REP_LEN],
4771
 
                        &tvec[NUM_STR_REP_LEN * 2], t->con.text, t->proptext);
4772
 
        }
4773
 
}
4774
 
 
4775
 
static void ElementBoneSize(TransInfo *t, TransData *td, float mat[3][3])
4776
 
{
4777
 
        float tmat[3][3], smat[3][3], oldy;
4778
 
        float sizemat[3][3];
4779
 
 
4780
 
        mul_m3_m3m3(smat, mat, td->mtx);
4781
 
        mul_m3_m3m3(tmat, td->smtx, smat);
4782
 
 
4783
 
        if (t->con.applySize) {
4784
 
                t->con.applySize(t, td, tmat);
4785
 
        }
4786
 
 
4787
 
        /* we've tucked the scale in loc */
4788
 
        oldy = td->iloc[1];
4789
 
        size_to_mat3(sizemat, td->iloc);
4790
 
        mul_m3_m3m3(tmat, tmat, sizemat);
4791
 
        mat3_to_size(td->loc, tmat);
4792
 
        td->loc[1] = oldy;
4793
 
}
4794
 
 
4795
 
int BoneSize(TransInfo *t, const int mval[2])
4796
 
{
4797
 
        TransData *td = t->data;
4798
 
        float size[3], mat[3][3];
4799
 
        float ratio;
4800
 
        int i;
4801
 
        char str[60];
4802
 
        
4803
 
        // TRANSFORM_FIX_ME MOVE TO MOUSE INPUT
4804
 
        /* for manipulator, center handle, the scaling can't be done relative to center */
4805
 
        if ((t->flag & T_USES_MANIPULATOR) && t->con.mode == 0) {
4806
 
                ratio = 1.0f - ((t->imval[0] - mval[0]) + (t->imval[1] - mval[1])) / 100.0f;
4807
 
        }
4808
 
        else {
4809
 
                ratio = t->values[0];
4810
 
        }
4811
 
        
4812
 
        size[0] = size[1] = size[2] = ratio;
4813
 
        
4814
 
        snapGrid(t, size);
4815
 
        
4816
 
        if (hasNumInput(&t->num)) {
4817
 
                applyNumInput(&t->num, size);
4818
 
                constraintNumInput(t, size);
4819
 
        }
4820
 
        
4821
 
        size_to_mat3(mat, size);
4822
 
        
4823
 
        if (t->con.applySize) {
4824
 
                t->con.applySize(t, NULL, mat);
4825
 
        }
4826
 
        
4827
 
        copy_m3_m3(t->mat, mat);    // used in manipulator
4828
 
        
4829
 
        headerBoneSize(t, size, str);
4830
 
        
4831
 
        for (i = 0; i < t->total; i++, td++) {
4832
 
                if (td->flag & TD_NOACTION)
4833
 
                        break;
4834
 
                
4835
 
                if (td->flag & TD_SKIP)
4836
 
                        continue;
4837
 
                
4838
 
                ElementBoneSize(t, td, mat);
4839
 
        }
4840
 
        
4841
 
        recalcData(t);
4842
 
        
4843
 
        ED_area_headerprint(t->sa, str);
4844
 
        
4845
 
        return 1;
4846
 
}
4847
 
 
4848
 
 
4849
 
/* ******************** EditBone envelope *************** */
4850
 
 
4851
 
void initBoneEnvelope(TransInfo *t)
4852
 
{
4853
 
        t->mode = TFM_BONE_ENVELOPE;
4854
 
        t->transform = BoneEnvelope;
4855
 
        
4856
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING);
4857
 
        
4858
 
        t->idx_max = 0;
4859
 
        t->num.idx_max = 0;
4860
 
        t->snap[0] = 0.0f;
4861
 
        t->snap[1] = 0.1f;
4862
 
        t->snap[2] = t->snap[1] * 0.1f;
4863
 
        
4864
 
        t->num.increment = t->snap[1];
4865
 
 
4866
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
4867
 
}
4868
 
 
4869
 
int BoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
4870
 
{
4871
 
        TransData *td = t->data;
4872
 
        float ratio;
4873
 
        int i;
4874
 
        char str[50];
4875
 
        
4876
 
        ratio = t->values[0];
4877
 
        
4878
 
        snapGrid(t, &ratio);
4879
 
        
4880
 
        applyNumInput(&t->num, &ratio);
4881
 
        
4882
 
        /* header print for NumInput */
4883
 
        if (hasNumInput(&t->num)) {
4884
 
                char c[NUM_STR_REP_LEN];
4885
 
                
4886
 
                outputNumInput(&(t->num), c);
4887
 
                sprintf(str, IFACE_("Envelope: %s"), c);
4888
 
        }
4889
 
        else {
4890
 
                sprintf(str, IFACE_("Envelope: %3f"), ratio);
4891
 
        }
4892
 
        
4893
 
        for (i = 0; i < t->total; i++, td++) {
4894
 
                if (td->flag & TD_NOACTION)
4895
 
                        break;
4896
 
                
4897
 
                if (td->flag & TD_SKIP)
4898
 
                        continue;
4899
 
                
4900
 
                if (td->val) {
4901
 
                        /* if the old/original value was 0.0f, then just use ratio */
4902
 
                        if (td->ival)
4903
 
                                *td->val = td->ival * ratio;
4904
 
                        else
4905
 
                                *td->val = ratio;
4906
 
                }
4907
 
        }
4908
 
        
4909
 
        recalcData(t);
4910
 
        
4911
 
        ED_area_headerprint(t->sa, str);
4912
 
        
4913
 
        return 1;
4914
 
}
4915
 
 
4916
 
/* ********************  Edge Slide   *************** */
4917
 
static BMEdge *get_other_edge(BMVert *v, BMEdge *e)
4918
 
{
4919
 
        BMIter iter;
4920
 
        BMEdge *e_iter;
4921
 
 
4922
 
        BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
4923
 
                if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT) && e_iter != e) {
4924
 
                        return e_iter;
4925
 
                }
4926
 
        }
4927
 
 
4928
 
        return NULL;
4929
 
}
4930
 
 
4931
 
static void len_v3_ensure(float v[3], const float length)
4932
 
{
4933
 
        normalize_v3(v);
4934
 
        mul_v3_fl(v, length);
4935
 
}
4936
 
 
4937
 
/**
4938
 
 * Find the closest point on the ngon on the opposite side.
4939
 
 * used to set the edge slide distance for ngons.
4940
 
 */
4941
 
static bool bm_loop_calc_opposite_co(BMLoop *l_tmp,
4942
 
                                     const float plane_no[3],
4943
 
                                     float r_co[3])
4944
 
{
4945
 
        /* skip adjacent edges */
4946
 
        BMLoop *l_first = l_tmp->next;
4947
 
        BMLoop *l_last  = l_tmp->prev;
4948
 
        BMLoop *l_iter;
4949
 
        float dist = FLT_MAX;
4950
 
 
4951
 
        l_iter = l_first;
4952
 
        do {
4953
 
                float tvec[3];
4954
 
                if (isect_line_plane_v3(tvec,
4955
 
                                        l_iter->v->co, l_iter->next->v->co,
4956
 
                                        l_tmp->v->co, plane_no, false))
4957
 
                {
4958
 
                        const float fac = line_point_factor_v3(tvec, l_iter->v->co, l_iter->next->v->co);
4959
 
                        /* allow some overlap to avoid missing the intersection because of float precision */
4960
 
                        if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) {
4961
 
                                /* likelyhood of multiple intersections per ngon is quite low,
4962
 
                                 * it would have to loop back on its self, but better support it
4963
 
                                 * so check for the closest opposite edge */
4964
 
                                const float tdist = len_v3v3(l_tmp->v->co, tvec);
4965
 
                                if (tdist < dist) {
4966
 
                                        copy_v3_v3(r_co, tvec);
4967
 
                                        dist = tdist;
4968
 
                                }
4969
 
                        }
4970
 
                }
4971
 
        } while ((l_iter = l_iter->next) != l_last);
4972
 
 
4973
 
        return (dist != FLT_MAX);
4974
 
}
4975
 
 
4976
 
/**
4977
 
 * Given 2 edges and a loop, step over the loops
4978
 
 * and calculate a direction to slide along.
4979
 
 *
4980
 
 * \param r_slide_vec the direction to slide,
4981
 
 * the length of the vector defines the slide distance.
4982
 
 */
4983
 
static BMLoop *get_next_loop(BMVert *v, BMLoop *l,
4984
 
                             BMEdge *e_prev, BMEdge *e_next, float r_slide_vec[3])
4985
 
{
4986
 
        BMLoop *l_first;
4987
 
        float vec_accum[3] = {0.0f, 0.0f, 0.0f};
4988
 
        float vec_accum_len = 0.0f;
4989
 
        int i = 0;
4990
 
 
4991
 
        BLI_assert(BM_edge_share_vert(e_prev, e_next) == v);
4992
 
 
4993
 
        l_first = l;
4994
 
        do {
4995
 
                l = BM_face_other_edge_loop(l->f, l->e, v);
4996
 
                if (l->radial_next == l)
4997
 
                        return NULL;
4998
 
                
4999
 
                if (l->e == e_next) {
5000
 
                        if (i) {
5001
 
                                len_v3_ensure(vec_accum, vec_accum_len / (float)i);
5002
 
                        }
5003
 
                        else {
5004
 
                                /* When there is no edge to slide along,
5005
 
                                 * we must slide along the vector defined by the face we're attach to */
5006
 
                                BMLoop *l_tmp = BM_face_vert_share_loop(l_first->f, v);
5007
 
 
5008
 
                                BLI_assert(ELEM(l_tmp->e, e_prev, e_next) && ELEM(l_tmp->prev->e, e_prev, e_next));
5009
 
 
5010
 
                                if (l_tmp->f->len == 4) {
5011
 
                                        /* we could use code below, but in this case
5012
 
                                         * sliding diagonally across the quad works well */
5013
 
                                        sub_v3_v3v3(vec_accum, l_tmp->next->next->v->co, v->co);
5014
 
                                }
5015
 
                                else {
5016
 
                                        float tdir[3];
5017
 
                                        BM_loop_calc_face_direction(l_tmp, tdir);
5018
 
                                        cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir);
5019
 
#if 0
5020
 
                                        /* rough guess, we can  do better! */
5021
 
                                        len_v3_ensure(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f);
5022
 
#else
5023
 
                                        /* be clever, check the opposite ngon edge to slide into.
5024
 
                                         * this gives best results */
5025
 
                                        {
5026
 
                                                float tvec[3];
5027
 
                                                float dist;
5028
 
 
5029
 
                                                if (bm_loop_calc_opposite_co(l_tmp, tdir, tvec)) {
5030
 
                                                        dist = len_v3v3(l_tmp->v->co, tvec);
5031
 
                                                }
5032
 
                                                else {
5033
 
                                                        dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f;
5034
 
                                                }
5035
 
 
5036
 
                                                len_v3_ensure(vec_accum, dist);
5037
 
                                        }
5038
 
#endif
5039
 
                                }
5040
 
                        }
5041
 
 
5042
 
                        copy_v3_v3(r_slide_vec, vec_accum);
5043
 
                        return l;
5044
 
                }
5045
 
                else {
5046
 
                        /* accumulate the normalized edge vector,
5047
 
                         * normalize so some edges don't skew the result */
5048
 
                        float tvec[3];
5049
 
                        sub_v3_v3v3(tvec, BM_edge_other_vert(l->e, v)->co, v->co);
5050
 
                        vec_accum_len += normalize_v3(tvec);
5051
 
                        add_v3_v3(vec_accum, tvec);
5052
 
                        i += 1;
5053
 
                }
5054
 
 
5055
 
                if (BM_face_other_edge_loop(l->f, l->e, v)->e == e_next) {
5056
 
                        if (i) {
5057
 
                                len_v3_ensure(vec_accum, vec_accum_len / (float)i);
5058
 
                        }
5059
 
 
5060
 
                        copy_v3_v3(r_slide_vec, vec_accum);
5061
 
                        return BM_face_other_edge_loop(l->f, l->e, v);
5062
 
                }
5063
 
                
5064
 
                BLI_assert(l != l->radial_next);
5065
 
                l = l->radial_next;
5066
 
        } while (l != l_first);
5067
 
 
5068
 
        if (i) {
5069
 
                len_v3_ensure(vec_accum, vec_accum_len / (float)i);
5070
 
        }
5071
 
        
5072
 
        copy_v3_v3(r_slide_vec, vec_accum);
5073
 
        
5074
 
        return NULL;
5075
 
}
5076
 
 
5077
 
static void calcNonProportionalEdgeSlide(TransInfo *t, EdgeSlideData *sld, const float mval[2])
5078
 
{
5079
 
        TransDataEdgeSlideVert *sv = sld->sv;
5080
 
 
5081
 
        if (sld->totsv > 0) {
5082
 
                ARegion *ar = t->ar;
5083
 
                RegionView3D *rv3d = NULL;
5084
 
                float projectMat[4][4];
5085
 
 
5086
 
                int i = 0;
5087
 
 
5088
 
                float v_proj[2];
5089
 
                float dist = 0;
5090
 
                float min_dist = FLT_MAX;
5091
 
 
5092
 
                if (t->spacetype == SPACE_VIEW3D) {
5093
 
                        /* background mode support */
5094
 
                        rv3d = t->ar ? t->ar->regiondata : NULL;
5095
 
                }
5096
 
 
5097
 
                if (!rv3d) {
5098
 
                        /* ok, let's try to survive this */
5099
 
                        unit_m4(projectMat);
5100
 
                }
5101
 
                else {
5102
 
                        ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
5103
 
                }
5104
 
 
5105
 
                for (i = 0; i < sld->totsv; i++, sv++) {
5106
 
                        /* Set length */
5107
 
                        sv->edge_len = len_v3v3(sv->upvec, sv->downvec);
5108
 
 
5109
 
                        ED_view3d_project_float_v2_m4(ar, sv->v->co, v_proj, projectMat);
5110
 
                        dist = len_squared_v2v2(mval, v_proj);
5111
 
                        if (dist < min_dist) {
5112
 
                                min_dist = dist;
5113
 
                                sld->curr_sv_index = i;
5114
 
                        }
5115
 
                }
5116
 
        }
5117
 
        else {
5118
 
                sld->curr_sv_index = 0;
5119
 
        }
5120
 
}
5121
 
 
5122
 
static int createEdgeSlideVerts(TransInfo *t)
5123
 
{
5124
 
        BMEditMesh *em = BMEdit_FromObject(t->obedit);
5125
 
        BMesh *bm = em->bm;
5126
 
        BMIter iter;
5127
 
        BMEdge *e, *e1;
5128
 
        BMVert *v, *v2;
5129
 
        TransDataEdgeSlideVert *sv_array;
5130
 
        int sv_tot;
5131
 
        BMBVHTree *btree;
5132
 
        SmallHash table;
5133
 
        EdgeSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
5134
 
        View3D *v3d = NULL;
5135
 
        RegionView3D *rv3d = NULL;
5136
 
        ARegion *ar = t->ar;
5137
 
        float projectMat[4][4];
5138
 
        float mval[2] = {(float)t->mval[0], (float)t->mval[1]};
5139
 
        float start[3] = {0.0f, 0.0f, 0.0f}, end[3] = {0.0f, 0.0f, 0.0f};
5140
 
        float vec[3], vec2[3] /*, lastvec[3], size, dis=0.0, z */ /* UNUSED */;
5141
 
        float dir[3], maxdist, (*loop_dir)[3], *loop_maxdist;
5142
 
        int numsel, i, j, loop_nr, l_nr;
5143
 
        int use_btree_disp;
5144
 
 
5145
 
        if (t->spacetype == SPACE_VIEW3D) {
5146
 
                /* background mode support */
5147
 
                v3d = t->sa ? t->sa->spacedata.first : NULL;
5148
 
                rv3d = t->ar ? t->ar->regiondata : NULL;
5149
 
        }
5150
 
 
5151
 
        use_btree_disp = (v3d && t->obedit->dt > OB_WIRE && v3d->drawtype > OB_WIRE);
5152
 
 
5153
 
        if (use_btree_disp) {
5154
 
                btree = BMBVH_NewBVH(em, BMBVH_RESPECT_HIDDEN, NULL, NULL);
5155
 
        }
5156
 
        else {
5157
 
                btree = NULL;
5158
 
        }
5159
 
 
5160
 
        sld->is_proportional = TRUE;
5161
 
        sld->curr_sv_index = 0;
5162
 
        sld->flipped_vtx = FALSE;
5163
 
 
5164
 
        if (!rv3d) {
5165
 
                /* ok, let's try to survive this */
5166
 
                unit_m4(projectMat);
5167
 
        }
5168
 
        else {
5169
 
                ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
5170
 
        }
5171
 
        
5172
 
        BLI_smallhash_init(&sld->vhash);
5173
 
        BLI_smallhash_init(&sld->origfaces);
5174
 
        BLI_smallhash_init(&table);
5175
 
        
5176
 
        /*ensure valid selection*/
5177
 
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
5178
 
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
5179
 
                        BMIter iter2;
5180
 
                        numsel = 0;
5181
 
                        BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) {
5182
 
                                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
5183
 
                                        /* BMESH_TODO: this is probably very evil,
5184
 
                                         * set v->e to a selected edge*/
5185
 
                                        v->e = e;
5186
 
 
5187
 
                                        numsel++;
5188
 
                                }
5189
 
                        }
5190
 
 
5191
 
                        if (numsel == 0 || numsel > 2) {
5192
 
                                MEM_freeN(sld);
5193
 
                                if (btree)
5194
 
                                        BMBVH_FreeBVH(btree);
5195
 
                                return 0; /* invalid edge selection */
5196
 
                        }
5197
 
                }
5198
 
        }
5199
 
 
5200
 
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
5201
 
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
5202
 
                        if (!BM_edge_is_manifold(e)) {
5203
 
                                MEM_freeN(sld);
5204
 
                                if (btree)
5205
 
                                        BMBVH_FreeBVH(btree);
5206
 
                                return 0; /* can only handle exactly 2 faces around each edge */
5207
 
                        }
5208
 
                }
5209
 
        }
5210
 
 
5211
 
        j = 0;
5212
 
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
5213
 
                if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
5214
 
                        BM_elem_flag_enable(v, BM_ELEM_TAG);
5215
 
                        BLI_smallhash_insert(&table, (uintptr_t)v, SET_INT_IN_POINTER(j));
5216
 
                        j += 1;
5217
 
                }
5218
 
                else {
5219
 
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
5220
 
                }
5221
 
        }
5222
 
 
5223
 
        if (!j) {
5224
 
                MEM_freeN(sld);
5225
 
                if (btree)
5226
 
                        BMBVH_FreeBVH(btree);
5227
 
                return 0;
5228
 
        }
5229
 
 
5230
 
        sv_tot = j;
5231
 
        sv_array = MEM_callocN(sizeof(TransDataEdgeSlideVert) * sv_tot, "sv_array");
5232
 
        loop_nr = 0;
5233
 
 
5234
 
        while (1) {
5235
 
                BMLoop *l, *l1, *l2;
5236
 
                BMVert *v_first;
5237
 
 
5238
 
                v = NULL;
5239
 
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
5240
 
                        if (BM_elem_flag_test(v, BM_ELEM_TAG))
5241
 
                                break;
5242
 
 
5243
 
                }
5244
 
 
5245
 
                if (!v)
5246
 
                        break;
5247
 
 
5248
 
                if (!v->e)
5249
 
                        continue;
5250
 
                
5251
 
                v_first = v;
5252
 
 
5253
 
                /*walk along the edge loop*/
5254
 
                e = v->e;
5255
 
 
5256
 
                /*first, rewind*/
5257
 
                numsel = 0;
5258
 
                do {
5259
 
                        e = get_other_edge(v, e);
5260
 
                        if (!e) {
5261
 
                                e = v->e;
5262
 
                                break;
5263
 
                        }
5264
 
 
5265
 
                        numsel += 1;
5266
 
 
5267
 
                        if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG))
5268
 
                                break;
5269
 
 
5270
 
                        v = BM_edge_other_vert(e, v);
5271
 
                } while (e != v_first->e);
5272
 
 
5273
 
                BM_elem_flag_disable(v, BM_ELEM_TAG);
5274
 
 
5275
 
                l1 = l2 = l = NULL;
5276
 
                l1 = e->l;
5277
 
                l2 = e->l->radial_next;
5278
 
 
5279
 
                l = BM_face_other_edge_loop(l1->f, l1->e, v);
5280
 
                sub_v3_v3v3(vec, BM_edge_other_vert(l->e, v)->co, v->co);
5281
 
 
5282
 
                if (l2 != l1) {
5283
 
                        l = BM_face_other_edge_loop(l2->f, l2->e, v);
5284
 
                        sub_v3_v3v3(vec2, BM_edge_other_vert(l->e, v)->co, v->co);
5285
 
                }
5286
 
                else {
5287
 
                        l2 = NULL;
5288
 
                }
5289
 
 
5290
 
                /*iterate over the loop*/
5291
 
                v_first = v;
5292
 
                do {
5293
 
                        TransDataEdgeSlideVert *sv;
5294
 
 
5295
 
                        /* XXX, 'sv' will initialize multiple times, this is suspicious. see [#34024] */
5296
 
                        BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
5297
 
                        sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
5298
 
                        sv->v = v;
5299
 
                        sv->origvert = *v;
5300
 
                        sv->loop_nr = loop_nr;
5301
 
 
5302
 
                        copy_v3_v3(sv->upvec, vec);
5303
 
                        if (l2)
5304
 
                                copy_v3_v3(sv->downvec, vec2);
5305
 
 
5306
 
                        l = BM_face_other_edge_loop(l1->f, l1->e, v);
5307
 
                        sv->up = BM_edge_other_vert(l->e, v);
5308
 
 
5309
 
                        if (l2) {
5310
 
                                l = BM_face_other_edge_loop(l2->f, l2->e, v);
5311
 
                                sv->down = BM_edge_other_vert(l->e, v);
5312
 
                        }
5313
 
 
5314
 
                        v2 = v, v = BM_edge_other_vert(e, v);
5315
 
 
5316
 
                        e1 = e;
5317
 
                        e = get_other_edge(v, e);
5318
 
                        if (!e) {
5319
 
                                BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
5320
 
                                sv = sv_array + GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
5321
 
                                sv->v = v;
5322
 
                                sv->origvert = *v;
5323
 
                                sv->loop_nr = loop_nr;
5324
 
                                
5325
 
                                l = BM_face_other_edge_loop(l1->f, l1->e, v);
5326
 
                                sv->up = BM_edge_other_vert(l->e, v);
5327
 
                                sub_v3_v3v3(sv->upvec, BM_edge_other_vert(l->e, v)->co, v->co);
5328
 
 
5329
 
                                if (l2) {
5330
 
                                        l = BM_face_other_edge_loop(l2->f, l2->e, v);
5331
 
                                        sv->down = BM_edge_other_vert(l->e, v);
5332
 
                                        sub_v3_v3v3(sv->downvec, BM_edge_other_vert(l->e, v)->co, v->co);
5333
 
                                }
5334
 
 
5335
 
                                BM_elem_flag_disable(v, BM_ELEM_TAG);
5336
 
                                BM_elem_flag_disable(v2, BM_ELEM_TAG);
5337
 
 
5338
 
                                break;
5339
 
                        }
5340
 
 
5341
 
                        l1 = get_next_loop(v, l1, e1, e, vec);
5342
 
                        l2 = l2 ? get_next_loop(v, l2, e1, e, vec2) : NULL;
5343
 
 
5344
 
                        if (UNLIKELY(l1 == NULL && l2 != NULL)) {
5345
 
                                l1 = l2;
5346
 
                                l2 = NULL;
5347
 
                                swap_v3_v3(vec, vec2);
5348
 
                        }
5349
 
 
5350
 
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
5351
 
                        BM_elem_flag_disable(v2, BM_ELEM_TAG);
5352
 
                } while (e != v_first->e && l1);
5353
 
 
5354
 
                loop_nr++;
5355
 
        }
5356
 
 
5357
 
        /* EDBM_flag_disable_all(em, BM_ELEM_SELECT); */
5358
 
 
5359
 
        sld->sv = sv_array;
5360
 
        sld->totsv = sv_tot;
5361
 
        
5362
 
        /* find mouse vectors, the global one, and one per loop in case we have
5363
 
         * multiple loops selected, in case they are oriented different */
5364
 
        zero_v3(dir);
5365
 
        maxdist = -1.0f;
5366
 
 
5367
 
        loop_dir = MEM_callocN(sizeof(float) * 3 * loop_nr, "sv loop_dir");
5368
 
        loop_maxdist = MEM_callocN(sizeof(float) * loop_nr, "sv loop_maxdist");
5369
 
        for (j = 0; j < loop_nr; j++)
5370
 
                loop_maxdist[j] = -1.0f;
5371
 
 
5372
 
        BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
5373
 
                if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
5374
 
                        BMIter iter2;
5375
 
                        BMEdge *e2;
5376
 
                        float vec1[3], d;
5377
 
 
5378
 
                        /* search cross edges for visible edge to the mouse cursor,
5379
 
                         * then use the shared vertex to calculate screen vector*/
5380
 
                        for (i = 0; i < 2; i++) {
5381
 
                                v = i ? e->v1 : e->v2;
5382
 
                                BM_ITER_ELEM (e2, &iter2, v, BM_EDGES_OF_VERT) {
5383
 
                                        if (BM_elem_flag_test(e2, BM_ELEM_SELECT))
5384
 
                                                continue;
5385
 
 
5386
 
                                        /* This test is only relevant if object is not wire-drawn! See [#32068]. */
5387
 
                                        if (use_btree_disp && !BMBVH_EdgeVisible(btree, e2, ar, v3d, t->obedit)) {
5388
 
                                                continue;
5389
 
                                        }
5390
 
 
5391
 
                                        BLI_assert(BLI_smallhash_haskey(&table, (uintptr_t)v) != false);
5392
 
                                        j = GET_INT_FROM_POINTER(BLI_smallhash_lookup(&table, (uintptr_t)v));
5393
 
 
5394
 
                                        if (sv_array[j].down) {
5395
 
                                                ED_view3d_project_float_v3_m4(ar, sv_array[j].down->co, vec1, projectMat);
5396
 
                                        }
5397
 
                                        else {
5398
 
                                                add_v3_v3v3(vec1, v->co, sv_array[j].downvec);
5399
 
                                                ED_view3d_project_float_v3_m4(ar, vec1, vec1, projectMat);
5400
 
                                        }
5401
 
                                        
5402
 
                                        if (sv_array[j].up) {
5403
 
                                                ED_view3d_project_float_v3_m4(ar, sv_array[j].up->co, vec2, projectMat);
5404
 
                                        }
5405
 
                                        else {
5406
 
                                                add_v3_v3v3(vec2, v->co, sv_array[j].upvec);
5407
 
                                                ED_view3d_project_float_v3_m4(ar, vec2, vec2, projectMat);
5408
 
                                        }
5409
 
                                        
5410
 
                                        /* global direction */
5411
 
                                        d = dist_to_line_segment_v2(mval, vec1, vec2);
5412
 
                                        if (maxdist == -1.0f || d < maxdist) {
5413
 
                                                maxdist = d;
5414
 
                                                sub_v3_v3v3(dir, vec1, vec2);
5415
 
                                        }
5416
 
 
5417
 
                                        /* per loop direction */
5418
 
                                        l_nr = sv_array[j].loop_nr;
5419
 
                                        if (loop_maxdist[l_nr] == -1.0f || d < loop_maxdist[l_nr]) {
5420
 
                                                loop_maxdist[l_nr] = d;
5421
 
                                                sub_v3_v3v3(loop_dir[l_nr], vec1, vec2);
5422
 
                                        }
5423
 
                                }
5424
 
                        }
5425
 
                }
5426
 
        }
5427
 
 
5428
 
        bmesh_edit_begin(bm, BMO_OP_FLAG_UNTAN_MULTIRES);
5429
 
 
5430
 
        /*create copies of faces for customdata projection*/
5431
 
        sv_array = sld->sv;
5432
 
        for (i = 0; i < sld->totsv; i++, sv_array++) {
5433
 
                BMIter fiter, liter;
5434
 
                BMFace *f;
5435
 
                BMLoop *l;
5436
 
                
5437
 
                BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) {
5438
 
                        
5439
 
                        if (!BLI_smallhash_haskey(&sld->origfaces, (uintptr_t)f)) {
5440
 
                                BMFace *copyf = BM_face_copy(bm, f, TRUE, TRUE);
5441
 
                                
5442
 
                                BM_face_select_set(bm, copyf, FALSE);
5443
 
                                BM_elem_flag_enable(copyf, BM_ELEM_HIDDEN);
5444
 
                                BM_ITER_ELEM (l, &liter, copyf, BM_LOOPS_OF_FACE) {
5445
 
                                        BM_vert_select_set(bm, l->v, FALSE);
5446
 
                                        BM_elem_flag_enable(l->v, BM_ELEM_HIDDEN);
5447
 
                                        BM_edge_select_set(bm, l->e, FALSE);
5448
 
                                        BM_elem_flag_enable(l->e, BM_ELEM_HIDDEN);
5449
 
                                }
5450
 
 
5451
 
                                BLI_smallhash_insert(&sld->origfaces, (uintptr_t)f, copyf);
5452
 
                        }
5453
 
                }
5454
 
 
5455
 
                BLI_smallhash_insert(&sld->vhash, (uintptr_t)sv_array->v, sv_array);
5456
 
 
5457
 
                /* switch up/down if loop direction is different from global direction */
5458
 
                l_nr = sv_array->loop_nr;
5459
 
                if (dot_v3v3(loop_dir[l_nr], dir) < 0.0f) {
5460
 
                        swap_v3_v3(sv_array->upvec, sv_array->downvec);
5461
 
                        SWAP(BMVert, sv_array->vup, sv_array->vdown);
5462
 
                        SWAP(BMVert *, sv_array->up, sv_array->down);
5463
 
                }
5464
 
        }
5465
 
 
5466
 
        if (rv3d)
5467
 
                calcNonProportionalEdgeSlide(t, sld, mval);
5468
 
 
5469
 
        sld->origfaces_init = true;
5470
 
        sld->em = em;
5471
 
        
5472
 
        /*zero out start*/
5473
 
        zero_v3(start);
5474
 
 
5475
 
        /*dir holds a vector along edge loop*/
5476
 
        copy_v3_v3(end, dir);
5477
 
        mul_v3_fl(end, 0.5f);
5478
 
        
5479
 
        sld->start[0] = t->mval[0] + start[0];
5480
 
        sld->start[1] = t->mval[1] + start[1];
5481
 
 
5482
 
        sld->end[0] = t->mval[0] + end[0];
5483
 
        sld->end[1] = t->mval[1] + end[1];
5484
 
        
5485
 
        sld->perc = 0.0f;
5486
 
        
5487
 
        t->customData = sld;
5488
 
        
5489
 
        BLI_smallhash_release(&table);
5490
 
        if (btree) {
5491
 
                BMBVH_FreeBVH(btree);
5492
 
        }
5493
 
        MEM_freeN(loop_dir);
5494
 
        MEM_freeN(loop_maxdist);
5495
 
 
5496
 
        /* arrays are dirty from copying faces: EDBM_index_arrays_free */
5497
 
        EDBM_update_generic(em, FALSE, TRUE);
5498
 
 
5499
 
        return 1;
5500
 
}
5501
 
 
5502
 
void projectEdgeSlideData(TransInfo *t, bool is_final)
5503
 
{
5504
 
        EdgeSlideData *sld = t->customData;
5505
 
        TransDataEdgeSlideVert *sv;
5506
 
        BMEditMesh *em = sld->em;
5507
 
        SmallHash visit;
5508
 
        int i;
5509
 
 
5510
 
        if (!em)
5511
 
                return;
5512
 
        
5513
 
        if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
5514
 
                return;
5515
 
 
5516
 
        /* don't do this at all for non-basis shape keys, too easy to
5517
 
         * accidentally break uv maps or vertex colors then */
5518
 
        if (em->bm->shapenr > 1)
5519
 
                return;
5520
 
 
5521
 
        BLI_smallhash_init(&visit);
5522
 
        
5523
 
        for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
5524
 
                BMIter fiter;
5525
 
                BMFace *f;
5526
 
 
5527
 
                /* BMESH_TODO, this interpolates between vertex/loops which are not moved
5528
 
                 * (are only apart of a face attached to a slide vert), couldn't we iterate BM_LOOPS_OF_VERT
5529
 
                 * here and only interpolate those? */
5530
 
                BM_ITER_ELEM (f, &fiter, sv->v, BM_FACES_OF_VERT) {
5531
 
                        BMIter liter;
5532
 
                        BMLoop *l;
5533
 
 
5534
 
                        BMFace *f_copy;      /* the copy of 'f' */
5535
 
                        BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
5536
 
 
5537
 
                        char is_sel, is_hide;
5538
 
 
5539
 
                        
5540
 
                        if (BLI_smallhash_haskey(&visit, (uintptr_t)f))
5541
 
                                continue;
5542
 
                        
5543
 
                        BLI_smallhash_insert(&visit, (uintptr_t)f, NULL);
5544
 
                        
5545
 
                        /* the face attributes of the copied face will get
5546
 
                         * copied over, so its necessary to save the selection
5547
 
                         * and hidden state*/
5548
 
                        is_sel = BM_elem_flag_test(f, BM_ELEM_SELECT);
5549
 
                        is_hide = BM_elem_flag_test(f, BM_ELEM_HIDDEN);
5550
 
                        
5551
 
                        f_copy = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)f);
5552
 
                        
5553
 
                        /* project onto copied projection face */
5554
 
                        BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
5555
 
                                /* only affected verts will get interpolated */
5556
 
                                char affected = FALSE;
5557
 
                                f_copy_flip = f_copy;
5558
 
 
5559
 
                                if (BM_elem_flag_test(l->e, BM_ELEM_SELECT) || BM_elem_flag_test(l->prev->e, BM_ELEM_SELECT)) {
5560
 
                                        /* the loop is attached of the selected edges that are sliding */
5561
 
                                        BMLoop *l_ed_sel = l;
5562
 
                                        
5563
 
                                        if (!BM_elem_flag_test(l->e, BM_ELEM_SELECT))
5564
 
                                                l_ed_sel = l_ed_sel->prev;
5565
 
                                        
5566
 
                                        if (sld->perc < 0.0f) {
5567
 
                                                if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->down)) {
5568
 
                                                        f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l_ed_sel->radial_next->f);
5569
 
                                                }
5570
 
                                        }
5571
 
                                        else if (sld->perc > 0.0f) {
5572
 
                                                if (BM_vert_in_face(l_ed_sel->radial_next->f, sv->up)) {
5573
 
                                                        f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)l_ed_sel->radial_next->f);
5574
 
                                                }
5575
 
                                        }
5576
 
 
5577
 
                                        BLI_assert(f_copy_flip != NULL);
5578
 
                                        if (!f_copy_flip) {
5579
 
                                                continue;  /* shouldn't happen, but protection */
5580
 
                                        }
5581
 
 
5582
 
                                        affected = TRUE;
5583
 
                                }
5584
 
                                else {
5585
 
                                        /* the loop is attached to only one vertex and not a selected edge,
5586
 
                                         * this means we have to find a selected edges face going in the right direction
5587
 
                                         * to copy from else we get bad distortion see: [#31080] */
5588
 
                                        BMIter eiter;
5589
 
                                        BMEdge *e_sel;
5590
 
 
5591
 
                                        BM_ITER_ELEM (e_sel, &eiter, l->v, BM_EDGES_OF_VERT) {
5592
 
                                                if (BM_elem_flag_test(e_sel, BM_ELEM_SELECT)) {
5593
 
                                                        break;
5594
 
                                                }
5595
 
                                        }
5596
 
 
5597
 
                                        if (e_sel) {
5598
 
                                                /* warning if the UV's are not contiguous, this will copy from the _wrong_ UVs
5599
 
                                                 * in fact whenever the face being copied is not 'f_copy' this can happen,
5600
 
                                                 * we could be a lot smarter about this but would need to deal with every UV channel or
5601
 
                                                 * add a way to mask out lauers when calling #BM_loop_interp_from_face() */
5602
 
                                                if (sld->perc < 0.0f) {
5603
 
                                                        if (BM_vert_in_face(e_sel->l->f, sv->down)) {
5604
 
                                                                f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
5605
 
                                                        }
5606
 
                                                        else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->down)) {
5607
 
                                                                f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f);
5608
 
                                                        }
5609
 
 
5610
 
                                                }
5611
 
                                                else if (sld->perc > 0.0f) {
5612
 
                                                        if (BM_vert_in_face(e_sel->l->f, sv->up)) {
5613
 
                                                                f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->f);
5614
 
                                                        }
5615
 
                                                        else if (BM_vert_in_face(e_sel->l->radial_next->f, sv->up)) {
5616
 
                                                                f_copy_flip = BLI_smallhash_lookup(&sld->origfaces, (uintptr_t)e_sel->l->radial_next->f);
5617
 
                                                        }
5618
 
                                                }
5619
 
 
5620
 
                                                affected = TRUE;
5621
 
                                        }
5622
 
 
5623
 
                                }
5624
 
 
5625
 
                                if (!affected)
5626
 
                                        continue;
5627
 
 
5628
 
                                /* only loop data, no vertex data since that contains shape keys,
5629
 
                                 * and we do not want to mess up other shape keys */
5630
 
                                BM_loop_interp_from_face(em->bm, l, f_copy_flip, FALSE, FALSE);
5631
 
 
5632
 
                                if (is_final) {
5633
 
                                        BM_loop_interp_multires(em->bm, l, f_copy_flip);
5634
 
                                        if (f_copy != f_copy_flip) {
5635
 
                                                BM_loop_interp_multires(em->bm, l, f_copy);
5636
 
                                        }
5637
 
                                }
5638
 
                        }
5639
 
                        
5640
 
                        /* make sure face-attributes are correct (e.g. MTexPoly) */
5641
 
                        BM_elem_attrs_copy(em->bm, em->bm, f_copy, f);
5642
 
                        
5643
 
                        /* restore selection and hidden flags */
5644
 
                        BM_face_select_set(em->bm, f, is_sel);
5645
 
                        if (!is_hide) {
5646
 
                                /* this check is a workaround for bug, see note - [#30735],
5647
 
                                 * without this edge can be hidden and selected */
5648
 
                                BM_elem_hide_set(em->bm, f, is_hide);
5649
 
                        }
5650
 
                }
5651
 
        }
5652
 
 
5653
 
        BLI_smallhash_release(&visit);
5654
 
}
5655
 
 
5656
 
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
5657
 
{
5658
 
        if (sld->origfaces_init) {
5659
 
                SmallHashIter hiter;
5660
 
                BMFace *copyf;
5661
 
 
5662
 
                copyf = BLI_smallhash_iternew(&sld->origfaces, &hiter, NULL);
5663
 
                for (; copyf; copyf = BLI_smallhash_iternext(&hiter, NULL)) {
5664
 
                        BM_face_verts_kill(sld->em->bm, copyf);
5665
 
                }
5666
 
 
5667
 
                BLI_smallhash_release(&sld->origfaces);
5668
 
 
5669
 
                sld->origfaces_init = false;
5670
 
 
5671
 
                /* arrays are dirty from removing faces: EDBM_index_arrays_free */
5672
 
                EDBM_update_generic(sld->em, FALSE, TRUE);
5673
 
        }
5674
 
}
5675
 
 
5676
 
 
5677
 
void freeEdgeSlideVerts(TransInfo *t)
5678
 
{
5679
 
        EdgeSlideData *sld = t->customData;
5680
 
        
5681
 
#if 0 /*BMESH_TODO*/
5682
 
        if (me->drawflag & ME_DRAWEXTRA_EDGELEN) {
5683
 
                TransDataEdgeSlideVert *sv;
5684
 
                LinkNode *look = sld->vertlist;
5685
 
                GHash *vertgh = sld->vhash;
5686
 
                while (look) {
5687
 
                        sv  = BLI_ghash_lookup(vertgh, (EditVert *)look->link);
5688
 
                        if (sv != NULL) {
5689
 
                                sv->up->f &= !SELECT;
5690
 
                                sv->down->f &= !SELECT;
5691
 
                        }
5692
 
                        look = look->next;
5693
 
                }
5694
 
        }
5695
 
#endif
5696
 
        
5697
 
        if (!sld)
5698
 
                return;
5699
 
        
5700
 
        freeEdgeSlideTempFaces(sld);
5701
 
 
5702
 
        bmesh_edit_end(sld->em->bm, BMO_OP_FLAG_UNTAN_MULTIRES);
5703
 
 
5704
 
        BLI_smallhash_release(&sld->vhash);
5705
 
        
5706
 
        MEM_freeN(sld->sv);
5707
 
        MEM_freeN(sld);
5708
 
        
5709
 
        t->customData = NULL;
5710
 
        
5711
 
        recalcData(t);
5712
 
}
5713
 
 
5714
 
void initEdgeSlide(TransInfo *t)
5715
 
{
5716
 
        EdgeSlideData *sld;
5717
 
 
5718
 
        t->mode = TFM_EDGE_SLIDE;
5719
 
        t->transform = EdgeSlide;
5720
 
        t->handleEvent = handleEventEdgeSlide;
5721
 
 
5722
 
        if (!createEdgeSlideVerts(t)) {
5723
 
                t->state = TRANS_CANCEL;
5724
 
                return;
5725
 
        }
5726
 
        
5727
 
        sld = t->customData;
5728
 
 
5729
 
        if (!sld)
5730
 
                return;
5731
 
 
5732
 
        t->customFree = freeEdgeSlideVerts;
5733
 
 
5734
 
        /* set custom point first if you want value to be initialized by init */
5735
 
        setCustomPoints(t, &t->mouse, sld->end, sld->start);
5736
 
        initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO_FLIP);
5737
 
        
5738
 
        t->idx_max = 0;
5739
 
        t->num.idx_max = 0;
5740
 
        t->snap[0] = 0.0f;
5741
 
        t->snap[1] = 0.1f;
5742
 
        t->snap[2] = t->snap[1] * 0.1f;
5743
 
 
5744
 
        t->num.increment = t->snap[1];
5745
 
 
5746
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
5747
 
}
5748
 
 
5749
 
int handleEventEdgeSlide(struct TransInfo *t, struct wmEvent *event)
5750
 
{
5751
 
        if (t->mode == TFM_EDGE_SLIDE) {
5752
 
                EdgeSlideData *sld = t->customData;
5753
 
 
5754
 
                if (sld) {
5755
 
                        switch (event->type) {
5756
 
                                case EKEY:
5757
 
                                        if (event->val == KM_PRESS) {
5758
 
                                                sld->is_proportional = !sld->is_proportional;
5759
 
                                                return 1;
5760
 
                                        }
5761
 
                                        break;
5762
 
                                case FKEY:
5763
 
                                {
5764
 
                                        if (event->val == KM_PRESS) {
5765
 
                                                if (sld->is_proportional == FALSE) {
5766
 
                                                        sld->flipped_vtx = !sld->flipped_vtx;
5767
 
                                                }
5768
 
                                                return 1;
5769
 
                                        }
5770
 
                                        break;
5771
 
                                }
5772
 
                                case EVT_MODAL_MAP:
5773
 
                                {
5774
 
                                        switch (event->val) {
5775
 
                                                case TFM_MODAL_EDGESLIDE_DOWN:
5776
 
                                                {
5777
 
                                                        sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
5778
 
                                                        break;
5779
 
                                                }
5780
 
                                                case TFM_MODAL_EDGESLIDE_UP:
5781
 
                                                {
5782
 
                                                        sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
5783
 
                                                        break;
5784
 
                                                }
5785
 
                                        }
5786
 
                                }
5787
 
                                default:
5788
 
                                        break;
5789
 
                        }
5790
 
                }
5791
 
        }
5792
 
        return 0;
5793
 
}
5794
 
 
5795
 
void drawEdgeSlide(const struct bContext *C, TransInfo *t)
5796
 
{
5797
 
        if (t->mode == TFM_EDGE_SLIDE) {
5798
 
                EdgeSlideData *sld = (EdgeSlideData *)t->customData;
5799
 
                /* Non-Prop mode */
5800
 
                if (sld && sld->is_proportional == FALSE) {
5801
 
                        View3D *v3d = CTX_wm_view3d(C);
5802
 
                        float marker[3];
5803
 
                        float v1[3], v2[3];
5804
 
                        float interp_v;
5805
 
                        TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
5806
 
                        const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
5807
 
                        const float guide_size = ctrl_size - 0.5f;
5808
 
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
5809
 
                        const int alpha_shade = -30;
5810
 
 
5811
 
                        add_v3_v3v3(v1, curr_sv->origvert.co, curr_sv->upvec);
5812
 
                        add_v3_v3v3(v2, curr_sv->origvert.co, curr_sv->downvec);
5813
 
 
5814
 
                        interp_v = (sld->perc + 1.0f) / 2.0f;
5815
 
                        interp_v3_v3v3(marker, v2, v1, interp_v);
5816
 
 
5817
 
                        if (v3d && v3d->zbuf)
5818
 
                                glDisable(GL_DEPTH_TEST);
5819
 
 
5820
 
                        glEnable(GL_BLEND);
5821
 
                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5822
 
 
5823
 
                        glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
5824
 
                        glPushMatrix();
5825
 
 
5826
 
                        glMultMatrixf(t->obedit->obmat);
5827
 
 
5828
 
                        glLineWidth(line_size);
5829
 
                        UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
5830
 
                        glBegin(GL_LINES);
5831
 
                        glVertex3fv(curr_sv->up->co);
5832
 
                        glVertex3fv(curr_sv->origvert.co);
5833
 
                        glVertex3fv(curr_sv->down->co);
5834
 
                        glVertex3fv(curr_sv->origvert.co);
5835
 
                        bglEnd();
5836
 
 
5837
 
 
5838
 
                        UI_ThemeColorShadeAlpha(TH_SELECT, -30, alpha_shade);
5839
 
                        glPointSize(ctrl_size);
5840
 
                        if (sld->flipped_vtx) {
5841
 
                                bglBegin(GL_POINTS);
5842
 
                                bglVertex3fv(curr_sv->down->co);
5843
 
                                bglEnd();
5844
 
                        }
5845
 
                        else {
5846
 
                                bglBegin(GL_POINTS);
5847
 
                                bglVertex3fv(curr_sv->up->co);
5848
 
                                bglEnd();
5849
 
                        }
5850
 
 
5851
 
                        UI_ThemeColorShadeAlpha(TH_SELECT, 255, alpha_shade);
5852
 
                        glPointSize(guide_size);
5853
 
                        bglBegin(GL_POINTS);
5854
 
                        bglVertex3fv(marker);
5855
 
                        bglEnd();
5856
 
 
5857
 
 
5858
 
                        glPopMatrix();
5859
 
                        glPopAttrib();
5860
 
 
5861
 
                        glDisable(GL_BLEND);
5862
 
 
5863
 
                        if (v3d && v3d->zbuf)
5864
 
                                glEnable(GL_DEPTH_TEST);
5865
 
                }
5866
 
        }
5867
 
}
5868
 
 
5869
 
static int doEdgeSlide(TransInfo *t, float perc)
5870
 
{
5871
 
        EdgeSlideData *sld = t->customData;
5872
 
        TransDataEdgeSlideVert *svlist = sld->sv, *sv;
5873
 
        int i;
5874
 
 
5875
 
        sld->perc = perc;
5876
 
        sv = svlist;
5877
 
 
5878
 
        if (sld->is_proportional == TRUE) {
5879
 
                for (i = 0; i < sld->totsv; i++, sv++) {
5880
 
                        float vec[3];
5881
 
                        if (perc > 0.0f) {
5882
 
                                copy_v3_v3(vec, sv->upvec);
5883
 
                                mul_v3_fl(vec, perc);
5884
 
                                add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
5885
 
                        }
5886
 
                        else {
5887
 
                                copy_v3_v3(vec, sv->downvec);
5888
 
                                mul_v3_fl(vec, -perc);
5889
 
                                add_v3_v3v3(sv->v->co, sv->origvert.co, vec);
5890
 
                        }
5891
 
                }
5892
 
        }
5893
 
        else {
5894
 
                /**
5895
 
                 * Implementation note, non proportional mode ignores the starting positions and uses only the
5896
 
                 * up/down verts, this could be changed/improved so the distance is still met but the verts are moved along
5897
 
                 * their original path (which may not be straight), however how it works now is OK and matches 2.4x - Campbell
5898
 
                 *
5899
 
                 * \note len_v3v3(curr_sv->upvec, curr_sv->downvec)
5900
 
                 * is the same as the distance between the original vert locations, same goes for the lines below.
5901
 
                 */
5902
 
                TransDataEdgeSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
5903
 
                const float curr_length_perc = curr_sv->edge_len * (((sld->flipped_vtx ? perc : -perc) + 1.0f) / 2.0f);
5904
 
 
5905
 
                float down_co[3];
5906
 
                float up_co[3];
5907
 
 
5908
 
                for (i = 0; i < sld->totsv; i++, sv++) {
5909
 
                        if (sv->edge_len > FLT_EPSILON) {
5910
 
                                const float fac = min_ff(sv->edge_len, curr_length_perc) / sv->edge_len;
5911
 
 
5912
 
                                add_v3_v3v3(up_co, sv->origvert.co, sv->upvec);
5913
 
                                add_v3_v3v3(down_co, sv->origvert.co, sv->downvec);
5914
 
 
5915
 
                                if (sld->flipped_vtx) {
5916
 
                                        interp_v3_v3v3(sv->v->co, down_co, up_co, fac);
5917
 
                                }
5918
 
                                else {
5919
 
                                        interp_v3_v3v3(sv->v->co, up_co, down_co, fac);
5920
 
                                }
5921
 
                        }
5922
 
                }
5923
 
        }
5924
 
        
5925
 
        projectEdgeSlideData(t, 0);
5926
 
        
5927
 
        return 1;
5928
 
}
5929
 
 
5930
 
int EdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
5931
 
{
5932
 
        char str[128];
5933
 
        float final;
5934
 
        EdgeSlideData *sld =  t->customData;
5935
 
        bool flipped = sld->flipped_vtx;
5936
 
        bool is_proportional = sld->is_proportional;
5937
 
 
5938
 
        final = t->values[0];
5939
 
 
5940
 
        snapGrid(t, &final);
5941
 
 
5942
 
        /* only do this so out of range values are not displayed */
5943
 
        CLAMP(final, -1.0f, 1.0f);
5944
 
 
5945
 
        if (hasNumInput(&t->num)) {
5946
 
                char c[NUM_STR_REP_LEN];
5947
 
 
5948
 
                applyNumInput(&t->num, &final);
5949
 
 
5950
 
                outputNumInput(&(t->num), c);
5951
 
 
5952
 
                BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %s (E)ven: %s, (F)lipped: %s"),
5953
 
                             &c[0], !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
5954
 
        }
5955
 
        else {
5956
 
                BLI_snprintf(str, sizeof(str), IFACE_("Edge Slide: %.4f (E)ven: %s, (F)lipped: %s"),
5957
 
                             final, !is_proportional ? IFACE_("ON") : IFACE_("OFF"), flipped ? IFACE_("ON") : IFACE_("OFF"));
5958
 
        }
5959
 
 
5960
 
        CLAMP(final, -1.0f, 1.0f);
5961
 
 
5962
 
        t->values[0] = final;
5963
 
 
5964
 
        /*do stuff here*/
5965
 
        if (t->customData)
5966
 
                doEdgeSlide(t, final);
5967
 
        else {
5968
 
                strcpy(str, IFACE_("Invalid Edge Selection"));
5969
 
                t->state = TRANS_CANCEL;
5970
 
        }
5971
 
 
5972
 
        recalcData(t);
5973
 
 
5974
 
        ED_area_headerprint(t->sa, str);
5975
 
 
5976
 
        return 1;
5977
 
}
5978
 
 
5979
 
 
5980
 
/* ******************** Vert Slide *************** */
5981
 
static void calcVertSlideCustomPoints(struct TransInfo *t)
5982
 
{
5983
 
        VertSlideData *sld = t->customData;
5984
 
        TransDataVertSlideVert *sv = &sld->sv[sld->curr_sv_index];
5985
 
        float *co_orig = sv->co_orig_2d;
5986
 
        float *co_curr = sv->co_link_orig_2d[sv->co_link_curr];
5987
 
        const int start[2] = {co_orig[0], co_orig[1]};
5988
 
        const int end[2]   = {co_curr[0], co_curr[1]};
5989
 
 
5990
 
        if (sld->flipped_vtx && sld->is_proportional == false) {
5991
 
                setCustomPoints(t, &t->mouse, start, end);
5992
 
        }
5993
 
        else {
5994
 
                setCustomPoints(t, &t->mouse, end, start);
5995
 
        }
5996
 
}
5997
 
 
5998
 
/**
5999
 
 * Run once when initializing vert slide to find the reference edge
6000
 
 */
6001
 
static void calcVertSlideMouseActiveVert(struct TransInfo *t, const int mval[2])
6002
 
{
6003
 
        VertSlideData *sld = t->customData;
6004
 
        float mval_fl[2] = {UNPACK2(mval)};
6005
 
        TransDataVertSlideVert *sv;
6006
 
 
6007
 
        /* set the vertex to use as a reference for the mouse direction 'curr_sv_index' */
6008
 
        float dist = 0.0f;
6009
 
        float min_dist = FLT_MAX;
6010
 
        int i;
6011
 
 
6012
 
        for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
6013
 
                dist = len_squared_v2v2(mval_fl, sv->co_orig_2d);
6014
 
                if (dist < min_dist) {
6015
 
                        min_dist = dist;
6016
 
                        sld->curr_sv_index = i;
6017
 
                }
6018
 
        }
6019
 
}
6020
 
/**
6021
 
 * Run while moving the mouse to slide along the edge matching the mouse direction
6022
 
 */
6023
 
static void calcVertSlideMouseActiveEdges(struct TransInfo *t, const int mval[2])
6024
 
{
6025
 
        VertSlideData *sld = t->customData;
6026
 
        float mval_fl[2] = {UNPACK2(mval)};
6027
 
 
6028
 
        float dir[2];
6029
 
        TransDataVertSlideVert *sv;
6030
 
        int i;
6031
 
 
6032
 
        /* first get the direction of the original vertex */
6033
 
        sub_v2_v2v2(dir, sld->sv[sld->curr_sv_index].co_orig_2d, mval_fl);
6034
 
        normalize_v2(dir);
6035
 
 
6036
 
        for (i = 0, sv = sld->sv; i < sld->totsv; i++, sv++) {
6037
 
                if (sv->co_link_tot > 1) {
6038
 
                        float dir_dot_best = -FLT_MAX;
6039
 
                        int co_link_curr_best = -1;
6040
 
                        int j;
6041
 
 
6042
 
                        for (j = 0; j < sv->co_link_tot; j++) {
6043
 
                                float tdir[2];
6044
 
                                float dir_dot;
6045
 
                                sub_v2_v2v2(tdir, sv->co_orig_2d, sv->co_link_orig_2d[j]);
6046
 
                                normalize_v2(tdir);
6047
 
                                dir_dot = dot_v2v2(dir, tdir);
6048
 
                                if (dir_dot > dir_dot_best) {
6049
 
                                        dir_dot_best = dir_dot;
6050
 
                                        co_link_curr_best = j;
6051
 
                                }
6052
 
                        }
6053
 
 
6054
 
                        if (co_link_curr_best != -1) {
6055
 
                                sv->co_link_curr = co_link_curr_best;
6056
 
                        }
6057
 
                }
6058
 
        }
6059
 
}
6060
 
 
6061
 
static int createVertSlideVerts(TransInfo *t)
6062
 
{
6063
 
        BMEditMesh *em = BMEdit_FromObject(t->obedit);
6064
 
        BMesh *bm = em->bm;
6065
 
        BMIter iter;
6066
 
        BMIter eiter;
6067
 
        BMEdge *e;
6068
 
        BMVert *v;
6069
 
        TransDataVertSlideVert *sv_array;
6070
 
        VertSlideData *sld = MEM_callocN(sizeof(*sld), "sld");
6071
 
//      View3D *v3d = NULL;
6072
 
        RegionView3D *rv3d = NULL;
6073
 
        ARegion *ar = t->ar;
6074
 
        float projectMat[4][4];
6075
 
        int j;
6076
 
 
6077
 
        if (t->spacetype == SPACE_VIEW3D) {
6078
 
                /* background mode support */
6079
 
//              v3d = t->sa ? t->sa->spacedata.first : NULL;
6080
 
                rv3d = ar ? ar->regiondata : NULL;
6081
 
        }
6082
 
 
6083
 
        sld->is_proportional = true;
6084
 
        sld->curr_sv_index = 0;
6085
 
        sld->flipped_vtx = false;
6086
 
 
6087
 
        if (!rv3d) {
6088
 
                /* ok, let's try to survive this */
6089
 
                unit_m4(projectMat);
6090
 
        }
6091
 
        else {
6092
 
                ED_view3d_ob_project_mat_get(rv3d, t->obedit, projectMat);
6093
 
        }
6094
 
 
6095
 
        j = 0;
6096
 
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
6097
 
                bool ok = false;
6098
 
                if (BM_elem_flag_test(v, BM_ELEM_SELECT) && v->e) {
6099
 
                        BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
6100
 
                                if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
6101
 
                                        ok = true;
6102
 
                                        break;
6103
 
                                }
6104
 
                        }
6105
 
                }
6106
 
 
6107
 
                if (ok) {
6108
 
                        BM_elem_flag_enable(v, BM_ELEM_TAG);
6109
 
                        j += 1;
6110
 
                }
6111
 
                else {
6112
 
                        BM_elem_flag_disable(v, BM_ELEM_TAG);
6113
 
                }
6114
 
        }
6115
 
 
6116
 
        if (!j) {
6117
 
                MEM_freeN(sld);
6118
 
                return 0;
6119
 
        }
6120
 
 
6121
 
        sv_array = MEM_callocN(sizeof(TransDataVertSlideVert) * j, "sv_array");
6122
 
 
6123
 
        j = 0;
6124
 
        BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
6125
 
                if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
6126
 
                        int k;
6127
 
                        sv_array[j].v = v;
6128
 
                        copy_v3_v3(sv_array[j].co_orig_3d, v->co);
6129
 
 
6130
 
                        k = 0;
6131
 
                        BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
6132
 
                                if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
6133
 
                                        k++;
6134
 
                                }
6135
 
                        }
6136
 
 
6137
 
                        sv_array[j].co_link_orig_3d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_3d) * k, __func__);
6138
 
                        sv_array[j].co_link_orig_2d = MEM_mallocN(sizeof(*sv_array[j].co_link_orig_2d) * k, __func__);
6139
 
                        sv_array[j].co_link_tot = k;
6140
 
 
6141
 
                        k = 0;
6142
 
                        BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
6143
 
                                if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
6144
 
                                        BMVert *v_other = BM_edge_other_vert(e, v);
6145
 
                                        copy_v3_v3(sv_array[j].co_link_orig_3d[k], v_other->co);
6146
 
                                        if (ar) {
6147
 
                                                ED_view3d_project_float_v2_m4(ar,
6148
 
                                                                              sv_array[j].co_link_orig_3d[k],
6149
 
                                                                              sv_array[j].co_link_orig_2d[k],
6150
 
                                                                              projectMat);
6151
 
                                        }
6152
 
                                        else {
6153
 
                                                copy_v2_v2(sv_array[j].co_link_orig_2d[k],
6154
 
                                                           sv_array[j].co_link_orig_3d[k]);
6155
 
                                        }
6156
 
                                        k++;
6157
 
                                }
6158
 
                        }
6159
 
 
6160
 
                        if (ar) {
6161
 
                                ED_view3d_project_float_v2_m4(ar,
6162
 
                                                              sv_array[j].co_orig_3d,
6163
 
                                                              sv_array[j].co_orig_2d,
6164
 
                                                              projectMat);
6165
 
                        }
6166
 
                        else {
6167
 
                                copy_v2_v2(sv_array[j].co_orig_2d,
6168
 
                                           sv_array[j].co_orig_3d);
6169
 
                        }
6170
 
 
6171
 
                        j++;
6172
 
                }
6173
 
        }
6174
 
 
6175
 
        sld->sv = sv_array;
6176
 
        sld->totsv = j;
6177
 
 
6178
 
        sld->em = em;
6179
 
 
6180
 
        sld->perc = 0.0f;
6181
 
 
6182
 
        t->customData = sld;
6183
 
 
6184
 
        if (rv3d) {
6185
 
                calcVertSlideMouseActiveVert(t, t->mval);
6186
 
                calcVertSlideMouseActiveEdges(t, t->mval);
6187
 
        }
6188
 
 
6189
 
        return 1;
6190
 
}
6191
 
 
6192
 
void freeVertSlideVerts(TransInfo *t)
6193
 
{
6194
 
        VertSlideData *sld = t->customData;
6195
 
 
6196
 
        if (!sld)
6197
 
                return;
6198
 
 
6199
 
 
6200
 
        if (sld->totsv > 0) {
6201
 
                TransDataVertSlideVert *sv = sld->sv;
6202
 
                int i = 0;
6203
 
                for (i = 0; i < sld->totsv; i++, sv++) {
6204
 
                        MEM_freeN(sv->co_link_orig_2d);
6205
 
                        MEM_freeN(sv->co_link_orig_3d);
6206
 
                }
6207
 
        }
6208
 
 
6209
 
        MEM_freeN(sld->sv);
6210
 
        MEM_freeN(sld);
6211
 
 
6212
 
        t->customData = NULL;
6213
 
 
6214
 
        recalcData(t);
6215
 
}
6216
 
 
6217
 
void initVertSlide(TransInfo *t)
6218
 
{
6219
 
        VertSlideData *sld;
6220
 
 
6221
 
        t->mode = TFM_VERT_SLIDE;
6222
 
        t->transform = VertSlide;
6223
 
        t->handleEvent = handleEventVertSlide;
6224
 
 
6225
 
        if (!createVertSlideVerts(t)) {
6226
 
                t->state = TRANS_CANCEL;
6227
 
                return;
6228
 
        }
6229
 
 
6230
 
        sld = t->customData;
6231
 
 
6232
 
        if (!sld)
6233
 
                return;
6234
 
 
6235
 
        t->customFree = freeVertSlideVerts;
6236
 
 
6237
 
        /* set custom point first if you want value to be initialized by init */
6238
 
        calcVertSlideCustomPoints(t);
6239
 
        initMouseInputMode(t, &t->mouse, INPUT_CUSTOM_RATIO);
6240
 
 
6241
 
        t->idx_max = 0;
6242
 
        t->num.idx_max = 0;
6243
 
        t->snap[0] = 0.0f;
6244
 
        t->snap[1] = 0.1f;
6245
 
        t->snap[2] = t->snap[1] * 0.1f;
6246
 
 
6247
 
        t->num.increment = t->snap[1];
6248
 
 
6249
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
6250
 
}
6251
 
 
6252
 
int handleEventVertSlide(struct TransInfo *t, struct wmEvent *event)
6253
 
{
6254
 
        if (t->mode == TFM_VERT_SLIDE) {
6255
 
                VertSlideData *sld = t->customData;
6256
 
 
6257
 
                if (sld) {
6258
 
                        switch (event->type) {
6259
 
                                case EKEY:
6260
 
                                        if (event->val == KM_PRESS) {
6261
 
                                                sld->is_proportional = !sld->is_proportional;
6262
 
                                                if (sld->flipped_vtx) {
6263
 
                                                        calcVertSlideCustomPoints(t);
6264
 
                                                }
6265
 
                                                return 1;
6266
 
                                        }
6267
 
                                        break;
6268
 
                                case FKEY:
6269
 
                                {
6270
 
                                        if (event->val == KM_PRESS) {
6271
 
                                                sld->flipped_vtx = !sld->flipped_vtx;
6272
 
                                                calcVertSlideCustomPoints(t);
6273
 
                                                return 1;
6274
 
                                        }
6275
 
                                        break;
6276
 
                                }
6277
 
                                case CKEY:
6278
 
                                {
6279
 
                                        /* use like a modifier key */
6280
 
                                        if (event->val == KM_PRESS) {
6281
 
                                                t->flag ^= T_ALT_TRANSFORM;
6282
 
                                                calcVertSlideCustomPoints(t);
6283
 
                                                return 1;
6284
 
                                        }
6285
 
                                        break;
6286
 
                                }
6287
 
#if 0
6288
 
                                case EVT_MODAL_MAP:
6289
 
                                {
6290
 
                                        switch (event->val) {
6291
 
                                                case TFM_MODAL_EDGESLIDE_DOWN:
6292
 
                                                {
6293
 
                                                        sld->curr_sv_index = ((sld->curr_sv_index - 1) + sld->totsv) % sld->totsv;
6294
 
                                                        break;
6295
 
                                                }
6296
 
                                                case TFM_MODAL_EDGESLIDE_UP:
6297
 
                                                {
6298
 
                                                        sld->curr_sv_index = (sld->curr_sv_index + 1) % sld->totsv;
6299
 
                                                        break;
6300
 
                                                }
6301
 
                                        }
6302
 
                                }
6303
 
#endif
6304
 
                                case MOUSEMOVE:
6305
 
                                {
6306
 
                                        /* don't recalculat the best edge */
6307
 
                                        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
6308
 
                                        if (is_clamp) {
6309
 
                                                calcVertSlideMouseActiveEdges(t, event->mval);
6310
 
                                        }
6311
 
                                        calcVertSlideCustomPoints(t);
6312
 
                                }
6313
 
                                default:
6314
 
                                        break;
6315
 
                        }
6316
 
                }
6317
 
        }
6318
 
        return 0;
6319
 
}
6320
 
 
6321
 
static void drawVertSlide(const struct bContext *C, TransInfo *t)
6322
 
{
6323
 
        if (t->mode == TFM_VERT_SLIDE) {
6324
 
                VertSlideData *sld = (VertSlideData *)t->customData;
6325
 
                /* Non-Prop mode */
6326
 
                if (sld) {
6327
 
                        View3D *v3d = CTX_wm_view3d(C);
6328
 
                        TransDataVertSlideVert *curr_sv = &sld->sv[sld->curr_sv_index];
6329
 
                        TransDataVertSlideVert *sv;
6330
 
                        const float ctrl_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) + 1.5f;
6331
 
                        const float line_size = UI_GetThemeValuef(TH_OUTLINE_WIDTH) + 0.5f;
6332
 
                        const int alpha_shade = -30;
6333
 
                        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
6334
 
                        int i;
6335
 
 
6336
 
                        if (v3d && v3d->zbuf)
6337
 
                                glDisable(GL_DEPTH_TEST);
6338
 
 
6339
 
                        glEnable(GL_BLEND);
6340
 
                        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6341
 
 
6342
 
                        glPushAttrib(GL_CURRENT_BIT | GL_LINE_BIT | GL_POINT_BIT);
6343
 
                        glPushMatrix();
6344
 
 
6345
 
                        glMultMatrixf(t->obedit->obmat);
6346
 
 
6347
 
                        glLineWidth(line_size);
6348
 
                        UI_ThemeColorShadeAlpha(TH_EDGE_SELECT, 80, alpha_shade);
6349
 
                        glBegin(GL_LINES);
6350
 
                        if (is_clamp) {
6351
 
                                sv = sld->sv;
6352
 
                                for (i = 0; i < sld->totsv; i++, sv++) {
6353
 
                                        glVertex3fv(sv->co_orig_3d);
6354
 
                                        glVertex3fv(sv->co_link_orig_3d[sv->co_link_curr]);
6355
 
                                }
6356
 
                        }
6357
 
                        else {
6358
 
                                sv = sld->sv;
6359
 
                                for (i = 0; i < sld->totsv; i++, sv++) {
6360
 
                                        float a[3], b[3];
6361
 
                                        sub_v3_v3v3(a, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
6362
 
                                        mul_v3_fl(a, 100.0f);
6363
 
                                        negate_v3_v3(b, a);
6364
 
                                        add_v3_v3(a, sv->co_orig_3d);
6365
 
                                        add_v3_v3(b, sv->co_orig_3d);
6366
 
 
6367
 
                                        glVertex3fv(a);
6368
 
                                        glVertex3fv(b);
6369
 
                                }
6370
 
                        }
6371
 
                        bglEnd();
6372
 
 
6373
 
                        glPointSize(ctrl_size);
6374
 
 
6375
 
                        bglBegin(GL_POINTS);
6376
 
                        bglVertex3fv((sld->flipped_vtx && sld->is_proportional == FALSE) ?
6377
 
                                     curr_sv->co_link_orig_3d[curr_sv->co_link_curr] :
6378
 
                                     curr_sv->co_orig_3d);
6379
 
                        bglEnd();
6380
 
 
6381
 
                        glPopMatrix();
6382
 
                        glPopAttrib();
6383
 
 
6384
 
                        glDisable(GL_BLEND);
6385
 
 
6386
 
                        if (v3d && v3d->zbuf)
6387
 
                                glEnable(GL_DEPTH_TEST);
6388
 
                }
6389
 
        }
6390
 
}
6391
 
 
6392
 
static int doVertSlide(TransInfo *t, float perc)
6393
 
{
6394
 
        VertSlideData *sld = t->customData;
6395
 
        TransDataVertSlideVert *svlist = sld->sv, *sv;
6396
 
        int i;
6397
 
 
6398
 
        sld->perc = perc;
6399
 
        sv = svlist;
6400
 
 
6401
 
        if (sld->is_proportional == TRUE) {
6402
 
                for (i = 0; i < sld->totsv; i++, sv++) {
6403
 
                        interp_v3_v3v3(sv->v->co, sv->co_orig_3d, sv->co_link_orig_3d[sv->co_link_curr], perc);
6404
 
                }
6405
 
        }
6406
 
        else {
6407
 
                TransDataVertSlideVert *sv_curr = &sld->sv[sld->curr_sv_index];
6408
 
                const float edge_len_curr = len_v3v3(sv_curr->co_orig_3d, sv_curr->co_link_orig_3d[sv_curr->co_link_curr]);
6409
 
                const float tperc = perc * edge_len_curr;
6410
 
 
6411
 
                for (i = 0; i < sld->totsv; i++, sv++) {
6412
 
                        float edge_len;
6413
 
                        float dir[3];
6414
 
 
6415
 
                        sub_v3_v3v3(dir, sv->co_link_orig_3d[sv->co_link_curr], sv->co_orig_3d);
6416
 
                        edge_len = normalize_v3(dir);
6417
 
 
6418
 
                        if (edge_len > FLT_EPSILON) {
6419
 
                                if (sld->flipped_vtx) {
6420
 
                                        madd_v3_v3v3fl(sv->v->co, sv->co_link_orig_3d[sv->co_link_curr], dir, -tperc);
6421
 
                                }
6422
 
                                else {
6423
 
                                        madd_v3_v3v3fl(sv->v->co, sv->co_orig_3d, dir, tperc);
6424
 
                                }
6425
 
                        }
6426
 
                        else {
6427
 
                                copy_v3_v3(sv->v->co, sv->co_orig_3d);
6428
 
                        }
6429
 
                }
6430
 
        }
6431
 
 
6432
 
        return 1;
6433
 
}
6434
 
 
6435
 
int VertSlide(TransInfo *t, const int UNUSED(mval[2]))
6436
 
{
6437
 
        char str[128];
6438
 
        char *str_p;
6439
 
        float final;
6440
 
        VertSlideData *sld =  t->customData;
6441
 
        const bool flipped = sld->flipped_vtx;
6442
 
        const bool is_proportional = sld->is_proportional;
6443
 
        const bool is_clamp = !(t->flag & T_ALT_TRANSFORM);
6444
 
        const bool is_constrained = !(is_clamp == false || hasNumInput(&t->num));
6445
 
 
6446
 
        final = t->values[0];
6447
 
 
6448
 
        snapGrid(t, &final);
6449
 
 
6450
 
        /* only do this so out of range values are not displayed */
6451
 
        if (is_constrained) {
6452
 
                CLAMP(final, 0.0f, 1.0f);
6453
 
        }
6454
 
 
6455
 
        /* header string */
6456
 
        str_p = str;
6457
 
        str_p += BLI_snprintf(str_p, sizeof(str), IFACE_("Vert Slide: "));
6458
 
        if (hasNumInput(&t->num)) {
6459
 
                char c[NUM_STR_REP_LEN];
6460
 
                applyNumInput(&t->num, &final);
6461
 
                outputNumInput(&(t->num), c);
6462
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%s", &c[0]);
6463
 
        }
6464
 
        else {
6465
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), "%.4f ", final);
6466
 
        }
6467
 
        str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(E)ven: %s, "),
6468
 
                              !is_proportional ? IFACE_("ON") : IFACE_("OFF"));
6469
 
        if (!is_proportional) {
6470
 
                str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("(F)lipped: %s, "),
6471
 
                                      flipped ? IFACE_("ON") : IFACE_("OFF"));
6472
 
        }
6473
 
        str_p += BLI_snprintf(str_p, sizeof(str) - (str_p - str), IFACE_("Alt or (C)lamp: %s"),
6474
 
                              is_clamp ? IFACE_("ON") : IFACE_("OFF"));
6475
 
        /* done with header string */
6476
 
 
6477
 
        /*do stuff here*/
6478
 
        if (t->customData) {
6479
 
                doVertSlide(t, final);
6480
 
        }
6481
 
        else {
6482
 
                strcpy(str, IFACE_("Invalid Vert Selection"));
6483
 
                t->state = TRANS_CANCEL;
6484
 
        }
6485
 
 
6486
 
        recalcData(t);
6487
 
 
6488
 
        ED_area_headerprint(t->sa, str);
6489
 
 
6490
 
        return 1;
6491
 
}
6492
 
 
6493
 
 
6494
 
/* ******************** EditBone roll *************** */
6495
 
 
6496
 
void initBoneRoll(TransInfo *t)
6497
 
{
6498
 
        t->mode = TFM_BONE_ROLL;
6499
 
        t->transform = BoneRoll;
6500
 
 
6501
 
        initMouseInputMode(t, &t->mouse, INPUT_ANGLE);
6502
 
 
6503
 
        t->idx_max = 0;
6504
 
        t->num.idx_max = 0;
6505
 
        t->snap[0] = 0.0f;
6506
 
        t->snap[1] = (float)((5.0 / 180) * M_PI);
6507
 
        t->snap[2] = t->snap[1] * 0.2f;
6508
 
 
6509
 
        t->num.increment = 1.0f;
6510
 
 
6511
 
        t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT;
6512
 
}
6513
 
 
6514
 
int BoneRoll(TransInfo *t, const int UNUSED(mval[2]))
6515
 
{
6516
 
        TransData *td = t->data;
6517
 
        int i;
6518
 
        char str[50];
6519
 
 
6520
 
        float final;
6521
 
 
6522
 
        final = t->values[0];
6523
 
 
6524
 
        snapGrid(t, &final);
6525
 
 
6526
 
        if (hasNumInput(&t->num)) {
6527
 
                char c[NUM_STR_REP_LEN];
6528
 
 
6529
 
                applyNumInput(&t->num, &final);
6530
 
 
6531
 
                outputNumInput(&(t->num), c);
6532
 
 
6533
 
                sprintf(str, IFACE_("Roll: %s"), &c[0]);
6534
 
 
6535
 
                final = DEG2RADF(final);
6536
 
        }
6537
 
        else {
6538
 
                sprintf(str, IFACE_("Roll: %.2f"), RAD2DEGF(final));
6539
 
        }
6540
 
 
6541
 
        /* set roll values */
6542
 
        for (i = 0; i < t->total; i++, td++) {
6543
 
                if (td->flag & TD_NOACTION)
6544
 
                        break;
6545
 
 
6546
 
                if (td->flag & TD_SKIP)
6547
 
                        continue;
6548
 
 
6549
 
                *(td->val) = td->ival - final;
6550
 
        }
6551
 
 
6552
 
        recalcData(t);
6553
 
 
6554
 
        ED_area_headerprint(t->sa, str);
6555
 
 
6556
 
        return 1;
6557
 
}
6558
 
 
6559
 
/* ************************** BAKE TIME ******************* */
6560
 
 
6561
 
void initBakeTime(TransInfo *t)
6562
 
{
6563
 
        t->transform = BakeTime;
6564
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
6565
 
 
6566
 
        t->idx_max = 0;
6567
 
        t->num.idx_max = 0;
6568
 
        t->snap[0] = 0.0f;
6569
 
        t->snap[1] = 1.0f;
6570
 
        t->snap[2] = t->snap[1] * 0.1f;
6571
 
 
6572
 
        t->num.increment = t->snap[1];
6573
 
}
6574
 
 
6575
 
int BakeTime(TransInfo *t, const int mval[2])
6576
 
{
6577
 
        TransData *td = t->data;
6578
 
        float time;
6579
 
        int i;
6580
 
        char str[50];
6581
 
 
6582
 
        float fac = 0.1f;
6583
 
 
6584
 
        if (t->mouse.precision) {
6585
 
                /* calculate ratio for shiftkey pos, and for total, and blend these for precision */
6586
 
                time = (float)(t->center2d[0] - t->mouse.precision_mval[0]) * fac;
6587
 
                time += 0.1f * ((float)(t->center2d[0] * fac - mval[0]) - time);
6588
 
        }
6589
 
        else {
6590
 
                time = (float)(t->center2d[0] - mval[0]) * fac;
6591
 
        }
6592
 
 
6593
 
        snapGrid(t, &time);
6594
 
 
6595
 
        applyNumInput(&t->num, &time);
6596
 
 
6597
 
        /* header print for NumInput */
6598
 
        if (hasNumInput(&t->num)) {
6599
 
                char c[NUM_STR_REP_LEN];
6600
 
 
6601
 
                outputNumInput(&(t->num), c);
6602
 
 
6603
 
                if (time >= 0.0f)
6604
 
                        sprintf(str, IFACE_("Time: +%s %s"), c, t->proptext);
6605
 
                else
6606
 
                        sprintf(str, IFACE_("Time: %s %s"), c, t->proptext);
6607
 
        }
6608
 
        else {
6609
 
                /* default header print */
6610
 
                if (time >= 0.0f)
6611
 
                        sprintf(str, IFACE_("Time: +%.3f %s"), time, t->proptext);
6612
 
                else
6613
 
                        sprintf(str, IFACE_("Time: %.3f %s"), time, t->proptext);
6614
 
        }
6615
 
 
6616
 
        for (i = 0; i < t->total; i++, td++) {
6617
 
                if (td->flag & TD_NOACTION)
6618
 
                        break;
6619
 
 
6620
 
                if (td->flag & TD_SKIP)
6621
 
                        continue;
6622
 
 
6623
 
                if (td->val) {
6624
 
                        *td->val = td->ival + time * td->factor;
6625
 
                        if (td->ext->size && *td->val < *td->ext->size) *td->val = *td->ext->size;
6626
 
                        if (td->ext->quat && *td->val > *td->ext->quat) *td->val = *td->ext->quat;
6627
 
                }
6628
 
        }
6629
 
 
6630
 
        recalcData(t);
6631
 
 
6632
 
        ED_area_headerprint(t->sa, str);
6633
 
 
6634
 
        return 1;
6635
 
}
6636
 
 
6637
 
/* ************************** MIRROR *************************** */
6638
 
 
6639
 
void initMirror(TransInfo *t)
6640
 
{
6641
 
        t->transform = Mirror;
6642
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
6643
 
 
6644
 
        t->flag |= T_NULL_ONE;
6645
 
        if (!t->obedit) {
6646
 
                t->flag |= T_NO_ZERO;
6647
 
        }
6648
 
}
6649
 
 
6650
 
int Mirror(TransInfo *t, const int UNUSED(mval[2]))
6651
 
{
6652
 
        TransData *td;
6653
 
        float size[3], mat[3][3];
6654
 
        int i;
6655
 
        char str[200];
6656
 
 
6657
 
        /*
6658
 
         * OPTIMIZATION:
6659
 
         * This still recalcs transformation on mouse move
6660
 
         * while it should only recalc on constraint change
6661
 
         * */
6662
 
 
6663
 
        /* if an axis has been selected */
6664
 
        if (t->con.mode & CON_APPLY) {
6665
 
                size[0] = size[1] = size[2] = -1;
6666
 
 
6667
 
                size_to_mat3(mat, size);
6668
 
 
6669
 
                if (t->con.applySize) {
6670
 
                        t->con.applySize(t, NULL, mat);
6671
 
                }
6672
 
 
6673
 
                sprintf(str, IFACE_("Mirror%s"), t->con.text);
6674
 
 
6675
 
                for (i = 0, td = t->data; i < t->total; i++, td++) {
6676
 
                        if (td->flag & TD_NOACTION)
6677
 
                                break;
6678
 
 
6679
 
                        if (td->flag & TD_SKIP)
6680
 
                                continue;
6681
 
 
6682
 
                        ElementResize(t, td, mat);
6683
 
                }
6684
 
 
6685
 
                recalcData(t);
6686
 
 
6687
 
                ED_area_headerprint(t->sa, str);
6688
 
        }
6689
 
        else {
6690
 
                size[0] = size[1] = size[2] = 1;
6691
 
 
6692
 
                size_to_mat3(mat, size);
6693
 
 
6694
 
                for (i = 0, td = t->data; i < t->total; i++, td++) {
6695
 
                        if (td->flag & TD_NOACTION)
6696
 
                                break;
6697
 
 
6698
 
                        if (td->flag & TD_SKIP)
6699
 
                                continue;
6700
 
 
6701
 
                        ElementResize(t, td, mat);
6702
 
                }
6703
 
 
6704
 
                recalcData(t);
6705
 
 
6706
 
                if (t->flag & T_2D_EDIT)
6707
 
                        ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y)"));
6708
 
                else
6709
 
                        ED_area_headerprint(t->sa, IFACE_("Select a mirror axis (X, Y, Z)"));
6710
 
        }
6711
 
 
6712
 
        return 1;
6713
 
}
6714
 
 
6715
 
/* ************************** ALIGN *************************** */
6716
 
 
6717
 
void initAlign(TransInfo *t)
6718
 
{
6719
 
        t->flag |= T_NO_CONSTRAINT;
6720
 
 
6721
 
        t->transform = Align;
6722
 
 
6723
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
6724
 
}
6725
 
 
6726
 
int Align(TransInfo *t, const int UNUSED(mval[2]))
6727
 
{
6728
 
        TransData *td = t->data;
6729
 
        float center[3];
6730
 
        int i;
6731
 
 
6732
 
        /* saving original center */
6733
 
        copy_v3_v3(center, t->center);
6734
 
 
6735
 
        for (i = 0; i < t->total; i++, td++) {
6736
 
                float mat[3][3], invmat[3][3];
6737
 
 
6738
 
                if (td->flag & TD_NOACTION)
6739
 
                        break;
6740
 
 
6741
 
                if (td->flag & TD_SKIP)
6742
 
                        continue;
6743
 
 
6744
 
                /* around local centers */
6745
 
                if (t->flag & (T_OBJECT | T_POSE)) {
6746
 
                        copy_v3_v3(t->center, td->center);
6747
 
                }
6748
 
                else {
6749
 
                        if (t->settings->selectmode & SCE_SELECT_FACE) {
6750
 
                                copy_v3_v3(t->center, td->center);
6751
 
                        }
6752
 
                }
6753
 
 
6754
 
                invert_m3_m3(invmat, td->axismtx);
6755
 
 
6756
 
                mul_m3_m3m3(mat, t->spacemtx, invmat);
6757
 
 
6758
 
                ElementRotation(t, td, mat, t->around);
6759
 
        }
6760
 
 
6761
 
        /* restoring original center */
6762
 
        copy_v3_v3(t->center, center);
6763
 
 
6764
 
        recalcData(t);
6765
 
 
6766
 
        ED_area_headerprint(t->sa, IFACE_("Align"));
6767
 
 
6768
 
        return 1;
6769
 
}
6770
 
 
6771
 
/* ************************** SEQ SLIDE *************************** */
6772
 
 
6773
 
void initSeqSlide(TransInfo *t)
6774
 
{
6775
 
        t->transform = SeqSlide;
6776
 
 
6777
 
        initMouseInputMode(t, &t->mouse, INPUT_VECTOR);
6778
 
 
6779
 
        t->idx_max = 1;
6780
 
        t->num.flag = 0;
6781
 
        t->num.idx_max = t->idx_max;
6782
 
 
6783
 
        t->snap[0] = 0.0f;
6784
 
        t->snap[1] = floor(t->scene->r.frs_sec / t->scene->r.frs_sec_base);
6785
 
        t->snap[2] = 10.0f;
6786
 
 
6787
 
        t->num.increment = t->snap[1];
6788
 
}
6789
 
 
6790
 
static void headerSeqSlide(TransInfo *t, float val[2], char *str, size_t str_len)
6791
 
{
6792
 
        char tvec[NUM_STR_REP_LEN * 3];
6793
 
        char *str_p;
6794
 
 
6795
 
        if (hasNumInput(&t->num)) {
6796
 
                outputNumInput(&(t->num), tvec);
6797
 
        }
6798
 
        else {
6799
 
                sprintf(&tvec[0], "%.0f, %.0f", val[0], val[1]);
6800
 
        }
6801
 
 
6802
 
        str_p = str;
6803
 
        str_p += BLI_snprintf(str, str_len, IFACE_("Sequence Slide: %s%s, ("), &tvec[0], t->con.text);
6804
 
 
6805
 
        {
6806
 
                wmKeyMapItem *kmi = WM_modalkeymap_find_propvalue(t->keymap, TFM_MODAL_TRANSLATE);
6807
 
                if (kmi) {
6808
 
                        str_p += WM_keymap_item_to_string(kmi, str_p, str_len - (str_p - str));
6809
 
                }
6810
 
        }
6811
 
        str_p += BLI_snprintf(str_p, str_len - (str_p - str), IFACE_(" or Alt) Expand to fit %s"),
6812
 
                              (t->flag & T_ALT_TRANSFORM) ? IFACE_("ON") : IFACE_("OFF"));
6813
 
}
6814
 
 
6815
 
static void applySeqSlide(TransInfo *t, float val[2])
6816
 
{
6817
 
        TransData *td = t->data;
6818
 
        int i;
6819
 
 
6820
 
        for (i = 0; i < t->total; i++, td++) {
6821
 
                float tvec[2];
6822
 
 
6823
 
                if (td->flag & TD_NOACTION)
6824
 
                        break;
6825
 
 
6826
 
                if (td->flag & TD_SKIP)
6827
 
                        continue;
6828
 
 
6829
 
                copy_v2_v2(tvec, val);
6830
 
 
6831
 
                mul_v2_fl(tvec, td->factor);
6832
 
 
6833
 
                td->loc[0] = td->iloc[0] + tvec[0];
6834
 
                td->loc[1] = td->iloc[1] + tvec[1];
6835
 
        }
6836
 
}
6837
 
 
6838
 
int SeqSlide(TransInfo *t, const int UNUSED(mval[2]))
6839
 
{
6840
 
        char str[200];
6841
 
 
6842
 
        if (t->con.mode & CON_APPLY) {
6843
 
                float pvec[3] = {0.0f, 0.0f, 0.0f};
6844
 
                float tvec[3];
6845
 
                t->con.applyVec(t, NULL, t->values, tvec, pvec);
6846
 
                copy_v3_v3(t->values, tvec);
6847
 
        }
6848
 
        else {
6849
 
                snapGrid(t, t->values);
6850
 
                applyNumInput(&t->num, t->values);
6851
 
        }
6852
 
 
6853
 
        t->values[0] = floor(t->values[0] + 0.5f);
6854
 
        t->values[1] = floor(t->values[1] + 0.5f);
6855
 
 
6856
 
        headerSeqSlide(t, t->values, str, sizeof(str));
6857
 
        applySeqSlide(t, t->values);
6858
 
 
6859
 
        recalcData(t);
6860
 
 
6861
 
        ED_area_headerprint(t->sa, str);
6862
 
 
6863
 
        return 1;
6864
 
}
6865
 
 
6866
 
/* ************************** ANIM EDITORS - TRANSFORM TOOLS *************************** */
6867
 
 
6868
 
/* ---------------- Special Helpers for Various Settings ------------- */
6869
 
 
6870
 
 
6871
 
/* This function returns the snapping 'mode' for Animation Editors only
6872
 
 * We cannot use the standard snapping due to NLA-strip scaling complexities.
6873
 
 */
6874
 
// XXX these modifier checks should be keymappable
6875
 
static short getAnimEdit_SnapMode(TransInfo *t)
6876
 
{
6877
 
        short autosnap = SACTSNAP_OFF;
6878
 
        
6879
 
        if (t->spacetype == SPACE_ACTION) {
6880
 
                SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
6881
 
                
6882
 
                if (saction)
6883
 
                        autosnap = saction->autosnap;
6884
 
        }
6885
 
        else if (t->spacetype == SPACE_IPO) {
6886
 
                SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
6887
 
                
6888
 
                if (sipo)
6889
 
                        autosnap = sipo->autosnap;
6890
 
        }
6891
 
        else if (t->spacetype == SPACE_NLA) {
6892
 
                SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
6893
 
                
6894
 
                if (snla)
6895
 
                        autosnap = snla->autosnap;
6896
 
        }
6897
 
        else {
6898
 
                autosnap = SACTSNAP_OFF;
6899
 
        }
6900
 
        
6901
 
        /* toggle autosnap on/off 
6902
 
         *  - when toggling on, prefer nearest frame over 1.0 frame increments
6903
 
         */
6904
 
        if (t->modifiers & MOD_SNAP_INVERT) {
6905
 
                if (autosnap)
6906
 
                        autosnap = SACTSNAP_OFF;
6907
 
                else
6908
 
                        autosnap = SACTSNAP_FRAME;
6909
 
        }
6910
 
 
6911
 
        return autosnap;
6912
 
}
6913
 
 
6914
 
/* This function is used for testing if an Animation Editor is displaying
6915
 
 * its data in frames or seconds (and the data needing to be edited as such).
6916
 
 * Returns 1 if in seconds, 0 if in frames
6917
 
 */
6918
 
static short getAnimEdit_DrawTime(TransInfo *t)
6919
 
{
6920
 
        short drawtime;
6921
 
 
6922
 
        if (t->spacetype == SPACE_ACTION) {
6923
 
                SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
6924
 
                
6925
 
                drawtime = (saction->flag & SACTION_DRAWTIME) ? 1 : 0;
6926
 
        }
6927
 
        else if (t->spacetype == SPACE_NLA) {
6928
 
                SpaceNla *snla = (SpaceNla *)t->sa->spacedata.first;
6929
 
                
6930
 
                drawtime = (snla->flag & SNLA_DRAWTIME) ? 1 : 0;
6931
 
        }
6932
 
        else if (t->spacetype == SPACE_IPO) {
6933
 
                SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
6934
 
                
6935
 
                drawtime = (sipo->flag & SIPO_DRAWTIME) ? 1 : 0;
6936
 
        }
6937
 
        else {
6938
 
                drawtime = 0;
6939
 
        }
6940
 
 
6941
 
        return drawtime;
6942
 
}
6943
 
 
6944
 
 
6945
 
/* This function is used by Animation Editor specific transform functions to do
6946
 
 * the Snap Keyframe to Nearest Frame/Marker
6947
 
 */
6948
 
static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, TransData2D *td2d, AnimData *adt, short autosnap)
6949
 
{
6950
 
        /* snap key to nearest frame? */
6951
 
        if (autosnap == SACTSNAP_FRAME) {
6952
 
 
6953
 
#if 0   /* 'do_time' disabled for now */
6954
 
 
6955
 
                const Scene *scene = t->scene;
6956
 
                const short do_time = 0; //getAnimEdit_DrawTime(t); // NOTE: this works, but may be confusing behavior given the option's label, hence disabled
6957
 
                const double secf = FPS;
6958
 
#endif
6959
 
                double val;
6960
 
                
6961
 
                /* convert frame to nla-action time (if needed) */
6962
 
                if (adt)
6963
 
                        val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
6964
 
                else
6965
 
                        val = *(td->val);
6966
 
                
6967
 
#if 0   /* 'do_time' disabled for now */
6968
 
 
6969
 
                /* do the snapping to nearest frame/second */
6970
 
                if (do_time) {
6971
 
                        val = (float)(floor((val / secf) + 0.5f) * secf);
6972
 
                }
6973
 
                else
6974
 
#endif
6975
 
                {
6976
 
                        val = floor(val + 0.5);
6977
 
                }
6978
 
                
6979
 
                /* convert frame out of nla-action time */
6980
 
                if (adt)
6981
 
                        *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
6982
 
                else
6983
 
                        *(td->val) = val;
6984
 
        }
6985
 
        /* snap key to nearest marker? */
6986
 
        else if (autosnap == SACTSNAP_MARKER) {
6987
 
                float val;
6988
 
                
6989
 
                /* convert frame to nla-action time (if needed) */
6990
 
                if (adt)
6991
 
                        val = BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
6992
 
                else
6993
 
                        val = *(td->val);
6994
 
                
6995
 
                /* snap to nearest marker */
6996
 
                // TODO: need some more careful checks for where data comes from
6997
 
                val = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, val);
6998
 
                
6999
 
                /* convert frame out of nla-action time */
7000
 
                if (adt)
7001
 
                        *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
7002
 
                else
7003
 
                        *(td->val) = val;
7004
 
        }
7005
 
        
7006
 
        /* if the handles are to be moved too (as side-effect of keyframes moving, to keep the general effect) 
7007
 
         * offset them by the same amount so that the general angles are maintained (i.e. won't change while 
7008
 
         * handles are free-to-roam and keyframes are snap-locked)
7009
 
         */
7010
 
        if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
7011
 
                td2d->h1[0] = td2d->ih1[0] + *td->val - td->ival;
7012
 
        }
7013
 
        if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
7014
 
                td2d->h2[0] = td2d->ih2[0] + *td->val - td->ival;
7015
 
        }
7016
 
}
7017
 
 
7018
 
/* ----------------- Translation ----------------------- */
7019
 
 
7020
 
void initTimeTranslate(TransInfo *t)
7021
 
{
7022
 
        /* this tool is only really available in the Action Editor... */
7023
 
        if (!ELEM(t->spacetype, SPACE_ACTION, SPACE_SEQ)) {
7024
 
                t->state = TRANS_CANCEL;
7025
 
        }
7026
 
 
7027
 
        t->mode = TFM_TIME_TRANSLATE;
7028
 
        t->transform = TimeTranslate;
7029
 
 
7030
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
7031
 
 
7032
 
        /* num-input has max of (n-1) */
7033
 
        t->idx_max = 0;
7034
 
        t->num.flag = 0;
7035
 
        t->num.idx_max = t->idx_max;
7036
 
 
7037
 
        /* initialize snap like for everything else */
7038
 
        t->snap[0] = 0.0f;
7039
 
        t->snap[1] = t->snap[2] = 1.0f;
7040
 
 
7041
 
        t->num.increment = t->snap[1];
7042
 
}
7043
 
 
7044
 
static void headerTimeTranslate(TransInfo *t, char *str)
7045
 
{
7046
 
        char tvec[NUM_STR_REP_LEN * 3];
7047
 
 
7048
 
        /* if numeric input is active, use results from that, otherwise apply snapping to result */
7049
 
        if (hasNumInput(&t->num)) {
7050
 
                outputNumInput(&(t->num), tvec);
7051
 
        }
7052
 
        else {
7053
 
                const Scene *scene = t->scene;
7054
 
                const short autosnap = getAnimEdit_SnapMode(t);
7055
 
                const short do_time = getAnimEdit_DrawTime(t);
7056
 
                const double secf = FPS;
7057
 
                float val = t->values[0];
7058
 
                
7059
 
                /* apply snapping + frame->seconds conversions */
7060
 
                if (autosnap == SACTSNAP_STEP) {
7061
 
                        if (do_time)
7062
 
                                val = floorf((double)val / secf + 0.5);
7063
 
                        else
7064
 
                                val = floorf(val + 0.5f);
7065
 
                }
7066
 
                else {
7067
 
                        if (do_time)
7068
 
                                val = (float)((double)val / secf);
7069
 
                }
7070
 
                
7071
 
                if (autosnap == SACTSNAP_FRAME)
7072
 
                        sprintf(&tvec[0], "%d.00 (%.4f)", (int)val, val);
7073
 
                else
7074
 
                        sprintf(&tvec[0], "%.4f", val);
7075
 
        }
7076
 
 
7077
 
        sprintf(str, IFACE_("DeltaX: %s"), &tvec[0]);
7078
 
}
7079
 
 
7080
 
static void applyTimeTranslate(TransInfo *t, float UNUSED(sval))
7081
 
{
7082
 
        TransData *td = t->data;
7083
 
        TransData2D *td2d = t->data2d;
7084
 
        Scene *scene = t->scene;
7085
 
        int i;
7086
 
 
7087
 
        const short do_time = getAnimEdit_DrawTime(t);
7088
 
        const double secf = FPS;
7089
 
 
7090
 
        const short autosnap = getAnimEdit_SnapMode(t);
7091
 
 
7092
 
        float deltax, val /* , valprev */;
7093
 
 
7094
 
        /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
7095
 
        for (i = 0; i < t->total; i++, td++, td2d++) {
7096
 
                /* it is assumed that td->extra is a pointer to the AnimData,
7097
 
                 * whose active action is where this keyframe comes from
7098
 
                 * (this is only valid when not in NLA)
7099
 
                 */
7100
 
                AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
7101
 
 
7102
 
                /* valprev = *td->val; */ /* UNUSED */
7103
 
 
7104
 
                /* check if any need to apply nla-mapping */
7105
 
                if (adt && t->spacetype != SPACE_SEQ) {
7106
 
                        deltax = t->values[0];
7107
 
 
7108
 
                        if (autosnap == SACTSNAP_STEP) {
7109
 
                                if (do_time)
7110
 
                                        deltax = (float)(floor(((double)deltax / secf) + 0.5) * secf);
7111
 
                                else
7112
 
                                        deltax = (float)(floor(deltax + 0.5f));
7113
 
                        }
7114
 
 
7115
 
                        val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
7116
 
                        val += deltax;
7117
 
                        *(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
7118
 
                }
7119
 
                else {
7120
 
                        deltax = val = t->values[0];
7121
 
 
7122
 
                        if (autosnap == SACTSNAP_STEP) {
7123
 
                                if (do_time)
7124
 
                                        val = (float)(floor(((double)deltax / secf) + 0.5) * secf);
7125
 
                                else
7126
 
                                        val = (float)(floor(val + 0.5f));
7127
 
                        }
7128
 
 
7129
 
                        *(td->val) = td->ival + val;
7130
 
                }
7131
 
 
7132
 
                /* apply nearest snapping */
7133
 
                doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
7134
 
        }
7135
 
}
7136
 
 
7137
 
int TimeTranslate(TransInfo *t, const int mval[2])
7138
 
{
7139
 
        View2D *v2d = (View2D *)t->view;
7140
 
        float cval[2], sval[2];
7141
 
        char str[200];
7142
 
 
7143
 
        /* calculate translation amount from mouse movement - in 'time-grid space' */
7144
 
        UI_view2d_region_to_view(v2d, mval[0], mval[0], &cval[0], &cval[1]);
7145
 
        UI_view2d_region_to_view(v2d, t->imval[0], t->imval[0], &sval[0], &sval[1]);
7146
 
 
7147
 
        /* we only need to calculate effect for time (applyTimeTranslate only needs that) */
7148
 
        t->values[0] = cval[0] - sval[0];
7149
 
 
7150
 
        /* handle numeric-input stuff */
7151
 
        t->vec[0] = t->values[0];
7152
 
        applyNumInput(&t->num, &t->vec[0]);
7153
 
        t->values[0] = t->vec[0];
7154
 
        headerTimeTranslate(t, str);
7155
 
 
7156
 
        applyTimeTranslate(t, sval[0]);
7157
 
 
7158
 
        recalcData(t);
7159
 
 
7160
 
        ED_area_headerprint(t->sa, str);
7161
 
 
7162
 
        return 1;
7163
 
}
7164
 
 
7165
 
/* ----------------- Time Slide ----------------------- */
7166
 
 
7167
 
void initTimeSlide(TransInfo *t)
7168
 
{
7169
 
        /* this tool is only really available in the Action Editor... */
7170
 
        if (t->spacetype == SPACE_ACTION) {
7171
 
                SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
7172
 
 
7173
 
                /* set flag for drawing stuff */
7174
 
                saction->flag |= SACTION_MOVING;
7175
 
        }
7176
 
        else {
7177
 
                t->state = TRANS_CANCEL;
7178
 
        }
7179
 
 
7180
 
 
7181
 
        t->mode = TFM_TIME_SLIDE;
7182
 
        t->transform = TimeSlide;
7183
 
        t->flag |= T_FREE_CUSTOMDATA;
7184
 
 
7185
 
        initMouseInputMode(t, &t->mouse, INPUT_NONE);
7186
 
 
7187
 
        /* num-input has max of (n-1) */
7188
 
        t->idx_max = 0;
7189
 
        t->num.flag = 0;
7190
 
        t->num.idx_max = t->idx_max;
7191
 
 
7192
 
        /* initialize snap like for everything else */
7193
 
        t->snap[0] = 0.0f;
7194
 
        t->snap[1] = t->snap[2] = 1.0f;
7195
 
 
7196
 
        t->num.increment = t->snap[1];
7197
 
}
7198
 
 
7199
 
static void headerTimeSlide(TransInfo *t, float sval, char *str)
7200
 
{
7201
 
        char tvec[NUM_STR_REP_LEN * 3];
7202
 
 
7203
 
        if (hasNumInput(&t->num)) {
7204
 
                outputNumInput(&(t->num), tvec);
7205
 
        }
7206
 
        else {
7207
 
                float minx = *((float *)(t->customData));
7208
 
                float maxx = *((float *)(t->customData) + 1);
7209
 
                float cval = t->values[0];
7210
 
                float val;
7211
 
 
7212
 
                val = 2.0f * (cval - sval) / (maxx - minx);
7213
 
                CLAMP(val, -1.0f, 1.0f);
7214
 
 
7215
 
                sprintf(&tvec[0], "%.4f", val);
7216
 
        }
7217
 
 
7218
 
        sprintf(str, IFACE_("TimeSlide: %s"), &tvec[0]);
7219
 
}
7220
 
 
7221
 
static void applyTimeSlide(TransInfo *t, float sval)
7222
 
{
7223
 
        TransData *td = t->data;
7224
 
        int i;
7225
 
 
7226
 
        float minx = *((float *)(t->customData));
7227
 
        float maxx = *((float *)(t->customData) + 1);
7228
 
 
7229
 
        /* set value for drawing black line */
7230
 
        if (t->spacetype == SPACE_ACTION) {
7231
 
                SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
7232
 
                float cvalf = t->values[0];
7233
 
 
7234
 
                saction->timeslide = cvalf;
7235
 
        }
7236
 
 
7237
 
        /* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
7238
 
        for (i = 0; i < t->total; i++, td++) {
7239
 
                /* it is assumed that td->extra is a pointer to the AnimData,
7240
 
                 * whose active action is where this keyframe comes from
7241
 
                 * (this is only valid when not in NLA)
7242
 
                 */
7243
 
                AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
7244
 
                float cval = t->values[0];
7245
 
 
7246
 
                /* apply NLA-mapping to necessary values */
7247
 
                if (adt)
7248
 
                        cval = BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP);
7249
 
 
7250
 
                /* only apply to data if in range */
7251
 
                if ((sval > minx) && (sval < maxx)) {
7252
 
                        float cvalc = CLAMPIS(cval, minx, maxx);
7253
 
                        float timefac;
7254
 
 
7255
 
                        /* left half? */
7256
 
                        if (td->ival < sval) {
7257
 
                                timefac = (sval - td->ival) / (sval - minx);
7258
 
                                *(td->val) = cvalc - timefac * (cvalc - minx);
7259
 
                        }
7260
 
                        else {
7261
 
                                timefac = (td->ival - sval) / (maxx - sval);
7262
 
                                *(td->val) = cvalc + timefac * (maxx - cvalc);
7263
 
                        }
7264
 
                }
7265
 
        }
7266
 
}
7267
 
 
7268
 
int TimeSlide(TransInfo *t, const int mval[2])
7269
 
{
7270
 
        View2D *v2d = (View2D *)t->view;
7271
 
        float cval[2], sval[2];
7272
 
        float minx = *((float *)(t->customData));
7273
 
        float maxx = *((float *)(t->customData) + 1);
7274
 
        char str[200];
7275
 
 
7276
 
        /* calculate mouse co-ordinates */
7277
 
        UI_view2d_region_to_view(v2d, mval[0], mval[1], &cval[0], &cval[1]);
7278
 
        UI_view2d_region_to_view(v2d, t->imval[0], t->imval[1], &sval[0], &sval[1]);
7279
 
 
7280
 
        /* t->values[0] stores cval[0], which is the current mouse-pointer location (in frames) */
7281
 
        // XXX Need to be able to repeat this
7282
 
        t->values[0] = cval[0];
7283
 
 
7284
 
        /* handle numeric-input stuff */
7285
 
        t->vec[0] = 2.0f * (cval[0] - sval[0]) / (maxx - minx);
7286
 
        applyNumInput(&t->num, &t->vec[0]);
7287
 
        t->values[0] = (maxx - minx) * t->vec[0] / 2.0f + sval[0];
7288
 
 
7289
 
        headerTimeSlide(t, sval[0], str);
7290
 
        applyTimeSlide(t, sval[0]);
7291
 
 
7292
 
        recalcData(t);
7293
 
 
7294
 
        ED_area_headerprint(t->sa, str);
7295
 
 
7296
 
        return 1;
7297
 
}
7298
 
 
7299
 
/* ----------------- Scaling ----------------------- */
7300
 
 
7301
 
void initTimeScale(TransInfo *t)
7302
 
{
7303
 
        int center[2];
7304
 
 
7305
 
        /* this tool is only really available in the Action Editor
7306
 
         * AND NLA Editor (for strip scaling)
7307
 
         */
7308
 
        if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA) == 0) {
7309
 
                t->state = TRANS_CANCEL;
7310
 
        }
7311
 
 
7312
 
        t->mode = TFM_TIME_SCALE;
7313
 
        t->transform = TimeScale;
7314
 
 
7315
 
        /* recalculate center2d to use CFRA and mouse Y, since that's
7316
 
         * what is used in time scale */
7317
 
        t->center[0] = t->scene->r.cfra;
7318
 
        projectIntView(t, t->center, center);
7319
 
        center[1] = t->imval[1];
7320
 
 
7321
 
        /* force a reinit with the center2d used here */
7322
 
        initMouseInput(t, &t->mouse, center, t->imval);
7323
 
 
7324
 
        initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP);
7325
 
 
7326
 
        t->flag |= T_NULL_ONE;
7327
 
        t->num.flag |= NUM_NULL_ONE;
7328
 
 
7329
 
        /* num-input has max of (n-1) */
7330
 
        t->idx_max = 0;
7331
 
        t->num.flag = 0;
7332
 
        t->num.idx_max = t->idx_max;
7333
 
 
7334
 
        /* initialize snap like for everything else */
7335
 
        t->snap[0] = 0.0f;
7336
 
        t->snap[1] = t->snap[2] = 1.0f;
7337
 
 
7338
 
        t->num.increment = t->snap[1];
7339
 
}
7340
 
 
7341
 
static void headerTimeScale(TransInfo *t, char *str)
7342
 
{
7343
 
        char tvec[NUM_STR_REP_LEN * 3];
7344
 
 
7345
 
        if (hasNumInput(&t->num))
7346
 
                outputNumInput(&(t->num), tvec);
7347
 
        else
7348
 
                sprintf(&tvec[0], "%.4f", t->values[0]);
7349
 
 
7350
 
        sprintf(str, IFACE_("ScaleX: %s"), &tvec[0]);
7351
 
}
7352
 
 
7353
 
static void applyTimeScale(TransInfo *t)
7354
 
{
7355
 
        Scene *scene = t->scene;
7356
 
        TransData *td = t->data;
7357
 
        TransData2D *td2d = t->data2d;
7358
 
        int i;
7359
 
 
7360
 
        const short autosnap = getAnimEdit_SnapMode(t);
7361
 
        const short do_time = getAnimEdit_DrawTime(t);
7362
 
        const double secf = FPS;
7363
 
 
7364
 
 
7365
 
        for (i = 0; i < t->total; i++, td++, td2d++) {
7366
 
                /* it is assumed that td->extra is a pointer to the AnimData,
7367
 
                 * whose active action is where this keyframe comes from
7368
 
                 * (this is only valid when not in NLA)
7369
 
                 */
7370
 
                AnimData *adt = (t->spacetype != SPACE_NLA) ? td->extra : NULL;
7371
 
                float startx = CFRA;
7372
 
                float fac = t->values[0];
7373
 
 
7374
 
                if (autosnap == SACTSNAP_STEP) {
7375
 
                        if (do_time)
7376
 
                                fac = (float)(floor((double)fac / secf + 0.5) * secf);
7377
 
                        else
7378
 
                                fac = (float)(floor(fac + 0.5f));
7379
 
                }
7380
 
 
7381
 
                /* check if any need to apply nla-mapping */
7382
 
                if (adt)
7383
 
                        startx = BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
7384
 
 
7385
 
                /* now, calculate the new value */
7386
 
                *(td->val) = ((td->ival - startx) * fac) + startx;
7387
 
 
7388
 
                /* apply nearest snapping */
7389
 
                doAnimEdit_SnapFrame(t, td, td2d, adt, autosnap);
7390
 
        }
7391
 
}
7392
 
 
7393
 
int TimeScale(TransInfo *t, const int UNUSED(mval[2]))
7394
 
{
7395
 
        char str[200];
7396
 
        
7397
 
        /* handle numeric-input stuff */
7398
 
        t->vec[0] = t->values[0];
7399
 
        applyNumInput(&t->num, &t->vec[0]);
7400
 
        t->values[0] = t->vec[0];
7401
 
        headerTimeScale(t, str);
7402
 
 
7403
 
        applyTimeScale(t);
7404
 
 
7405
 
        recalcData(t);
7406
 
 
7407
 
        ED_area_headerprint(t->sa, str);
7408
 
 
7409
 
        return 1;
7410
 
}
7411
 
 
7412
 
/* ************************************ */
7413
 
 
7414
 
void BIF_TransformSetUndo(const char *UNUSED(str))
7415
 
{
7416
 
        // TRANSFORM_FIX_ME
7417
 
        //Trans.undostr = str;
7418
 
}
7419
 
 
7420
 
 
7421
 
/* TODO, move to: transform_queries.c */
7422
 
bool checkUseLocalCenter_GraphEdit(TransInfo *t)
7423
 
{
7424
 
        return ((t->around == V3D_LOCAL) && !ELEM3(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE));
7425
 
}