Blender V4.3
strip_transform.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 * SPDX-FileCopyrightText: 2003-2009 Blender Authors
3 * SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later */
6
10
11#include "DNA_scene_types.h"
12#include "DNA_sequence_types.h"
13
14#include "BLI_listbase.h"
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
19
20#include "SEQ_animation.hh"
21#include "SEQ_channels.hh"
22#include "SEQ_edit.hh"
23#include "SEQ_effects.hh"
24#include "SEQ_iterator.hh"
25#include "SEQ_relations.hh"
26#include "SEQ_sequencer.hh"
27#include "SEQ_time.hh"
28#include "SEQ_transform.hh"
29
30#include "sequencer.hh"
31#include "strip_time.hh"
32
34{
35 return (seq->flag & SEQ_SINGLE_FRAME_CONTENT) != 0;
36}
37
39{
40 /* is there more than 1 select */
41 bool ok = false;
42
43 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
44 if (seq->flag & SELECT) {
45 ok = true;
46 break;
47 }
48 }
49
50 if (ok == false) {
51 return false;
52 }
53
54 /* test relationships */
55 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
56 if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
57 continue;
58 }
59
60 if (seq->flag & SELECT) {
61 if ((seq->seq1 && (seq->seq1->flag & SELECT) == 0) ||
62 (seq->seq2 && (seq->seq2->flag & SELECT) == 0))
63 {
64 return false;
65 }
66 }
67 else {
68 if ((seq->seq1 && (seq->seq1->flag & SELECT)) || (seq->seq2 && (seq->seq2->flag & SELECT))) {
69 return false;
70 }
71 }
72 }
73
74 return true;
75}
76
78{
79 return !(seq->type & SEQ_TYPE_EFFECT) || (SEQ_effect_get_num_inputs(seq->type) == 0);
80}
81
83{
84 return (seq1 != seq2 && seq1->machine == seq2->machine &&
85 ((SEQ_time_right_handle_frame_get(scene, seq1) <=
86 SEQ_time_left_handle_frame_get(scene, seq2)) ||
87 (SEQ_time_left_handle_frame_get(scene, seq1) >=
88 SEQ_time_right_handle_frame_get(scene, seq2))) == 0);
89}
90
91bool SEQ_transform_test_overlap(const Scene *scene, ListBase *seqbasep, Sequence *test)
92{
93 Sequence *seq;
94
95 seq = static_cast<Sequence *>(seqbasep->first);
96 while (seq) {
97 if (SEQ_transform_test_overlap_seq_seq(scene, test, seq)) {
98 return true;
99 }
100
101 seq = seq->next;
102 }
103 return false;
104}
105
106void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delta)
107{
108 if (delta == 0) {
109 return;
110 }
111
112 /* Meta strips requires their content is to be translated, and then frame range of the meta is
113 * updated based on nested strips. This won't work for empty meta-strips,
114 * so they can be treated as normal strip. */
115 if (seq->type == SEQ_TYPE_META && !BLI_listbase_is_empty(&seq->seqbase)) {
116 LISTBASE_FOREACH (Sequence *, seq_child, &seq->seqbase) {
117 SEQ_transform_translate_sequence(evil_scene, seq_child, delta);
118 }
119 /* Move meta start/end points. */
120 seq_time_translate_handles(evil_scene, seq, delta);
121 }
122 else if (seq->seq1 == nullptr && seq->seq2 == nullptr) { /* All other strip types. */
123 seq->start += delta;
124 /* Only to make files usable in older versions. */
125 seq->startdisp = SEQ_time_left_handle_frame_get(evil_scene, seq);
126 seq->enddisp = SEQ_time_right_handle_frame_get(evil_scene, seq);
127 }
128
129 SEQ_offset_animdata(evil_scene, seq, delta);
130 blender::Span effects = seq_sequence_lookup_effects_by_seq(evil_scene, seq);
131 seq_time_update_effects_strip_range(evil_scene, effects);
133}
134
136 Sequence *test,
137 Scene *evil_scene,
138 int channel_delta)
139{
140 const int orig_machine = test->machine;
141 BLI_assert(ELEM(channel_delta, -1, 1));
142
143 test->machine += channel_delta;
144 while (SEQ_transform_test_overlap(evil_scene, seqbasep, test)) {
145 if ((channel_delta > 0) ? (test->machine >= SEQ_MAX_CHANNELS) : (test->machine < 1)) {
146 break;
147 }
148
149 test->machine += channel_delta;
150 }
151
152 if (!SEQ_is_valid_strip_channel(test)) {
153 /* Blender 2.4x would remove the strip.
154 * nicer to move it to the end */
155
156 int new_frame = SEQ_time_right_handle_frame_get(evil_scene, test);
157
158 LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
159 if (seq->machine == orig_machine) {
160 new_frame = max_ii(new_frame, SEQ_time_right_handle_frame_get(evil_scene, seq));
161 }
162 }
163
164 test->machine = orig_machine;
165 new_frame = new_frame + (test->start - SEQ_time_left_handle_frame_get(
166 evil_scene, test)); /* adjust by the startdisp */
167 SEQ_transform_translate_sequence(evil_scene, test, new_frame - test->start);
168 return false;
169 }
170
171 return true;
172}
173
174bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
175{
176 return SEQ_transform_seqbase_shuffle_ex(seqbasep, test, evil_scene, 1);
177}
178
179static bool shuffle_seq_test_overlap(const Scene *scene,
180 const Sequence *seq1,
181 const Sequence *seq2,
182 const int offset)
183{
184 BLI_assert(seq1 != seq2);
185 return (seq1->machine == seq2->machine &&
186 ((SEQ_time_right_handle_frame_get(scene, seq1) + offset <=
187 SEQ_time_left_handle_frame_get(scene, seq2)) ||
188 (SEQ_time_left_handle_frame_get(scene, seq1) + offset >=
189 SEQ_time_right_handle_frame_get(scene, seq2))) == 0);
190}
191
192static int shuffle_seq_time_offset_get(const Scene *scene,
193 blender::Span<Sequence *> strips_to_shuffle,
194 ListBase *seqbasep,
195 char dir)
196{
197 int offset = 0;
198 bool all_conflicts_resolved = false;
199
200 while (!all_conflicts_resolved) {
201 all_conflicts_resolved = true;
202 for (Sequence *seq : strips_to_shuffle) {
203 LISTBASE_FOREACH (Sequence *, seq_other, seqbasep) {
204 if (strips_to_shuffle.contains(seq_other)) {
205 continue;
206 }
207 if (SEQ_relation_is_effect_of_strip(seq_other, seq)) {
208 continue;
209 }
210 if (!shuffle_seq_test_overlap(scene, seq, seq_other, offset)) {
211 continue;
212 }
213
214 all_conflicts_resolved = false;
215
216 if (dir == 'L') {
217 offset = min_ii(offset,
218 SEQ_time_left_handle_frame_get(scene, seq_other) -
220 }
221 else {
222 offset = max_ii(offset,
223 SEQ_time_right_handle_frame_get(scene, seq_other) -
225 }
226 }
227 }
228 }
229
230 return offset;
231}
232
234 ListBase *seqbasep,
235 Scene *evil_scene,
236 ListBase *markers,
237 const bool use_sync_markers)
238{
241 strips_to_shuffle, empty_set, seqbasep, evil_scene, markers, use_sync_markers);
242}
243
245 blender::Span<Sequence *> time_dependent_strips,
246 ListBase *seqbasep,
247 Scene *evil_scene,
248 ListBase *markers,
249 const bool use_sync_markers)
250{
251 int offset_l = shuffle_seq_time_offset_get(evil_scene, strips_to_shuffle, seqbasep, 'L');
252 int offset_r = shuffle_seq_time_offset_get(evil_scene, strips_to_shuffle, seqbasep, 'R');
253 int offset = (-offset_l < offset_r) ? offset_l : offset_r;
254
255 if (offset) {
256 for (Sequence *seq : strips_to_shuffle) {
257 SEQ_transform_translate_sequence(evil_scene, seq, offset);
258 seq->flag &= ~SEQ_OVERLAP;
259 }
260
261 if (!time_dependent_strips.is_empty()) {
262 for (Sequence *seq : time_dependent_strips) {
263 SEQ_offset_animdata(evil_scene, seq, offset);
264 }
265 }
266
267 if (use_sync_markers && !(evil_scene->toolsettings->lock_markers) && (markers != nullptr)) {
268 /* affect selected markers - it's unlikely that we will want to affect all in this way? */
269 LISTBASE_FOREACH (TimeMarker *, marker, markers) {
270 if (marker->flag & SELECT) {
271 marker->frame += offset;
272 }
273 }
274 }
275 }
276
277 return offset ? false : true;
278}
279
281 blender::Span<Sequence *> transformed_strips)
282{
283 blender::VectorSet<Sequence *> standalone_strips;
284
285 for (Sequence *seq : transformed_strips) {
286 if ((seq->type & SEQ_TYPE_EFFECT) == 0 || seq->seq1 == nullptr) {
287 standalone_strips.add(seq);
288 }
289 }
290 return standalone_strips;
291}
292
293/* Query strips positioned after left edge of transformed strips bound-box. */
295 const Scene *scene,
296 ListBase *seqbase,
297 blender::Span<Sequence *> transformed_strips,
298 blender::Span<Sequence *> time_dependent_strips)
299{
300 int minframe = MAXFRAME;
301 {
302 for (Sequence *seq : transformed_strips) {
303 minframe = min_ii(minframe, SEQ_time_left_handle_frame_get(scene, seq));
304 }
305 }
306
307 blender::VectorSet<Sequence *> right_side_strips;
308 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
309 if (!time_dependent_strips.is_empty() && time_dependent_strips.contains(seq)) {
310 continue;
311 }
312 if (transformed_strips.contains(seq)) {
313 continue;
314 }
315
316 if ((seq->flag & SELECT) == 0 && SEQ_time_left_handle_frame_get(scene, seq) >= minframe) {
317 right_side_strips.add(seq);
318 }
319 }
320 return right_side_strips;
321}
322
323/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal
324 * to overlap of transformed strips. */
326 ListBase *seqbasep,
327 blender::Span<Sequence *> transformed_strips,
328 blender::Span<Sequence *> time_dependent_strips,
329 bool use_sync_markers)
330{
331 ListBase *markers = &scene->markers;
332
334 scene, seqbasep, transformed_strips, time_dependent_strips);
335
336 /* Temporarily move right side strips beyond timeline boundary. */
337 for (Sequence *seq : right_side_strips) {
338 seq->machine += SEQ_MAX_CHANNELS * 2;
339 }
340
341 /* Shuffle transformed standalone strips. This is because transformed strips can overlap with
342 * strips on left side. */
343 blender::VectorSet standalone_strips = extract_standalone_strips(transformed_strips);
345 standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
346
347 /* Move temporarily moved strips back to their original place and tag for shuffling. */
348 for (Sequence *seq : right_side_strips) {
349 seq->machine -= SEQ_MAX_CHANNELS * 2;
350 }
351 /* Shuffle again to displace strips on right side. Final effect shuffling is done in
352 * SEQ_transform_handle_overlap. */
354 right_side_strips, seqbasep, scene, markers, use_sync_markers);
355}
356
358 const Scene *scene, ListBase *seqbasep, blender::Span<Sequence *> transformed_strips)
359{
361
362 /* Effects of transformed strips can be unselected. These must not be included. */
363 overwrite_targets.remove_if([&](Sequence *seq) { return transformed_strips.contains(seq); });
364 overwrite_targets.remove_if([&](Sequence *seq) {
365 bool does_overlap = false;
366 for (Sequence *seq_transformed : transformed_strips) {
367 if (SEQ_transform_test_overlap_seq_seq(scene, seq, seq_transformed)) {
368 does_overlap = true;
369 }
370 }
371
372 return !does_overlap;
373 });
374
375 return overwrite_targets;
376}
377
379 /* No overlap. */
381 /* Overlapping strip covers overlapped completely. */
383 /* Overlapping strip is inside overlapped. */
385 /* Partial overlap between 2 strips. */
388};
389
391 const Sequence *transformed,
392 const Sequence *target)
393{
394 if (SEQ_time_left_handle_frame_get(scene, transformed) <=
395 SEQ_time_left_handle_frame_get(scene, target) &&
396 SEQ_time_right_handle_frame_get(scene, transformed) >=
397 SEQ_time_right_handle_frame_get(scene, target))
398 {
400 }
401 if (SEQ_time_left_handle_frame_get(scene, transformed) >
402 SEQ_time_left_handle_frame_get(scene, target) &&
403 SEQ_time_right_handle_frame_get(scene, transformed) <
404 SEQ_time_right_handle_frame_get(scene, target))
405 {
407 }
408 if (SEQ_time_left_handle_frame_get(scene, transformed) <=
409 SEQ_time_left_handle_frame_get(scene, target) &&
410 SEQ_time_left_handle_frame_get(scene, target) <=
411 SEQ_time_right_handle_frame_get(scene, transformed))
412 {
414 }
415 if (SEQ_time_left_handle_frame_get(scene, transformed) <=
416 SEQ_time_right_handle_frame_get(scene, target) &&
417 SEQ_time_right_handle_frame_get(scene, target) <=
418 SEQ_time_right_handle_frame_get(scene, transformed))
419 {
421 }
422 return STRIP_OVERLAP_NONE;
423}
424
425/* Split strip in 3 parts, remove middle part and fit transformed inside. */
427 ListBase *seqbasep,
428 const Sequence *transformed,
429 Sequence *target)
430{
431 /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can
432 * pass nullptr here. */
433 Main *bmain = nullptr;
434
435 Sequence *split_strip = SEQ_edit_strip_split(bmain,
436 scene,
437 seqbasep,
438 target,
439 SEQ_time_left_handle_frame_get(scene, transformed),
441 nullptr);
443 scene,
444 seqbasep,
445 split_strip,
446 SEQ_time_right_handle_frame_get(scene, transformed),
448 nullptr);
449 SEQ_edit_flag_for_removal(scene, seqbasep, split_strip);
450 SEQ_edit_remove_flagged_sequences(scene, seqbasep);
451}
452
453/* Trim strips by adjusting handle position.
454 * This is bit more complicated in case overlap happens on effect. */
456 ListBase *seqbasep,
457 const Sequence *transformed,
458 Sequence *target,
459 const eOvelapDescrition overlap)
460{
462 target, scene, seqbasep, SEQ_query_strip_effect_chain);
463
464 /* Expand collection by adding all target's children, effects and their children. */
465 if ((target->type & SEQ_TYPE_EFFECT) != 0) {
466 SEQ_iterator_set_expand(scene, seqbasep, targets, SEQ_query_strip_effect_chain);
467 }
468
469 /* Trim all non effects, that have influence on effect length which is overlapping. */
470 for (Sequence *seq : targets) {
471 if ((seq->type & SEQ_TYPE_EFFECT) != 0 && SEQ_effect_get_num_inputs(seq->type) > 0) {
472 continue;
473 }
474 if (overlap == STRIP_OVERLAP_LEFT_SIDE) {
476 scene, seq, SEQ_time_right_handle_frame_get(scene, transformed));
477 }
478 else {
481 scene, seq, SEQ_time_left_handle_frame_get(scene, transformed));
482 }
483 }
484}
485
487 ListBase *seqbasep,
488 blender::Span<Sequence *> transformed_strips)
489{
490 blender::VectorSet targets = query_overwrite_targets(scene, seqbasep, transformed_strips);
491 blender::VectorSet<Sequence *> strips_to_delete;
492
493 for (Sequence *target : targets) {
494 for (Sequence *transformed : transformed_strips) {
495 if (transformed->machine != target->machine) {
496 continue;
497 }
498
499 const eOvelapDescrition overlap = overlap_description_get(scene, transformed, target);
500
501 if (overlap == STRIP_OVERLAP_IS_FULL) {
502 strips_to_delete.add(target);
503 }
504 else if (overlap == STRIP_OVERLAP_IS_INSIDE) {
505 seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target);
506 }
508 seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap);
509 }
510 }
511 }
512
513 /* Remove covered strips. This must be done in separate loop, because
514 * `SEQ_edit_strip_split()` also uses `SEQ_edit_remove_flagged_sequences()`. See #91096. */
515 if (!strips_to_delete.is_empty()) {
516 for (Sequence *seq : strips_to_delete) {
517 SEQ_edit_flag_for_removal(scene, seqbasep, seq);
518 }
519 SEQ_edit_remove_flagged_sequences(scene, seqbasep);
520 }
521}
522
524 ListBase *seqbasep,
525 blender::Span<Sequence *> transformed_strips,
526 blender::Span<Sequence *> time_dependent_strips,
527 bool use_sync_markers)
528{
529 ListBase *markers = &scene->markers;
530
531 /* Shuffle non strips with no effects attached. */
532 blender::VectorSet standalone_strips = extract_standalone_strips(transformed_strips);
534 standalone_strips, time_dependent_strips, seqbasep, scene, markers, use_sync_markers);
535}
536
538 ListBase *seqbasep,
539 blender::Span<Sequence *> transformed_strips,
540 bool use_sync_markers)
541{
543 SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, empty_set, use_sync_markers);
544}
545
547 ListBase *seqbasep,
548 blender::Span<Sequence *> transformed_strips,
549 blender::Span<Sequence *> time_dependent_strips,
550 bool use_sync_markers)
551{
552 const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene);
553
554 switch (overlap_mode) {
557 scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
558 break;
560 seq_transform_handle_overwrite(scene, seqbasep, transformed_strips);
561 break;
564 scene, seqbasep, transformed_strips, time_dependent_strips, use_sync_markers);
565 break;
566 }
567
568 /* If any effects still overlap, we need to move them up.
569 * In some cases other strips can be overlapping still, see #90646. */
570 for (Sequence *seq : transformed_strips) {
571 if (SEQ_transform_test_overlap(scene, seqbasep, seq)) {
572 SEQ_transform_seqbase_shuffle(seqbasep, seq, scene);
573 }
574 seq->flag &= ~SEQ_OVERLAP;
575 }
576}
577
579 ListBase *seqbase,
580 const int delta,
581 const int timeline_frame)
582{
583 LISTBASE_FOREACH (Sequence *, seq, seqbase) {
584 if (SEQ_time_left_handle_frame_get(scene, seq) >= timeline_frame) {
585 SEQ_transform_translate_sequence(scene, seq, delta);
587 }
588 }
589
590 if (!scene->toolsettings->lock_markers) {
591 LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) {
592 if (marker->frame >= timeline_frame) {
593 marker->frame += delta;
594 }
595 }
596 }
597}
598
600{
602 return seq->flag & SEQ_LOCK ||
603 (SEQ_channel_is_locked(channel) && ((seq->flag & SEQ_IGNORE_CHANNEL_LOCK) == 0));
604}
605
606void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2])
607{
608 r_mirror[0] = 1.0f;
609 r_mirror[1] = 1.0f;
610
611 if ((seq->flag & SEQ_FLIPX) != 0) {
612 r_mirror[0] = -1.0f;
613 }
614 if ((seq->flag & SEQ_FLIPY) != 0) {
615 r_mirror[1] = -1.0f;
616 }
617}
618
620 const Sequence *seq,
621 float r_origin[2])
622{
623 float image_size[2];
624 const StripElem *strip_elem = seq->strip->stripdata;
625 if (strip_elem == nullptr) {
626 image_size[0] = scene->r.xsch;
627 image_size[1] = scene->r.ysch;
628 }
629 else {
630 image_size[0] = strip_elem->orig_width;
631 image_size[1] = strip_elem->orig_height;
632 }
633
635 r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
636 r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
637
638 const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
639 float mirror[2];
641 mul_v2_v2(r_origin, mirror);
642 mul_v2_v2(r_origin, viewport_pixel_aspect);
643}
644
645static void seq_image_transform_quad_get_ex(const Scene *scene,
646 const Sequence *seq,
647 bool apply_rotation,
648 float r_quad[4][2])
649{
651 const StripCrop *crop = seq->strip->crop;
652
653 float image_size[2] = {float(scene->r.xsch), float(scene->r.ysch)};
655 image_size[0] = seq->strip->stripdata->orig_width;
656 image_size[1] = seq->strip->stripdata->orig_height;
657 }
658
659 float transform_matrix[4][4];
660 float rotation_matrix[3][3];
661 axis_angle_to_mat3_single(rotation_matrix, 'Z', apply_rotation ? transform->rotation : 0.0f);
662 loc_rot_size_to_mat4(transform_matrix,
663 blender::float3{transform->xofs, transform->yofs, 0.0f},
664 rotation_matrix,
665 blender::float3{transform->scale_x, transform->scale_y, 1.0f});
666 const float origin[2] = {image_size[0] * transform->origin[0],
667 image_size[1] * transform->origin[1]};
668 const float pivot[3] = {origin[0] - (image_size[0] / 2), origin[1] - (image_size[1] / 2), 0.0f};
669 transform_pivot_set_m4(transform_matrix, pivot);
670
671 float quad_temp[4][3];
672 for (int i = 0; i < 4; i++) {
673 zero_v3(quad_temp[i]);
674 }
675
676 quad_temp[0][0] = (image_size[0] / 2) - crop->right;
677 quad_temp[0][1] = (image_size[1] / 2) - crop->top;
678 quad_temp[1][0] = (image_size[0] / 2) - crop->right;
679 quad_temp[1][1] = (-image_size[1] / 2) + crop->bottom;
680 quad_temp[2][0] = (-image_size[0] / 2) + crop->left;
681 quad_temp[2][1] = (-image_size[1] / 2) + crop->bottom;
682 quad_temp[3][0] = (-image_size[0] / 2) + crop->left;
683 quad_temp[3][1] = (image_size[1] / 2) - crop->top;
684
685 float mirror[2];
687
688 const float viewport_pixel_aspect[2] = {scene->r.xasp / scene->r.yasp, 1.0f};
689
690 for (int i = 0; i < 4; i++) {
691 mul_m4_v3(transform_matrix, quad_temp[i]);
692 mul_v2_v2(quad_temp[i], mirror);
693 mul_v2_v2(quad_temp[i], viewport_pixel_aspect);
694 copy_v2_v2(r_quad[i], quad_temp[i]);
695 }
696}
697
699 const Sequence *seq,
700 bool apply_rotation,
701 float r_quad[4][2])
702{
703 seq_image_transform_quad_get_ex(scene, seq, apply_rotation, r_quad);
704}
705
707 const Sequence *seq,
708 float r_quad[4][2])
709{
710 seq_image_transform_quad_get_ex(scene, seq, true, r_quad);
711}
712
713void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
714{
715 co_dst[0] = co_src[0] * scene->r.xsch;
716 co_dst[1] = co_src[1] * scene->r.ysch;
717}
718
719void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2])
720{
721 co_dst[0] = co_src[0] / scene->r.xsch;
722 co_dst[1] = co_src[1] / scene->r.ysch;
723}
724
727 bool apply_rotation,
728 float r_min[2],
729 float r_max[2])
730{
731 INIT_MINMAX2(r_min, r_max);
732 for (Sequence *seq : strips) {
733 float quad[4][2];
734 SEQ_image_transform_quad_get(scene, seq, apply_rotation, quad);
735 for (int i = 0; i < 4; i++) {
736 minmax_v2v2_v2(r_min, r_max, quad[i]);
737 }
738 }
739}
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void loc_rot_size_to_mat4(float R[4][4], const float loc[3], const float rot[3][3], const float size[3])
void transform_pivot_set_m4(float mat[4][4], const float pivot[3])
void mul_m4_v3(const float M[4][4], float r[3])
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
MINLINE void mul_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2(float r[2], const float a[2])
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
MINLINE void zero_v3(float r[3])
#define INIT_MINMAX2(min, max)
#define ELEM(...)
eSeqOverlapMode
@ SEQ_OVERLAP_EXPAND
@ SEQ_OVERLAP_SHUFFLE
@ SEQ_OVERLAP_OVERWRITE
#define MAXFRAME
@ SEQ_TYPE_META
@ SEQ_TYPE_IMAGE
@ SEQ_TYPE_EFFECT
@ SEQ_TYPE_MOVIE
@ SEQ_SINGLE_FRAME_CONTENT
@ SEQ_FLIPX
@ SEQ_IGNORE_CHANNEL_LOCK
@ SEQ_OVERLAP
@ SEQ_FLIPY
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
@ SEQ_SPLIT_SOFT
Definition SEQ_edit.hh:55
constexpr int SEQ_MAX_CHANNELS
void SEQ_offset_animdata(Scene *scene, Sequence *seq, int ofs)
Definition animation.cc:69
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
SeqTimelineChannel * SEQ_channel_get_by_index(const ListBase *channels, const int channel_index)
Definition channels.cc:61
bool SEQ_channel_is_locked(const SeqTimelineChannel *channel)
Definition channels.cc:77
constexpr bool is_empty() const
Definition BLI_span.hh:261
constexpr bool contains(const T &value) const
Definition BLI_span.hh:278
bool add(const Key &key)
int64_t remove_if(Predicate &&predicate)
#define SELECT
draw_view in_light_buf[] float
int SEQ_effect_get_num_inputs(int seq_type)
Definition effects.cc:3467
blender::gpu::Batch * quad
VectorSet< Sequence * > SEQ_query_unselected_strips(ListBase *seqbase)
Definition iterator.cc:198
void SEQ_iterator_set_expand(const Scene *scene, ListBase *seqbase, VectorSet< Sequence * > &strips, void seq_query_func(const Scene *scene, Sequence *seq_reference, ListBase *seqbase, VectorSet< Sequence * > &strips))
Definition iterator.cc:61
void SEQ_query_strip_effect_chain(const Scene *scene, Sequence *reference_strip, ListBase *seqbase, VectorSet< Sequence * > &strips)
Definition iterator.cc:210
VectorSet< Sequence * > SEQ_query_by_reference(Sequence *seq_reference, const Scene *scene, ListBase *seqbase, void seq_query_func(const Scene *scene, Sequence *seq_reference, ListBase *seqbase, VectorSet< Sequence * > &strips))
Definition iterator.cc:48
VecBase< float, 3 > float3
Sequence * seq_sequence_lookup_meta_by_seq(const Scene *scene, const Sequence *key)
blender::Span< Sequence * > seq_sequence_lookup_effects_by_seq(const Scene *scene, const Sequence *key)
eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(Scene *scene)
Definition sequencer.cc:404
bool SEQ_is_valid_strip_channel(const Sequence *seq)
Definition sequencer.cc:696
void SEQ_edit_flag_for_removal(Scene *scene, ListBase *seqbase, Sequence *seq)
Sequence * SEQ_edit_strip_split(Main *bmain, Scene *scene, ListBase *seqbase, Sequence *seq, const int timeline_frame, const eSeqSplitMethod method, const char **r_error)
void SEQ_edit_remove_flagged_sequences(Scene *scene, ListBase *seqbase)
bool SEQ_relation_is_effect_of_strip(const Sequence *effect, const Sequence *input)
void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq)
void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
int SEQ_time_left_handle_frame_get(const Scene *, const Sequence *seq)
void seq_time_translate_handles(const Scene *scene, Sequence *seq, const int offset)
void seq_time_update_effects_strip_range(const Scene *scene, const blender::Span< Sequence * > effects)
int SEQ_time_right_handle_frame_get(const Scene *scene, const Sequence *seq)
void SEQ_image_transform_quad_get(const Scene *scene, const Sequence *seq, bool apply_rotation, float r_quad[4][2])
bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase)
static void seq_transform_handle_overwrite(Scene *scene, ListBase *seqbasep, blender::Span< Sequence * > transformed_strips)
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep, Sequence *test, Scene *evil_scene, int channel_delta)
static void seq_image_transform_quad_get_ex(const Scene *scene, const Sequence *seq, bool apply_rotation, float r_quad[4][2])
bool SEQ_transform_seqbase_shuffle(ListBase *seqbasep, Sequence *test, Scene *evil_scene)
static eOvelapDescrition overlap_description_get(const Scene *scene, const Sequence *transformed, const Sequence *target)
void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
void SEQ_image_transform_bounding_box_from_collection(Scene *scene, blender::Span< Sequence * > strips, bool apply_rotation, float r_min[2], float r_max[2])
bool SEQ_transform_test_overlap(const Scene *scene, ListBase *seqbasep, Sequence *test)
static void seq_transform_handle_overwrite_split(Scene *scene, ListBase *seqbasep, const Sequence *transformed, Sequence *target)
static blender::VectorSet< Sequence * > extract_standalone_strips(blender::Span< Sequence * > transformed_strips)
static void seq_transform_handle_overlap_shuffle(Scene *scene, ListBase *seqbasep, blender::Span< Sequence * > transformed_strips, blender::Span< Sequence * > time_dependent_strips, bool use_sync_markers)
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, const Sequence *seq, float r_origin[2])
void SEQ_image_transform_final_quad_get(const Scene *scene, const Sequence *seq, float r_quad[4][2])
bool SEQ_transform_seqbase_shuffle_time(blender::Span< Sequence * > strips_to_shuffle, ListBase *seqbasep, Scene *evil_scene, ListBase *markers, const bool use_sync_markers)
static bool shuffle_seq_test_overlap(const Scene *scene, const Sequence *seq1, const Sequence *seq2, const int offset)
static blender::VectorSet< Sequence * > query_right_side_strips(const Scene *scene, ListBase *seqbase, blender::Span< Sequence * > transformed_strips, blender::Span< Sequence * > time_dependent_strips)
static void seq_transform_handle_expand_to_fit(Scene *scene, ListBase *seqbasep, blender::Span< Sequence * > transformed_strips, blender::Span< Sequence * > time_dependent_strips, bool use_sync_markers)
void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delta)
static blender::VectorSet< Sequence * > query_overwrite_targets(const Scene *scene, ListBase *seqbasep, blender::Span< Sequence * > transformed_strips)
void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2])
bool SEQ_transform_is_locked(ListBase *channels, const Sequence *seq)
eOvelapDescrition
@ STRIP_OVERLAP_RIGHT_SIDE
@ STRIP_OVERLAP_LEFT_SIDE
@ STRIP_OVERLAP_IS_INSIDE
@ STRIP_OVERLAP_IS_FULL
@ STRIP_OVERLAP_NONE
void SEQ_transform_handle_overlap(Scene *scene, ListBase *seqbasep, blender::Span< Sequence * > transformed_strips, bool use_sync_markers)
void SEQ_image_preview_unit_from_px(const Scene *scene, const float co_src[2], float co_dst[2])
bool SEQ_transform_sequence_can_be_translated(const Sequence *seq)
static void seq_transform_handle_overwrite_trim(Scene *scene, ListBase *seqbasep, const Sequence *transformed, Sequence *target, const eOvelapDescrition overlap)
bool SEQ_transform_test_overlap_seq_seq(const Scene *scene, Sequence *seq1, Sequence *seq2)
static int shuffle_seq_time_offset_get(const Scene *scene, blender::Span< Sequence * > strips_to_shuffle, ListBase *seqbasep, char dir)
bool SEQ_transform_single_image_check(const Sequence *seq)
void SEQ_transform_offset_after_frame(Scene *scene, ListBase *seqbase, const int delta, const int timeline_frame)
void * first
struct ToolSettings * toolsettings
struct RenderData r
ListBase markers
struct Sequence * seq1
struct Sequence * seq2
struct Sequence * next
StripTransform * transform
StripElem * stripdata
StripCrop * crop