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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Antalik <richardantalik@gmail.com>2021-09-21 10:38:30 +0300
committerRichard Antalik <richardantalik@gmail.com>2021-09-21 11:55:04 +0300
commitfa2c1698b077f510175e79adf3dbf3e1602b1030 (patch)
tree7b15540db52813ae7de54eceeda7e78cce25b724 /source/blender/sequencer
parent26f9b1ef49772d568560f8ac1d8d2d15bb77849f (diff)
VSE: Image transform tools
Add tools for image manipulation in sequencer preview region. This includes: - Translate, rotate and resize operators, tools and gizmos - Origin for image transformation - Median point and individual origins pivot modes - Select and Box select operator works in preview - Image overlay drawing ref T90156 Reviewed By: campbellbarton Differential Revision: https://developer.blender.org/D12105
Diffstat (limited to 'source/blender/sequencer')
-rw-r--r--source/blender/sequencer/SEQ_iterator.h8
-rw-r--r--source/blender/sequencer/SEQ_sequencer.h1
-rw-r--r--source/blender/sequencer/SEQ_transform.h9
-rw-r--r--source/blender/sequencer/intern/iterator.c120
-rw-r--r--source/blender/sequencer/intern/render.c99
-rw-r--r--source/blender/sequencer/intern/sequencer.c9
-rw-r--r--source/blender/sequencer/intern/strip_transform.c98
7 files changed, 246 insertions, 98 deletions
diff --git a/source/blender/sequencer/SEQ_iterator.h b/source/blender/sequencer/SEQ_iterator.h
index 4f7d603fd6a..d2a47a13db3 100644
--- a/source/blender/sequencer/SEQ_iterator.h
+++ b/source/blender/sequencer/SEQ_iterator.h
@@ -94,11 +94,15 @@ SeqCollection *SEQ_query_by_reference(struct Sequence *seq_reference,
SeqCollection *collection));
SeqCollection *SEQ_query_selected_strips(struct ListBase *seqbase);
SeqCollection *SEQ_query_unselected_strips(struct ListBase *seqbase);
-SeqCollection *SEQ_query_all_strips(struct ListBase *seqbase);
-SeqCollection *SEQ_query_all_strips_recursive(struct ListBase *seqbase);
+SeqCollection *SEQ_query_all_strips(ListBase *seqbase);
+SeqCollection *SEQ_query_all_strips_recursive(ListBase *seqbase);
+SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
+ const int timeline_frame,
+ const int displayed_channel);
void SEQ_query_strip_effect_chain(struct Sequence *seq_reference,
struct ListBase *seqbase,
SeqCollection *collection);
+void SEQ_filter_selected_strips(SeqCollection *collection);
#ifdef __cplusplus
}
diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h
index d7800d208a4..7e733817630 100644
--- a/source/blender/sequencer/SEQ_sequencer.h
+++ b/source/blender/sequencer/SEQ_sequencer.h
@@ -64,6 +64,7 @@ short SEQ_tool_settings_snap_flag_get(struct Scene *scene);
short SEQ_tool_settings_snap_mode_get(struct Scene *scene);
int SEQ_tool_settings_snap_distance_get(struct Scene *scene);
eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(struct Scene *scene);
+int SEQ_tool_settings_pivot_point_get(struct Scene *scene);
struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings);
struct Editing *SEQ_editing_get(const struct Scene *scene);
struct Editing *SEQ_editing_ensure(struct Scene *scene);
diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h
index 1977835f627..328efb9424a 100644
--- a/source/blender/sequencer/SEQ_transform.h
+++ b/source/blender/sequencer/SEQ_transform.h
@@ -61,6 +61,15 @@ void SEQ_transform_offset_after_frame(struct Scene *scene,
const int delta,
const int timeline_frame);
+/* Image transformation. */
+void SEQ_image_transform_mirror_factor_get(const struct Sequence *seq, float r_mirror[2]);
+void SEQ_image_transform_origin_offset_pixelspace_get(const struct Scene *scene,
+ const struct Sequence *seq,
+ float r_origin[2]);
+void SEQ_image_transform_final_quad_get(const struct Scene *scene,
+ const struct Sequence *seq,
+ float r_quad[4][2]);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/sequencer/intern/iterator.c b/source/blender/sequencer/intern/iterator.c
index 58f68205f51..2429405350b 100644
--- a/source/blender/sequencer/intern/iterator.c
+++ b/source/blender/sequencer/intern/iterator.c
@@ -37,6 +37,8 @@
#include "BKE_scene.h"
#include "SEQ_iterator.h"
+#include "SEQ_time.h"
+#include "render.h"
/* -------------------------------------------------------------------- */
/** \Iterator API
@@ -340,6 +342,114 @@ SeqCollection *SEQ_query_selected_strips(ListBase *seqbase)
return collection;
}
+static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame)
+{
+ SeqCollection *collection = SEQ_collection_create(__func__);
+
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
+ SEQ_collection_append_strip(seq, collection);
+ }
+ }
+ return collection;
+}
+
+static void collection_filter_channel_up_to_incl(SeqCollection *collection, const int channel)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ if (seq->machine <= channel) {
+ continue;
+ }
+ SEQ_collection_remove_strip(seq, collection);
+ }
+}
+
+static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input)
+{
+ if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input ||
+ seq_effect->seq3 == possibly_input) {
+ return true;
+ }
+ return false;
+}
+
+/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself.
+ * Order of applying these conditions is important. */
+static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame)
+{
+ bool seq_have_effect_in_stack = false;
+ Sequence *seq_iter;
+ SEQ_ITERATOR_FOREACH (seq_iter, strips_at_timeline_frame) {
+ /* Strips is below another strip with replace blending are not rendered. */
+ if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) {
+ return false;
+ }
+
+ if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) {
+ /* Strips in same channel or higher than its effect are rendered. */
+ if (seq->machine >= seq_iter->machine) {
+ return true;
+ }
+ /* Mark that this strip has effect in stack, that is above the strip. */
+ seq_have_effect_in_stack = true;
+ }
+ }
+
+ /* All effects are rendered (with respect to conditions above). */
+ if ((seq->type & SEQ_TYPE_EFFECT) != 0) {
+ return true;
+ }
+
+ /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */
+ if (seq_have_effect_in_stack) {
+ return false;
+ }
+
+ return true;
+}
+
+/* Remove strips we don't want to render from collection. */
+static void collection_filter_rendered_strips(SeqCollection *collection)
+{
+ Sequence *seq;
+
+ /* Remove sound strips and muted strips from collection, because these are not rendered.
+ * Function #must_render_strip() don't have to check for these strips anymore. */
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ if (must_render_strip(seq, collection)) {
+ continue;
+ }
+ SEQ_collection_remove_strip(seq, collection);
+ }
+}
+
+/**
+ * Query strips that are rendered at \a timeline_frame when \a displayed channel is viewed
+ *
+ * \param seqbase: ListBase in which strips are queried
+ * \param timeline_frame: viewed frame
+ * \param displayed_channel: viewed channel. when set to 0, no channel filter is applied
+ * \return strip collection
+ */
+SeqCollection *SEQ_query_rendered_strips(ListBase *seqbase,
+ const int timeline_frame,
+ const int displayed_channel)
+{
+ SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame);
+ if (displayed_channel != 0) {
+ collection_filter_channel_up_to_incl(collection, displayed_channel);
+ }
+ collection_filter_rendered_strips(collection);
+ return collection;
+}
+
/**
* Query all unselected strips in seqbase.
*
@@ -396,3 +506,13 @@ void SEQ_query_strip_effect_chain(Sequence *seq_reference,
}
}
}
+
+void SEQ_filter_selected_strips(SeqCollection *collection)
+{
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ if ((seq->flag & SELECT) == 0) {
+ SEQ_collection_remove_strip(seq, collection);
+ }
+ }
+}
diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c
index 6c4502a3608..e42a3f4d6e9 100644
--- a/source/blender/sequencer/intern/render.c
+++ b/source/blender/sequencer/intern/render.c
@@ -72,6 +72,7 @@
#include "SEQ_render.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
+#include "SEQ_transform.h"
#include "SEQ_utils.h"
#include "effects.h"
@@ -262,94 +263,6 @@ StripElem *SEQ_render_give_stripelem(Sequence *seq, int timeline_frame)
return se;
}
-static bool seq_is_effect_of(const Sequence *seq_effect, const Sequence *possibly_input)
-{
- if (seq_effect->seq1 == possibly_input || seq_effect->seq2 == possibly_input ||
- seq_effect->seq3 == possibly_input) {
- return true;
- }
- return false;
-}
-
-/* Check if seq must be rendered. This depends on whole stack in some cases, not only seq itself.
- * Order of applying these conditions is important. */
-static bool must_render_strip(const Sequence *seq, SeqCollection *strips_at_timeline_frame)
-{
- bool seq_have_effect_in_stack = false;
- Sequence *seq_iter;
- SEQ_ITERATOR_FOREACH (seq_iter, strips_at_timeline_frame) {
- /* Strips is below another strip with replace blending are not rendered. */
- if (seq_iter->blend_mode == SEQ_BLEND_REPLACE && seq->machine < seq_iter->machine) {
- return false;
- }
-
- if ((seq_iter->type & SEQ_TYPE_EFFECT) != 0 && seq_is_effect_of(seq_iter, seq)) {
- /* Strips in same channel or higher than its effect are rendered. */
- if (seq->machine >= seq_iter->machine) {
- return true;
- }
- /* Mark that this strip has effect in stack, that is above the strip. */
- seq_have_effect_in_stack = true;
- }
- }
-
- /* All effects are rendered (with respect to conditions above). */
- if ((seq->type & SEQ_TYPE_EFFECT) != 0) {
- return true;
- }
-
- /* If strip has effects in stack, and all effects are above this strip, it is not rendered. */
- if (seq_have_effect_in_stack) {
- return false;
- }
-
- return true;
-}
-
-static SeqCollection *query_strips_at_frame(ListBase *seqbase, const int timeline_frame)
-{
- SeqCollection *collection = SEQ_collection_create(__func__);
-
- LISTBASE_FOREACH (Sequence *, seq, seqbase) {
- if (SEQ_time_strip_intersects_frame(seq, timeline_frame)) {
- SEQ_collection_append_strip(seq, collection);
- }
- }
- return collection;
-}
-
-static void collection_filter_channel_up_to_incl(SeqCollection *collection, const int channel)
-{
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if (seq->machine <= channel) {
- continue;
- }
- SEQ_collection_remove_strip(seq, collection);
- }
-}
-
-/* Remove strips we don't want to render from collection. */
-static void collection_filter_rendered_strips(SeqCollection *collection)
-{
- Sequence *seq;
-
- /* Remove sound strips and muted strips from collection, because these are not rendered.
- * Function #must_render_strip() don't have to check for these strips anymore. */
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if (seq->type == SEQ_TYPE_SOUND_RAM || (seq->flag & SEQ_MUTE) != 0) {
- SEQ_collection_remove_strip(seq, collection);
- }
- }
-
- SEQ_ITERATOR_FOREACH (seq, collection) {
- if (must_render_strip(seq, collection)) {
- continue;
- }
- SEQ_collection_remove_strip(seq, collection);
- }
-}
-
static int seq_channel_cmp_fn(const void *a, const void *b)
{
return (*(Sequence **)a)->machine - (*(Sequence **)b)->machine;
@@ -360,13 +273,7 @@ int seq_get_shown_sequences(ListBase *seqbase,
const int chanshown,
Sequence **r_seq_arr)
{
- SeqCollection *collection = query_strips_at_frame(seqbase, timeline_frame);
-
- if (chanshown != 0) {
- collection_filter_channel_up_to_incl(collection, chanshown);
- }
- collection_filter_rendered_strips(collection);
-
+ SeqCollection *collection = SEQ_query_rendered_strips(seqbase, timeline_frame, chanshown);
const int strip_count = BLI_gset_len(collection->set);
if (strip_count > MAXSEQ) {
@@ -504,7 +411,7 @@ static void sequencer_image_crop_transform_matrix(const Sequence *seq,
const float image_center_offs_y = (out->y - in->y) / 2;
const float translate_x = transform->xofs * preview_scale_factor + image_center_offs_x;
const float translate_y = transform->yofs * preview_scale_factor + image_center_offs_y;
- const float pivot[2] = {in->x / 2, in->y / 2};
+ const float pivot[2] = {in->x * transform->origin[0], in->y * transform->origin[1]};
loc_rot_size_to_mat3(r_transform_matrix,
(const float[]){translate_x, translate_y},
transform->rotation,
diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c
index bf5942090c9..d3f8411cf0a 100644
--- a/source/blender/sequencer/intern/sequencer.c
+++ b/source/blender/sequencer/intern/sequencer.c
@@ -79,6 +79,8 @@ static Strip *seq_strip_alloc(int type)
strip->transform = MEM_callocN(sizeof(struct StripTransform), "StripTransform");
strip->transform->scale_x = 1;
strip->transform->scale_y = 1;
+ strip->transform->origin[0] = 0.5f;
+ strip->transform->origin[1] = 0.5f;
strip->crop = MEM_callocN(sizeof(struct StripCrop), "StripCrop");
}
@@ -321,6 +323,7 @@ SequencerToolSettings *SEQ_tool_settings_init(void)
SEQ_SNAP_TO_STRIP_HOLD;
tool_settings->snap_distance = 15;
tool_settings->overlap_mode = SEQ_OVERLAP_SHUFFLE;
+ tool_settings->pivot_point = V3D_AROUND_LOCAL_ORIGINS;
return tool_settings;
}
@@ -377,6 +380,12 @@ eSeqOverlapMode SEQ_tool_settings_overlap_mode_get(Scene *scene)
return tool_settings->overlap_mode;
}
+int SEQ_tool_settings_pivot_point_get(Scene *scene)
+{
+ const SequencerToolSettings *tool_settings = SEQ_tool_settings_ensure(scene);
+ return tool_settings->pivot_point;
+}
+
/**
* Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase
*
diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c
index 3a5f93a72b0..d5ff455c694 100644
--- a/source/blender/sequencer/intern/strip_transform.c
+++ b/source/blender/sequencer/intern/strip_transform.c
@@ -421,3 +421,101 @@ void SEQ_transform_offset_after_frame(Scene *scene,
}
}
}
+
+void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2])
+{
+ r_mirror[0] = 1.0f;
+ r_mirror[1] = 1.0f;
+
+ if ((seq->flag & SEQ_FLIPX) != 0) {
+ r_mirror[0] = -1.0f;
+ }
+ if ((seq->flag & SEQ_FLIPY) != 0) {
+ r_mirror[1] = -1.0f;
+ }
+}
+
+/**
+ * Get strip transform origin offset from image center
+ * Note: This function does not apply axis mirror.
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate image transform origin
+ * \param r_origin: return value
+ */
+void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene,
+ const Sequence *seq,
+ float r_origin[2])
+{
+ float image_size[2];
+ StripElem *strip_elem = seq->strip->stripdata;
+ if (strip_elem == NULL) {
+ image_size[0] = scene->r.xsch;
+ image_size[1] = scene->r.ysch;
+ }
+ else {
+ image_size[0] = strip_elem->orig_width;
+ image_size[1] = strip_elem->orig_height;
+ }
+
+ const StripTransform *transform = seq->strip->transform;
+ r_origin[0] = (image_size[0] * transform->origin[0]) - (image_size[0] * 0.5f) + transform->xofs;
+ r_origin[1] = (image_size[1] * transform->origin[1]) - (image_size[1] * 0.5f) + transform->yofs;
+
+ float mirror[2];
+ SEQ_image_transform_mirror_factor_get(seq, mirror);
+ mul_v2_v2(r_origin, mirror);
+}
+
+/**
+ * Get strip transform origin offset from image center
+ *
+ * \param scene: Scene in which strips are located
+ * \param seq: Sequence to calculate image transform origin
+ * \param r_origin: return value
+ */
+
+void SEQ_image_transform_final_quad_get(const Scene *scene,
+ const Sequence *seq,
+ float r_quad[4][2])
+{
+ StripTransform *transform = seq->strip->transform;
+ StripCrop *crop = seq->strip->crop;
+
+ int imgage_size[2] = {scene->r.xsch, scene->r.ysch};
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE)) {
+ imgage_size[0] = seq->strip->stripdata->orig_width;
+ imgage_size[1] = seq->strip->stripdata->orig_height;
+ }
+
+ float transform_matrix[3][3];
+ loc_rot_size_to_mat3(transform_matrix,
+ (const float[]){transform->xofs, transform->yofs},
+ transform->rotation,
+ (const float[]){transform->scale_x, transform->scale_y});
+ const float origin[2] = {imgage_size[0] * transform->origin[0],
+ imgage_size[1] * transform->origin[1]};
+ const float pivot[2] = {origin[0] - (imgage_size[0] / 2), origin[1] - (imgage_size[1] / 2)};
+ transform_pivot_set_m3(transform_matrix, pivot);
+
+ r_quad[0][0] = (imgage_size[0] / 2) - crop->right;
+ r_quad[0][1] = (imgage_size[1] / 2) - crop->top;
+ r_quad[1][0] = (imgage_size[0] / 2) - crop->right;
+ r_quad[1][1] = (-imgage_size[1] / 2) + crop->bottom;
+ r_quad[2][0] = (-imgage_size[0] / 2) + crop->left;
+ r_quad[2][1] = (-imgage_size[1] / 2) + crop->bottom;
+ r_quad[3][0] = (-imgage_size[0] / 2) + crop->left;
+ r_quad[3][1] = (imgage_size[1] / 2) - crop->top;
+
+ mul_m3_v2(transform_matrix, r_quad[0]);
+ mul_m3_v2(transform_matrix, r_quad[1]);
+ mul_m3_v2(transform_matrix, r_quad[2]);
+ mul_m3_v2(transform_matrix, r_quad[3]);
+
+ float mirror[2];
+ SEQ_image_transform_mirror_factor_get(seq, mirror);
+ mul_v2_v2(r_quad[0], mirror);
+ mul_v2_v2(r_quad[1], mirror);
+ mul_v2_v2(r_quad[2], mirror);
+ mul_v2_v2(r_quad[3], mirror);
+}