1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edtransform
22 */
23
24 #include "DNA_anim_types.h"
25 #include "DNA_space_types.h"
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_listbase.h"
30 #include "BLI_math.h"
31
32 #include "BKE_context.h"
33 #include "BKE_nla.h"
34
35 #include "ED_anim_api.h"
36 #include "ED_markers.h"
37
38 #include "WM_api.h"
39
40 #include "RNA_access.h"
41
42 #include "transform.h"
43 #include "transform_convert.h"
44
45 /** Used for NLA transform (stored in #TransData.extra pointer). */
46 typedef struct TransDataNla {
47 /** ID-block NLA-data is attached to. */
48 ID *id;
49
50 /** Original NLA-Track that the strip belongs to. */
51 struct NlaTrack *oldTrack;
52 /** Current NLA-Track that the strip belongs to. */
53 struct NlaTrack *nlt;
54
55 /** NLA-strip this data represents. */
56 struct NlaStrip *strip;
57
58 /* dummy values for transform to write in - must have 3 elements... */
59 /** start handle. */
60 float h1[3];
61 /** end handle. */
62 float h2[3];
63
64 /** index of track that strip is currently in. */
65 int trackIndex;
66 /** handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends. */
67 int handle;
68 } TransDataNla;
69
70 /* -------------------------------------------------------------------- */
71 /** \name NLA Transform Creation
72 *
73 * \{ */
74
createTransNlaData(bContext * C,TransInfo * t)75 void createTransNlaData(bContext *C, TransInfo *t)
76 {
77 Scene *scene = t->scene;
78 SpaceNla *snla = NULL;
79 TransData *td = NULL;
80 TransDataNla *tdn = NULL;
81
82 bAnimContext ac;
83 ListBase anim_data = {NULL, NULL};
84 bAnimListElem *ale;
85 int filter;
86
87 int count = 0;
88
89 TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
90
91 /* determine what type of data we are operating on */
92 if (ANIM_animdata_get_context(C, &ac) == 0) {
93 return;
94 }
95 snla = (SpaceNla *)ac.sl;
96
97 /* filter data */
98 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
99 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
100
101 /* which side of the current frame should be allowed */
102 if (t->mode == TFM_TIME_EXTEND) {
103 t->frame_side = transform_convert_frame_side_dir_get(t, (float)CFRA);
104 }
105 else {
106 /* normal transform - both sides of current frame are considered */
107 t->frame_side = 'B';
108 }
109
110 /* loop 1: count how many strips are selected (consider each strip as 2 points) */
111 for (ale = anim_data.first; ale; ale = ale->next) {
112 NlaTrack *nlt = (NlaTrack *)ale->data;
113 NlaStrip *strip;
114
115 /* make some meta-strips for chains of selected strips */
116 BKE_nlastrips_make_metas(&nlt->strips, 1);
117
118 /* only consider selected strips */
119 for (strip = nlt->strips.first; strip; strip = strip->next) {
120 /* TODO: we can make strips have handles later on. */
121 /* transition strips can't get directly transformed */
122 if (strip->type != NLASTRIP_TYPE_TRANSITION) {
123 if (strip->flag & NLASTRIP_FLAG_SELECT) {
124 if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
125 count++;
126 }
127 if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
128 count++;
129 }
130 }
131 }
132 }
133 }
134
135 /* stop if trying to build list if nothing selected */
136 if (count == 0) {
137 /* clear temp metas that may have been created but aren't needed now
138 * because they fell on the wrong side of CFRA
139 */
140 for (ale = anim_data.first; ale; ale = ale->next) {
141 NlaTrack *nlt = (NlaTrack *)ale->data;
142 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
143 }
144
145 /* cleanup temp list */
146 ANIM_animdata_freelist(&anim_data);
147 return;
148 }
149
150 /* allocate memory for data */
151 tc->data_len = count;
152
153 tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransData(NLA Editor)");
154 td = tc->data;
155 tc->custom.type.data = tdn = MEM_callocN(tc->data_len * sizeof(TransDataNla),
156 "TransDataNla (NLA Editor)");
157 tc->custom.type.use_free = true;
158
159 /* loop 2: build transdata array */
160 for (ale = anim_data.first; ale; ale = ale->next) {
161 /* only if a real NLA-track */
162 if (ale->type == ANIMTYPE_NLATRACK) {
163 AnimData *adt = ale->adt;
164 NlaTrack *nlt = (NlaTrack *)ale->data;
165 NlaStrip *strip;
166
167 /* only consider selected strips */
168 for (strip = nlt->strips.first; strip; strip = strip->next) {
169 /* TODO: we can make strips have handles later on. */
170 /* transition strips can't get directly transformed */
171 if (strip->type != NLASTRIP_TYPE_TRANSITION) {
172 if (strip->flag & NLASTRIP_FLAG_SELECT) {
173 /* our transform data is constructed as follows:
174 * - only the handles on the right side of the current-frame get included
175 * - td structs are transform-elements operated on by the transform system
176 * and represent a single handle. The storage/pointer used (val or loc) depends on
177 * whether we're scaling or transforming. Ultimately though, the handles
178 * the td writes to will simply be a dummy in tdn
179 * - for each strip being transformed, a single tdn struct is used, so in some
180 * cases, there will need to be 1 of these tdn elements in the array skipped...
181 */
182 float center[3], yval;
183
184 /* firstly, init tdn settings */
185 tdn->id = ale->id;
186 tdn->oldTrack = tdn->nlt = nlt;
187 tdn->strip = strip;
188 tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
189
190 yval = (float)(tdn->trackIndex * NLACHANNEL_STEP(snla));
191
192 tdn->h1[0] = strip->start;
193 tdn->h1[1] = yval;
194 tdn->h2[0] = strip->end;
195 tdn->h2[1] = yval;
196
197 center[0] = (float)CFRA;
198 center[1] = yval;
199 center[2] = 0.0f;
200
201 /* set td's based on which handles are applicable */
202 if (FrameOnMouseSide(t->frame_side, strip->start, (float)CFRA)) {
203 /* just set tdn to assume that it only has one handle for now */
204 tdn->handle = -1;
205
206 /* now, link the transform data up to this data */
207 if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
208 td->loc = tdn->h1;
209 copy_v3_v3(td->iloc, tdn->h1);
210
211 /* store all the other gunk that is required by transform */
212 copy_v3_v3(td->center, center);
213 memset(td->axismtx, 0, sizeof(td->axismtx));
214 td->axismtx[2][2] = 1.0f;
215
216 td->ext = NULL;
217 td->val = NULL;
218
219 td->flag |= TD_SELECTED;
220 td->dist = 0.0f;
221
222 unit_m3(td->mtx);
223 unit_m3(td->smtx);
224 }
225 else {
226 /* time scaling only needs single value */
227 td->val = &tdn->h1[0];
228 td->ival = tdn->h1[0];
229 }
230
231 td->extra = tdn;
232 td++;
233 }
234 if (FrameOnMouseSide(t->frame_side, strip->end, (float)CFRA)) {
235 /* if tdn is already holding the start handle,
236 * then we're doing both, otherwise, only end */
237 tdn->handle = (tdn->handle) ? 2 : 1;
238
239 /* now, link the transform data up to this data */
240 if (ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_EXTEND)) {
241 td->loc = tdn->h2;
242 copy_v3_v3(td->iloc, tdn->h2);
243
244 /* store all the other gunk that is required by transform */
245 copy_v3_v3(td->center, center);
246 memset(td->axismtx, 0, sizeof(td->axismtx));
247 td->axismtx[2][2] = 1.0f;
248
249 td->ext = NULL;
250 td->val = NULL;
251
252 td->flag |= TD_SELECTED;
253 td->dist = 0.0f;
254
255 unit_m3(td->mtx);
256 unit_m3(td->smtx);
257 }
258 else {
259 /* time scaling only needs single value */
260 td->val = &tdn->h2[0];
261 td->ival = tdn->h2[0];
262 }
263
264 td->extra = tdn;
265 td++;
266 }
267
268 /* If both handles were used, skip the next tdn (i.e. leave it blank)
269 * since the counting code is dumb.
270 * Otherwise, just advance to the next one.
271 */
272 if (tdn->handle == 2) {
273 tdn += 2;
274 }
275 else {
276 tdn++;
277 }
278 }
279 }
280 }
281 }
282 }
283
284 /* cleanup temp list */
285 ANIM_animdata_freelist(&anim_data);
286 }
287
288 /* helper for recalcData() - for NLA Editor transforms */
recalcData_nla(TransInfo * t)289 void recalcData_nla(TransInfo *t)
290 {
291 SpaceNla *snla = (SpaceNla *)t->area->spacedata.first;
292 Scene *scene = t->scene;
293 double secf = FPS;
294 int i;
295
296 TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
297 TransDataNla *tdn = tc->custom.type.data;
298
299 /* For each strip we've got, perform some additional validation of the values
300 * that got set before using RNA to set the value (which does some special
301 * operations when setting these values to make sure that everything works ok).
302 */
303 for (i = 0; i < tc->data_len; i++, tdn++) {
304 NlaStrip *strip = tdn->strip;
305 PointerRNA strip_ptr;
306 short pExceeded, nExceeded, iter;
307 int delta_y1, delta_y2;
308
309 /* if this tdn has no handles, that means it is just a dummy that should be skipped */
310 if (tdn->handle == 0) {
311 continue;
312 }
313
314 /* set refresh tags for objects using this animation,
315 * BUT only if realtime updates are enabled
316 */
317 if ((snla->flag & SNLA_NOREALTIMEUPDATES) == 0) {
318 ANIM_id_update(CTX_data_main(t->context), tdn->id);
319 }
320
321 /* if canceling transform, just write the values without validating, then move on */
322 if (t->state == TRANS_CANCEL) {
323 /* clear the values by directly overwriting the originals, but also need to restore
324 * endpoints of neighboring transition-strips
325 */
326
327 /* start */
328 strip->start = tdn->h1[0];
329
330 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) {
331 strip->prev->end = tdn->h1[0];
332 }
333
334 /* end */
335 strip->end = tdn->h2[0];
336
337 if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION)) {
338 strip->next->start = tdn->h2[0];
339 }
340
341 /* flush transforms to child strips (since this should be a meta) */
342 BKE_nlameta_flush_transforms(strip);
343
344 /* restore to original track (if needed) */
345 if (tdn->oldTrack != tdn->nlt) {
346 /* Just append to end of list for now,
347 * since strips get sorted in special_aftertrans_update(). */
348 BLI_remlink(&tdn->nlt->strips, strip);
349 BLI_addtail(&tdn->oldTrack->strips, strip);
350 }
351
352 continue;
353 }
354
355 /* firstly, check if the proposed transform locations would overlap with any neighboring strips
356 * (barring transitions) which are absolute barriers since they are not being moved
357 *
358 * this is done as a iterative procedure (done 5 times max for now)
359 */
360 for (iter = 0; iter < 5; iter++) {
361 pExceeded = ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) &&
362 (tdn->h1[0] < strip->prev->end));
363 nExceeded = ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) &&
364 (tdn->h2[0] > strip->next->start));
365
366 if ((pExceeded && nExceeded) || (iter == 4)) {
367 /* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
368 * - Simply crop strip to fit within the bounds of the strips bounding it
369 * - If there were no neighbors, clear the transforms
370 * (make it default to the strip's current values).
371 */
372 if (strip->prev && strip->next) {
373 tdn->h1[0] = strip->prev->end;
374 tdn->h2[0] = strip->next->start;
375 }
376 else {
377 tdn->h1[0] = strip->start;
378 tdn->h2[0] = strip->end;
379 }
380 }
381 else if (nExceeded) {
382 /* move backwards */
383 float offset = tdn->h2[0] - strip->next->start;
384
385 tdn->h1[0] -= offset;
386 tdn->h2[0] -= offset;
387 }
388 else if (pExceeded) {
389 /* more forwards */
390 float offset = strip->prev->end - tdn->h1[0];
391
392 tdn->h1[0] += offset;
393 tdn->h2[0] += offset;
394 }
395 else { /* all is fine and well */
396 break;
397 }
398 }
399
400 /* handle auto-snapping
401 * NOTE: only do this when transform is still running, or we can't restore
402 */
403 if (t->state != TRANS_CANCEL) {
404 switch (snla->autosnap) {
405 case SACTSNAP_FRAME: /* snap to nearest frame */
406 case SACTSNAP_STEP: /* frame step - this is basically the same,
407 * since we don't have any remapping going on */
408 {
409 tdn->h1[0] = floorf(tdn->h1[0] + 0.5f);
410 tdn->h2[0] = floorf(tdn->h2[0] + 0.5f);
411 break;
412 }
413
414 case SACTSNAP_SECOND: /* snap to nearest second */
415 case SACTSNAP_TSTEP: /* second step - this is basically the same,
416 * since we don't have any remapping going on */
417 {
418 /* This case behaves differently from the rest, since lengths of strips
419 * may not be multiples of a second. If we just naively resize adjust
420 * the handles, things may not work correctly. Instead, we only snap
421 * the first handle, and move the other to fit.
422 *
423 * FIXME: we do run into problems here when user attempts to negatively
424 * scale the strip, as it then just compresses down and refuses
425 * to expand out the other end.
426 */
427 float h1_new = (float)(floor(((double)tdn->h1[0] / secf) + 0.5) * secf);
428 float delta = h1_new - tdn->h1[0];
429
430 tdn->h1[0] = h1_new;
431 tdn->h2[0] += delta;
432 break;
433 }
434
435 case SACTSNAP_MARKER: /* snap to nearest marker */
436 {
437 tdn->h1[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
438 tdn->h2[0] = (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
439 break;
440 }
441 }
442 }
443
444 /* Use RNA to write the values to ensure that constraints on these are obeyed
445 * (e.g. for transition strips, the values are taken from the neighbors)
446 *
447 * NOTE: we write these twice to avoid truncation errors which can arise when
448 * moving the strips a large distance using numeric input T33852.
449 */
450 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
451
452 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
453 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
454
455 RNA_float_set(&strip_ptr, "frame_start", tdn->h1[0]);
456 RNA_float_set(&strip_ptr, "frame_end", tdn->h2[0]);
457
458 /* flush transforms to child strips (since this should be a meta) */
459 BKE_nlameta_flush_transforms(strip);
460
461 /* Now, check if we need to try and move track:
462 * - we need to calculate both,
463 * as only one may have been altered by transform if only 1 handle moved.
464 */
465 delta_y1 = ((int)tdn->h1[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
466 delta_y2 = ((int)tdn->h2[1] / NLACHANNEL_STEP(snla) - tdn->trackIndex);
467
468 if (delta_y1 || delta_y2) {
469 NlaTrack *track;
470 int delta = (delta_y2) ? delta_y2 : delta_y1;
471 int n;
472
473 /* Move in the requested direction,
474 * checking at each layer if there's space for strip to pass through,
475 * stopping on the last track available or that we're able to fit in.
476 */
477 if (delta > 0) {
478 for (track = tdn->nlt->next, n = 0; (track) && (n < delta); track = track->next, n++) {
479 /* check if space in this track for the strip */
480 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
481 /* move strip to this track */
482 BLI_remlink(&tdn->nlt->strips, strip);
483 BKE_nlatrack_add_strip(track, strip);
484
485 tdn->nlt = track;
486 tdn->trackIndex++;
487 }
488 else { /* can't move any further */
489 break;
490 }
491 }
492 }
493 else {
494 /* make delta 'positive' before using it, since we now know to go backwards */
495 delta = -delta;
496
497 for (track = tdn->nlt->prev, n = 0; (track) && (n < delta); track = track->prev, n++) {
498 /* check if space in this track for the strip */
499 if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
500 /* move strip to this track */
501 BLI_remlink(&tdn->nlt->strips, strip);
502 BKE_nlatrack_add_strip(track, strip);
503
504 tdn->nlt = track;
505 tdn->trackIndex--;
506 }
507 else { /* can't move any further */
508 break;
509 }
510 }
511 }
512 }
513 }
514 }
515
516 /** \} */
517
518 /* -------------------------------------------------------------------- */
519 /** \name Special After Transform NLA
520 * \{ */
521
special_aftertrans_update__nla(bContext * C,TransInfo * UNUSED (t))522 void special_aftertrans_update__nla(bContext *C, TransInfo *UNUSED(t))
523 {
524 bAnimContext ac;
525
526 /* initialize relevant anim-context 'context' data */
527 if (ANIM_animdata_get_context(C, &ac) == 0) {
528 return;
529 }
530
531 if (ac.datatype) {
532 ListBase anim_data = {NULL, NULL};
533 bAnimListElem *ale;
534 short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT);
535
536 /* get channels to work on */
537 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
538
539 for (ale = anim_data.first; ale; ale = ale->next) {
540 NlaTrack *nlt = (NlaTrack *)ale->data;
541
542 /* make sure strips are in order again */
543 BKE_nlatrack_sort_strips(nlt);
544
545 /* remove the temp metas */
546 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
547 }
548
549 /* free temp memory */
550 ANIM_animdata_freelist(&anim_data);
551
552 /* perform after-transfrom validation */
553 ED_nla_postop_refresh(&ac);
554 }
555 }
556
557 /** \} */
558