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/editors/space_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/editors/space_sequencer')
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c67
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c123
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c73
3 files changed, 248 insertions, 15 deletions
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 5b39feacfe3..e063e12a9a8 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -71,6 +71,7 @@
#include "BIF_glutil.h"
#include "SEQ_effects.h"
+#include "SEQ_iterator.h"
#include "SEQ_prefetch.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
@@ -2056,6 +2057,64 @@ static int sequencer_draw_get_transform_preview_frame(Scene *scene)
return preview_frame;
}
+static void seq_draw_image_origin_and_outline(const bContext *C, Sequence *seq)
+{
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if ((seq->flag & SELECT) == 0) {
+ return;
+ }
+ if (ED_screen_animation_no_scrub(CTX_wm_manager(C))) {
+ return;
+ }
+ if ((sseq->flag & SEQ_SHOW_OVERLAY) == 0 ||
+ (sseq->preview_overlay.flag & SEQ_PREVIEW_SHOW_OUTLINE_SELECTED) == 0) {
+ return;
+ }
+ if (ELEM(sseq->mainb, SEQ_DRAW_IMG_WAVEFORM, SEQ_DRAW_IMG_VECTORSCOPE, SEQ_DRAW_IMG_HISTOGRAM)) {
+ return;
+ }
+
+ float origin[2];
+ SEQ_image_transform_origin_offset_pixelspace_get(CTX_data_scene(C), seq, origin);
+
+ /* Origin. */
+ GPUVertFormat *format = immVertexFormat();
+ uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
+ immUniform1f("outlineWidth", 1.5f);
+ immUniformColor3f(1.0f, 1.0f, 1.0f);
+ immUniform4f("outlineColor", 0.0f, 0.0f, 0.0f, 1.0f);
+ immUniform1f("size", 15.0f * U.pixelsize);
+ immBegin(GPU_PRIM_POINTS, 1);
+ immVertex2f(pos, origin[0], origin[1]);
+ immEnd();
+ immUnbindProgram();
+
+ /* Outline. */
+ float seq_image_quad[4][2];
+ SEQ_image_transform_final_quad_get(CTX_data_scene(C), seq, seq_image_quad);
+
+ GPU_line_smooth(true);
+ GPU_blend(GPU_BLEND_ALPHA);
+ GPU_line_width(2);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ float col[3];
+ UI_GetThemeColor3fv(TH_SEQ_SELECTED, col);
+ immUniformColor3fv(col);
+ immUniform1f("lineWidth", U.pixelsize);
+ immBegin(GPU_PRIM_LINE_LOOP, 4);
+ immVertex2f(pos, seq_image_quad[0][0], seq_image_quad[0][1]);
+ immVertex2f(pos, seq_image_quad[1][0], seq_image_quad[1][1]);
+ immVertex2f(pos, seq_image_quad[2][0], seq_image_quad[2][1]);
+ immVertex2f(pos, seq_image_quad[3][0], seq_image_quad[3][1]);
+ immEnd();
+ immUnbindProgram();
+ GPU_line_width(1);
+ GPU_blend(GPU_BLEND_NONE);
+ GPU_line_smooth(false);
+}
+
void sequencer_draw_preview(const bContext *C,
Scene *scene,
ARegion *region,
@@ -2132,9 +2191,17 @@ void sequencer_draw_preview(const bContext *C,
sequencer_draw_borders_overlay(sseq, v2d, scene);
}
+ SeqCollection *collection = SEQ_query_rendered_strips(&scene->ed->seqbase, timeline_frame, 0);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, collection) {
+ seq_draw_image_origin_and_outline(C, seq);
+ }
+ SEQ_collection_free(collection);
+
if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_OVERLAY)) {
sequencer_draw_gpencil_overlay(C);
}
+
#if 0
sequencer_draw_maskedit(C, scene, region, sseq);
#endif
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 80d3e2cbdaa..aa6599a7c53 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -44,6 +44,7 @@
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
+#include "SEQ_utils.h"
/* For menu, popup, icons, etc. */
@@ -385,6 +386,20 @@ void recurs_sel_seq(Sequence *seq_meta)
}
}
+static bool seq_point_image_isect(const Scene *scene, const Sequence *seq, float point[2])
+{
+ float seq_image_quad[4][2];
+ SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad);
+ return isect_point_quad_v2(
+ point, seq_image_quad[0], seq_image_quad[1], seq_image_quad[2], seq_image_quad[3]);
+}
+
+static void sequencer_select_do_updates(bContext *C, Scene *scene)
+{
+ ED_outliner_select_sync_from_sequence_tag(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -523,12 +538,6 @@ static void sequencer_select_set_active(Scene *scene, Sequence *seq)
recurs_sel_seq(seq);
}
-static void sequencer_select_do_updates(bContext *C, Scene *scene)
-{
- ED_outliner_select_sync_from_sequence_tag(C);
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
-}
-
static void sequencer_select_side_of_frame(const bContext *C,
const View2D *v2d,
const int mval[2],
@@ -626,6 +635,45 @@ static void sequencer_select_linked_handle(const bContext *C,
}
}
+/* Check if click happened on image which belongs to strip. If multiple strips are found, loop
+ * through them in order. */
+static Sequence *seq_select_seq_from_preview(const bContext *C, const int mval[2])
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ View2D *v2d = UI_view2d_fromcontext(C);
+
+ float mouseco_view[2];
+ UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseco_view[0], &mouseco_view[1]);
+
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
+ ListBase strips_ordered = {NULL};
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ if (seq_point_image_isect(scene, seq, mouseco_view)) {
+ BLI_remlink(seqbase, seq);
+ BLI_addtail(&strips_ordered, seq);
+ }
+ }
+ SEQ_collection_free(strips);
+ SEQ_sort(&strips_ordered);
+
+ Sequence *seq_active = SEQ_select_active_get(scene);
+ Sequence *seq_select = strips_ordered.first;
+ LISTBASE_FOREACH (Sequence *, seq_iter, &strips_ordered) {
+ if (seq_iter == seq_active && seq_iter->next != NULL) {
+ seq_select = seq_iter->next;
+ break;
+ }
+ }
+
+ BLI_movelisttolist(seqbase, &strips_ordered);
+
+ return seq_select;
+}
+
static bool element_already_selected(const Sequence *seq, const int handle_clicked)
{
const bool handle_already_selected = ((handle_clicked == SEQ_SIDE_LEFT) &&
@@ -680,8 +728,15 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
- int handle_clicked;
- Sequence *seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
+ ARegion *region = CTX_wm_region(C);
+ int handle_clicked = SEQ_SIDE_NONE;
+ Sequence *seq = NULL;
+ if (region->regiontype == RGN_TYPE_PREVIEW) {
+ seq = seq_select_seq_from_preview(C, mval);
+ }
+ else {
+ seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
+ }
/* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
* therefore both properties can be true at the same time. */
@@ -1311,6 +1366,47 @@ void SEQUENCER_OT_select_side(wmOperatorType *ot)
/** \name Box Select Operator
* \{ */
+static bool seq_box_select_rect_image_isect(const Scene *scene, const Sequence *seq, rctf *rect)
+{
+ float seq_image_quad[4][2];
+ SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad);
+ float rect_quad[4][2] = {{rect->xmax, rect->ymax},
+ {rect->xmax, rect->ymin},
+ {rect->xmin, rect->ymin},
+ {rect->xmin, rect->ymax}};
+
+ return seq_point_image_isect(scene, seq, rect_quad[0]) ||
+ seq_point_image_isect(scene, seq, rect_quad[1]) ||
+ seq_point_image_isect(scene, seq, rect_quad[2]) ||
+ seq_point_image_isect(scene, seq, rect_quad[3]) ||
+ isect_point_quad_v2(
+ seq_image_quad[0], rect_quad[0], rect_quad[1], rect_quad[2], rect_quad[3]) ||
+ isect_point_quad_v2(
+ seq_image_quad[1], rect_quad[0], rect_quad[1], rect_quad[2], rect_quad[3]) ||
+ isect_point_quad_v2(
+ seq_image_quad[2], rect_quad[0], rect_quad[1], rect_quad[2], rect_quad[3]) ||
+ isect_point_quad_v2(
+ seq_image_quad[3], rect_quad[0], rect_quad[1], rect_quad[2], rect_quad[3]);
+}
+
+static void seq_box_select_seq_from_preview(const bContext *C, rctf *rect)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(ed);
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+
+ SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
+ Sequence *seq;
+ SEQ_ITERATOR_FOREACH (seq, strips) {
+ if (seq_box_select_rect_image_isect(scene, seq, rect)) {
+ seq->flag |= SELECT;
+ }
+ }
+
+ SEQ_collection_free(strips);
+}
+
static int sequencer_box_select_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
@@ -1333,6 +1429,13 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
WM_operator_properties_border_to_rctf(op, &rectf);
UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
+ ARegion *region = CTX_wm_region(C);
+ if (region->regiontype == RGN_TYPE_PREVIEW) {
+ seq_box_select_seq_from_preview(C, &rectf);
+ sequencer_select_do_updates(C, scene);
+ return OPERATOR_FINISHED;
+ }
+
LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
rctf rq;
seq_rectf(seq, &rq);
@@ -1378,9 +1481,7 @@ static int sequencer_box_select_exec(bContext *C, wmOperator *op)
}
}
- ED_outliner_select_sync_from_sequence_tag(C);
-
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+ sequencer_select_do_updates(C, scene);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 0d09f2564e8..cb5fe6f0ef3 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -42,6 +42,7 @@
#include "ED_screen.h"
#include "ED_space_api.h"
+#include "ED_transform.h"
#include "ED_view3d.h"
#include "ED_view3d_offscreen.h" /* Only for sequencer view3d drawing callback. */
@@ -98,10 +99,11 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce
sseq->chanshown = 0;
sseq->view = SEQ_VIEW_SEQUENCE;
sseq->mainb = SEQ_DRAW_IMG_IMBUF;
- sseq->flag = SEQ_PREVIEW_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS |
- SEQ_TIMELINE_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_OVERLAY |
- SEQ_TIMELINE_SHOW_STRIP_NAME | SEQ_TIMELINE_SHOW_STRIP_SOURCE |
- SEQ_TIMELINE_SHOW_STRIP_DURATION | SEQ_TIMELINE_SHOW_GRID;
+ sseq->flag = SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_ZOOM_TO_FIT | SEQ_SHOW_OVERLAY;
+ sseq->preview_overlay.flag = SEQ_PREVIEW_SHOW_GPENCIL | SEQ_PREVIEW_SHOW_OUTLINE_SELECTED;
+ sseq->timeline_overlay.flag = SEQ_TIMELINE_SHOW_STRIP_NAME | SEQ_TIMELINE_SHOW_STRIP_SOURCE |
+ SEQ_TIMELINE_SHOW_STRIP_DURATION | SEQ_TIMELINE_SHOW_GRID |
+ SEQ_TIMELINE_SHOW_FCURVES;
/* Tool header. */
region = MEM_callocN(sizeof(ARegion), "tool header for sequencer");
@@ -481,11 +483,72 @@ static void SEQUENCER_GGT_navigate(wmGizmoGroupType *gzgt)
VIEW2D_GGT_navigate_impl(gzgt, "SEQUENCER_GGT_navigate");
}
+static void SEQUENCER_GGT_gizmo2d(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Sequencer Transform Gizmo";
+ gzgt->idname = "SEQUENCER_GGT_gizmo2d";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_SEQ;
+ gzgt->gzmap_params.regionid = RGN_TYPE_PREVIEW;
+
+ ED_widgetgroup_gizmo2d_xform_callbacks_set(gzgt);
+}
+
+static void SEQUENCER_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Sequencer Translate Gizmo";
+ gzgt->idname = "SEQUENCER_GGT_gizmo2d_translate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_SEQ;
+ gzgt->gzmap_params.regionid = RGN_TYPE_PREVIEW;
+
+ ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(gzgt);
+}
+
+static void SEQUENCER_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Sequencer Transform Gizmo Resize";
+ gzgt->idname = "SEQUENCER_GGT_gizmo2d_resize";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_SEQ;
+ gzgt->gzmap_params.regionid = RGN_TYPE_PREVIEW;
+
+ ED_widgetgroup_gizmo2d_resize_callbacks_set(gzgt);
+}
+
+static void SEQUENCER_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
+{
+ gzgt->name = "Sequencer Transform Gizmo Resize";
+ gzgt->idname = "SEQUENCER_GGT_gizmo2d_rotate";
+
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
+
+ gzgt->gzmap_params.spaceid = SPACE_SEQ;
+ gzgt->gzmap_params.regionid = RGN_TYPE_PREVIEW;
+
+ ED_widgetgroup_gizmo2d_rotate_callbacks_set(gzgt);
+}
+
static void sequencer_gizmos(void)
{
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
&(const struct wmGizmoMapType_Params){SPACE_SEQ, RGN_TYPE_PREVIEW});
+ WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d);
+ WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_translate);
+ WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_resize);
+ WM_gizmogrouptype_append(SEQUENCER_GGT_gizmo2d_rotate);
+
WM_gizmogrouptype_append_and_link(gzmap_type, SEQUENCER_GGT_navigate);
}
@@ -742,6 +805,8 @@ static void sequencer_preview_region_listener(const wmRegionListenerParams *para
ARegion *region = params->region;
wmNotifier *wmn = params->notifier;
+ WM_gizmomap_tag_refresh(region->gizmo_map);
+
/* Context changes. */
switch (wmn->category) {
case NC_GPENCIL: