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
This commit is contained in:
parent
26f9b1ef49
commit
fa2c1698b0
Notes:
blender-bot
2023-05-22 12:40:41 +02:00
Referenced by issue #91694, Crash when switching to video editing workspace in new scene Referenced by issue #91698, VSE: Tool option Drag options exposed in Annotation & Sample Tool Referenced by issue #90156, VSE image transformation in preview
|
@ -2588,6 +2588,9 @@ def km_sequencercommon(params):
|
|||
("wm.context_toggle_enum", {"type": 'TAB', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("data_path", 'space_data.view_type'), ("value_1", 'SEQUENCER'), ("value_2", 'PREVIEW')]}),
|
||||
("sequencer.refresh_all", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
])
|
||||
|
||||
if params.select_mouse == 'LEFTMOUSE' and not params.legacy:
|
||||
|
@ -2670,9 +2673,6 @@ def km_sequencer(params):
|
|||
for i in range(10)
|
||||
)
|
||||
),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
|
||||
{"properties": [("extend", True)]}),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "alt": True},
|
||||
{"properties": [("linked_handle", True)]}),
|
||||
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True, "alt": True},
|
||||
|
@ -2749,6 +2749,15 @@ def km_sequencerpreview(params):
|
|||
("sequencer.view_zoom_ratio", {"type": 'NUMPAD_8', "value": 'PRESS'},
|
||||
{"properties": [("ratio", 0.125)]}),
|
||||
("sequencer.sample", {"type": params.action_mouse, "value": 'PRESS'}, None),
|
||||
("transform.translate", {"type": 'G', "value": 'PRESS'}, None),
|
||||
("transform.resize", {"type": 'S', "value": 'PRESS'}, None),
|
||||
("transform.rotate", {"type": 'R', "value": 'PRESS'}, None),
|
||||
("sequencer.strip_transform_clear", {"type": 'G', "alt": True, "value": 'PRESS'},
|
||||
{"properties": [("property", 'POSITION')]}),
|
||||
("sequencer.strip_transform_clear", {"type": 'S', "alt": True, "value": 'PRESS'},
|
||||
{"properties": [("property", 'SCALE')]}),
|
||||
("sequencer.strip_transform_clear", {"type": 'R', "alt": True, "value": 'PRESS'},
|
||||
{"properties": [("property", 'ROTATION')]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -7316,6 +7325,39 @@ def km_sequencer_editor_tool_blade(_params):
|
|||
)
|
||||
|
||||
|
||||
def km_sequencer_editor_tool_move(params):
|
||||
return (
|
||||
"Sequencer Tool: Move",
|
||||
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("transform.translate", {"type": params.tool_tweak, "value": 'ANY'},
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
def km_sequencer_editor_tool_rotate(params):
|
||||
return (
|
||||
"Sequencer Tool: Rotate",
|
||||
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("transform.rotate", {"type": params.tool_tweak, "value": 'ANY'},
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
def km_sequencer_editor_tool_scale(params):
|
||||
return (
|
||||
"Sequencer Tool: Scale",
|
||||
{"space_type": 'SEQUENCE_EDITOR', "region_type": 'WINDOW'},
|
||||
{"items": [
|
||||
("transform.resize", {"type": params.tool_tweak, "value": 'ANY'},
|
||||
{"properties": [("release_confirm", True)]}),
|
||||
]},
|
||||
)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Full Configuration
|
||||
|
||||
|
@ -7569,6 +7611,9 @@ def generate_keymaps(params=None):
|
|||
km_sequencer_editor_tool_select_box(params),
|
||||
km_sequencer_editor_tool_blade(params),
|
||||
km_sequencer_editor_tool_generic_sample(params),
|
||||
km_sequencer_editor_tool_scale(params),
|
||||
km_sequencer_editor_tool_rotate(params),
|
||||
km_sequencer_editor_tool_move(params),
|
||||
]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
|
@ -141,9 +141,14 @@ class SEQUENCER_HT_header(Header):
|
|||
|
||||
layout.separator_spacer()
|
||||
|
||||
tool_settings = context.tool_settings
|
||||
sequencer_tool_settings = tool_settings.sequencer_tool_settings
|
||||
|
||||
if st.view_type == 'PREVIEW':
|
||||
layout.prop(sequencer_tool_settings, "pivot_point", text="", icon_only=True)
|
||||
layout.separator_spacer()
|
||||
|
||||
if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}:
|
||||
tool_settings = context.tool_settings
|
||||
sequencer_tool_settings = tool_settings.sequencer_tool_settings
|
||||
row = layout.row(align=True)
|
||||
row.prop(sequencer_tool_settings, "overlap_mode", text="")
|
||||
row = layout.row(align=True)
|
||||
|
@ -209,6 +214,7 @@ class SEQUENCER_PT_preview_overlay(Panel):
|
|||
layout = self.layout
|
||||
|
||||
layout.active = st.show_strip_overlay
|
||||
layout.prop(overlay_settings, "show_image_outline")
|
||||
layout.prop(ed, "show_overlay", text="Frame Overlay")
|
||||
layout.prop(overlay_settings, "show_safe_areas", text="Safe Areas")
|
||||
layout.prop(overlay_settings, "show_metadata", text="Metadata")
|
||||
|
@ -1756,6 +1762,9 @@ class SEQUENCER_PT_adjust_transform(SequencerButtonsPanel, Panel):
|
|||
col = layout.column(align=True)
|
||||
col.prop(strip.transform, "rotation", text="Rotation")
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(strip.transform, "origin")
|
||||
|
||||
row = layout.row(heading="Mirror")
|
||||
sub = row.row(align=True)
|
||||
sub.prop(strip, "use_flip_x", text="X", toggle=True)
|
||||
|
|
|
@ -2454,6 +2454,39 @@ class _defs_sequencer_generic:
|
|||
keymap="Sequencer Tool: Sample",
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def translate():
|
||||
return dict(
|
||||
idname="builtin.move",
|
||||
label="Move",
|
||||
icon="ops.transform.translate",
|
||||
widget="SEQUENCER_GGT_gizmo2d_translate",
|
||||
operator="transform.translate",
|
||||
keymap="Sequencer Tool: Move",
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def rotate():
|
||||
return dict(
|
||||
idname="builtin.rotate",
|
||||
label="Rotate",
|
||||
icon="ops.transform.rotate",
|
||||
widget="SEQUENCER_GGT_gizmo2d_rotate",
|
||||
operator="transform.rotate",
|
||||
keymap="Sequencer Tool: Rotate",
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def scale():
|
||||
return dict(
|
||||
idname="builtin.scale",
|
||||
label="Scale",
|
||||
icon="ops.transform.resize",
|
||||
widget="SEQUENCER_GGT_gizmo2d_resize",
|
||||
operator="transform.resize",
|
||||
keymap="Sequencer Tool: Scale",
|
||||
)
|
||||
|
||||
|
||||
class _defs_sequencer_select:
|
||||
@ToolDef.from_fn
|
||||
|
@ -3045,6 +3078,10 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
|
|||
None: [
|
||||
],
|
||||
'PREVIEW': [
|
||||
*_tools_select,
|
||||
_defs_sequencer_generic.translate,
|
||||
_defs_sequencer_generic.rotate,
|
||||
_defs_sequencer_generic.scale,
|
||||
_defs_sequencer_generic.sample,
|
||||
*_tools_annotate,
|
||||
],
|
||||
|
@ -3054,6 +3091,9 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
|
|||
],
|
||||
'SEQUENCER_PREVIEW': [
|
||||
*_tools_select,
|
||||
_defs_sequencer_generic.translate,
|
||||
_defs_sequencer_generic.rotate,
|
||||
_defs_sequencer_generic.scale,
|
||||
_defs_sequencer_generic.blade,
|
||||
_defs_sequencer_generic.sample,
|
||||
*_tools_annotate,
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 23
|
||||
#define BLENDER_FILE_SUBVERSION 24
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and show a warning if the file
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include "MEM_guardedalloc.h"
|
||||
#include "readfile.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_sequencer.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
@ -774,6 +775,14 @@ static void version_geometry_nodes_change_legacy_names(bNodeTree *ntree)
|
|||
}
|
||||
}
|
||||
}
|
||||
static bool seq_transform_origin_set(Sequence *seq, void *UNUSED(user_data))
|
||||
{
|
||||
StripTransform *transform = seq->strip->transform;
|
||||
if (seq->strip->transform != NULL) {
|
||||
transform->origin[0] = transform->origin[1] = 0.5f;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* NOLINTNEXTLINE: readability-function-size */
|
||||
void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
||||
|
@ -1290,6 +1299,27 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
|
|||
}
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_ATLEAST(bmain, 300, 24)) {
|
||||
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
|
||||
SequencerToolSettings *sequencer_tool_settings = SEQ_tool_settings_ensure(scene);
|
||||
sequencer_tool_settings->pivot_point = V3D_AROUND_CENTER_MEDIAN;
|
||||
|
||||
if (scene->ed != NULL) {
|
||||
SEQ_for_each_callback(&scene->ed->seqbase, seq_transform_origin_set, NULL);
|
||||
}
|
||||
}
|
||||
LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
|
||||
LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
|
||||
LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
|
||||
if (sl->spacetype == SPACE_SEQ) {
|
||||
SpaceSeq *sseq = (SpaceSeq *)sl;
|
||||
sseq->preview_overlay.flag |= SEQ_PREVIEW_SHOW_OUTLINE_SELECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Versioning code until next subversion bump goes here.
|
||||
*
|
||||
|
|
|
@ -160,6 +160,7 @@ static void blo_update_defaults_screen(bScreen *screen,
|
|||
seq->render_size = SEQ_RENDER_SIZE_PROXY_100;
|
||||
seq->timeline_overlay.flag |= SEQ_TIMELINE_SHOW_STRIP_SOURCE | SEQ_TIMELINE_SHOW_STRIP_NAME |
|
||||
SEQ_TIMELINE_SHOW_STRIP_DURATION | SEQ_TIMELINE_SHOW_GRID;
|
||||
seq->preview_overlay.flag |= SEQ_PREVIEW_SHOW_OUTLINE_SELECTED;
|
||||
}
|
||||
else if (area->spacetype == SPACE_TEXT) {
|
||||
/* Show syntax and line numbers in Script workspace text editor. */
|
||||
|
|
|
@ -241,6 +241,11 @@ static bool use_sequencer_snapping(bContext *C)
|
|||
/* Modal Operator init */
|
||||
static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
if (CTX_wm_space_seq(C) != NULL && region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* Change to frame that mouse is over before adding modal handler,
|
||||
* as user could click on a single frame (jump to frame) as well as
|
||||
* click-dragging over a range (modal scrubbing).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -60,6 +60,7 @@ set(SRC
|
|||
transform_convert_particle.c
|
||||
transform_convert_sculpt.c
|
||||
transform_convert_sequencer.c
|
||||
transform_convert_sequencer_image.c
|
||||
transform_convert_tracking.c
|
||||
transform_draw_cursors.c
|
||||
transform_generics.c
|
||||
|
|
|
@ -1703,11 +1703,13 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||
t->draw_handle_cursor = WM_paint_cursor_activate(
|
||||
SPACE_TYPE_ANY, RGN_TYPE_ANY, transform_draw_cursor_poll, transform_draw_cursor_draw, t);
|
||||
}
|
||||
else if (t->spacetype == SPACE_SEQ) {
|
||||
t->draw_handle_view = ED_region_draw_cb_activate(
|
||||
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
|
||||
}
|
||||
else if (ELEM(t->spacetype, SPACE_IMAGE, SPACE_CLIP, SPACE_NODE, SPACE_GRAPH, SPACE_ACTION)) {
|
||||
else if (ELEM(t->spacetype,
|
||||
SPACE_IMAGE,
|
||||
SPACE_CLIP,
|
||||
SPACE_NODE,
|
||||
SPACE_GRAPH,
|
||||
SPACE_ACTION,
|
||||
SPACE_SEQ)) {
|
||||
t->draw_handle_view = ED_region_draw_cb_activate(
|
||||
t->region->type, drawTransformView, t, REGION_DRAW_POST_VIEW);
|
||||
t->draw_handle_cursor = WM_paint_cursor_activate(
|
||||
|
|
|
@ -87,15 +87,16 @@ typedef enum {
|
|||
CTX_PAINT_CURVE = (1 << 7),
|
||||
CTX_POSE_BONE = (1 << 8),
|
||||
CTX_TEXTURE_SPACE = (1 << 9),
|
||||
CTX_SEQUENCER_IMAGE = (1 << 10),
|
||||
|
||||
CTX_NO_PET = (1 << 10),
|
||||
CTX_AUTOCONFIRM = (1 << 11),
|
||||
CTX_NO_PET = (1 << 11),
|
||||
CTX_AUTOCONFIRM = (1 << 12),
|
||||
/** When transforming object's, adjust the object data so it stays in the same place. */
|
||||
CTX_OBMODE_XFORM_OBDATA = (1 << 12),
|
||||
CTX_OBMODE_XFORM_OBDATA = (1 << 13),
|
||||
/** Transform object parents without moving their children. */
|
||||
CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 13),
|
||||
CTX_OBMODE_XFORM_SKIP_CHILDREN = (1 << 14),
|
||||
/** Enable edge scrolling in 2D views */
|
||||
CTX_VIEW2D_EDGE_PAN = (1 << 14),
|
||||
CTX_VIEW2D_EDGE_PAN = (1 << 15),
|
||||
} eTContext;
|
||||
|
||||
/** #TransInfo.flag */
|
||||
|
@ -240,6 +241,7 @@ typedef enum {
|
|||
TC_PARTICLE_VERTS,
|
||||
TC_SCULPT,
|
||||
TC_SEQ_DATA,
|
||||
TC_SEQ_IMAGE_DATA,
|
||||
TC_TRACKING_DATA,
|
||||
} eTConvertType;
|
||||
|
||||
|
|
|
@ -955,6 +955,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
|
|||
case TC_OBJECT_TEXSPACE:
|
||||
case TC_PAINT_CURVE_VERTS:
|
||||
case TC_PARTICLE_VERTS:
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
case TC_NONE:
|
||||
default:
|
||||
break;
|
||||
|
@ -1042,6 +1043,7 @@ static void init_proportional_edit(TransInfo *t)
|
|||
case TC_PAINT_CURVE_VERTS:
|
||||
case TC_SCULPT:
|
||||
case TC_SEQ_DATA:
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
case TC_TRACKING_DATA:
|
||||
case TC_NONE:
|
||||
default:
|
||||
|
@ -1120,6 +1122,7 @@ static void init_TransDataContainers(TransInfo *t,
|
|||
case TC_PARTICLE_VERTS:
|
||||
case TC_SCULPT:
|
||||
case TC_SEQ_DATA:
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
case TC_TRACKING_DATA:
|
||||
case TC_NONE:
|
||||
default:
|
||||
|
@ -1204,6 +1207,7 @@ static eTFlag flags_from_data_type(eTConvertType data_type)
|
|||
case TC_NODE_DATA:
|
||||
case TC_PAINT_CURVE_VERTS:
|
||||
case TC_SEQ_DATA:
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
case TC_TRACKING_DATA:
|
||||
return T_POINTS | T_2D_EDIT;
|
||||
case TC_ARMATURE_VERTS:
|
||||
|
@ -1282,7 +1286,12 @@ static eTConvertType convert_type_get(const TransInfo *t, Object **r_obj_armatur
|
|||
convert_type = TC_NLA_DATA;
|
||||
}
|
||||
else if (t->spacetype == SPACE_SEQ) {
|
||||
convert_type = TC_SEQ_DATA;
|
||||
if (t->options & CTX_SEQUENCER_IMAGE) {
|
||||
convert_type = TC_SEQ_IMAGE_DATA;
|
||||
}
|
||||
else {
|
||||
convert_type = TC_SEQ_DATA;
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_GRAPH) {
|
||||
convert_type = TC_GRAPH_EDIT_DATA;
|
||||
|
@ -1470,6 +1479,10 @@ void createTransData(bContext *C, TransInfo *t)
|
|||
t->num.flag |= NUM_NO_FRACTION; /* sequencer has no use for floating point transform. */
|
||||
createTransSeqData(t);
|
||||
break;
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
t->obedit_type = -1;
|
||||
createTransSeqImageData(t);
|
||||
break;
|
||||
case TC_TRACKING_DATA:
|
||||
createTransTrackingData(C, t);
|
||||
break;
|
||||
|
@ -1746,6 +1759,9 @@ void recalcData(TransInfo *t)
|
|||
case TC_SEQ_DATA:
|
||||
recalcData_sequencer(t);
|
||||
break;
|
||||
case TC_SEQ_IMAGE_DATA:
|
||||
recalcData_sequencer_image(t);
|
||||
break;
|
||||
case TC_TRACKING_DATA:
|
||||
recalcData_tracking(t);
|
||||
break;
|
||||
|
|
|
@ -218,6 +218,10 @@ void createTransSeqData(TransInfo *t);
|
|||
void recalcData_sequencer(TransInfo *t);
|
||||
void special_aftertrans_update__sequencer(bContext *C, TransInfo *t);
|
||||
|
||||
/* transform_convert_sequencer_image.c */
|
||||
void createTransSeqImageData(TransInfo *t);
|
||||
void recalcData_sequencer_image(TransInfo *t);
|
||||
|
||||
/* transform_convert_tracking.c */
|
||||
void createTransTrackingData(bContext *C, TransInfo *t);
|
||||
void recalcData_tracking(TransInfo *t);
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* The Original Code is Copyright (C) 2021 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/** \file
|
||||
* \ingroup edtransform
|
||||
*/
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_space_types.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_relations.h"
|
||||
#include "SEQ_sequencer.h"
|
||||
#include "SEQ_time.h"
|
||||
#include "SEQ_transform.h"
|
||||
#include "SEQ_utils.h"
|
||||
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
|
||||
/** Used for sequencer transform. */
|
||||
typedef struct TransDataSeq {
|
||||
struct Sequence *seq;
|
||||
float orig_origin_position[2];
|
||||
float orig_translation[2];
|
||||
float orig_scale[2];
|
||||
float orig_rotation;
|
||||
} TransDataSeq;
|
||||
|
||||
static TransData *SeqToTransData(const Scene *scene,
|
||||
Sequence *seq,
|
||||
TransData *td,
|
||||
TransData2D *td2d,
|
||||
TransDataSeq *tdseq,
|
||||
int vert_index)
|
||||
{
|
||||
const StripTransform *transform = seq->strip->transform;
|
||||
float origin[2];
|
||||
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
|
||||
float vertex[2] = {origin[0], origin[1]};
|
||||
|
||||
/* Add control vertex, so rotation and scale can be calculated. */
|
||||
if (vert_index == 1) {
|
||||
vertex[0] += 1.0f;
|
||||
}
|
||||
else if (vert_index == 2) {
|
||||
vertex[1] += 1.0f;
|
||||
}
|
||||
|
||||
td2d->loc[0] = vertex[0];
|
||||
td2d->loc[1] = vertex[1];
|
||||
td2d->loc2d = NULL;
|
||||
td->loc = td2d->loc;
|
||||
copy_v3_v3(td->iloc, td->loc);
|
||||
|
||||
td->center[0] = origin[0];
|
||||
td->center[1] = origin[1];
|
||||
|
||||
memset(td->axismtx, 0, sizeof(td->axismtx));
|
||||
td->axismtx[2][2] = 1.0f;
|
||||
unit_m3(td->mtx);
|
||||
unit_m3(td->smtx);
|
||||
|
||||
tdseq->seq = seq;
|
||||
copy_v2_v2(tdseq->orig_origin_position, origin);
|
||||
tdseq->orig_translation[0] = transform->xofs;
|
||||
tdseq->orig_translation[1] = transform->yofs;
|
||||
tdseq->orig_scale[0] = transform->scale_x;
|
||||
tdseq->orig_scale[1] = transform->scale_y;
|
||||
tdseq->orig_rotation = transform->rotation;
|
||||
|
||||
td->extra = (void *)tdseq;
|
||||
td->ext = NULL;
|
||||
td->flag |= TD_SELECTED;
|
||||
td->dist = 0.0;
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
static void freeSeqData(TransInfo *UNUSED(t), TransDataContainer *tc, TransCustomData *UNUSED(custom_data))
|
||||
{
|
||||
TransData *td = (TransData *)tc->data;
|
||||
MEM_freeN(td->extra);
|
||||
}
|
||||
|
||||
void createTransSeqImageData(TransInfo *t)
|
||||
{
|
||||
Editing *ed = SEQ_editing_get(t->scene);
|
||||
ListBase *seqbase = SEQ_active_seqbase_get(ed);
|
||||
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, t->scene->r.cfra, 0);
|
||||
SEQ_filter_selected_strips(strips);
|
||||
|
||||
const int count = SEQ_collection_len(strips);
|
||||
if (ed == NULL || count == 0) {
|
||||
SEQ_collection_free(strips);
|
||||
return;
|
||||
}
|
||||
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
tc->custom.type.free_cb = freeSeqData;
|
||||
|
||||
tc->data_len = count * 3; /* 3 vertices per sequence are needed. */
|
||||
TransData *td = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransSeq TransData");
|
||||
TransData2D *td2d = tc->data_2d = MEM_callocN(tc->data_len * sizeof(TransData2D),
|
||||
"TransSeq TransData2D");
|
||||
TransDataSeq *tdseq = MEM_callocN(tc->data_len * sizeof(TransDataSeq), "TransSeq TransDataSeq");
|
||||
|
||||
Sequence *seq;
|
||||
SEQ_ITERATOR_FOREACH (seq, strips) {
|
||||
/* One `Sequence` needs 3 `TransData` entries - center point placed in image origin, then 2
|
||||
* points offset by 1 in X and Y direction respectively, so rotation and scale can be
|
||||
* calculated from these points. */
|
||||
SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 0);
|
||||
SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 1);
|
||||
SeqToTransData(t->scene, seq, td++, td2d++, tdseq++, 2);
|
||||
}
|
||||
|
||||
SEQ_collection_free(strips);
|
||||
}
|
||||
|
||||
void recalcData_sequencer_image(TransInfo *t)
|
||||
{
|
||||
TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
|
||||
TransData *td = NULL;
|
||||
TransData2D *td2d = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) {
|
||||
/* Origin. */
|
||||
float loc[2];
|
||||
copy_v2_v2(loc, td2d->loc);
|
||||
i++, td++, td2d++;
|
||||
|
||||
/* X and Y control points used to read scale and rotation. */
|
||||
float handle_x[2];
|
||||
copy_v2_v2(handle_x, td2d->loc);
|
||||
sub_v2_v2(handle_x, loc);
|
||||
i++, td++, td2d++;
|
||||
float handle_y[2];
|
||||
copy_v2_v2(handle_y, td2d->loc);
|
||||
sub_v2_v2(handle_y, loc);
|
||||
|
||||
TransDataSeq *tdseq = td->extra;
|
||||
Sequence *seq = tdseq->seq;
|
||||
StripTransform *transform = seq->strip->transform;
|
||||
float mirror[2];
|
||||
SEQ_image_transform_mirror_factor_get(seq, mirror);
|
||||
|
||||
/* Calculate translation. */
|
||||
float translation[2];
|
||||
copy_v2_v2(translation, tdseq->orig_origin_position);
|
||||
sub_v2_v2(translation, loc);
|
||||
mul_v2_v2(translation, mirror);
|
||||
transform->xofs = tdseq->orig_translation[0] - translation[0];
|
||||
transform->yofs = tdseq->orig_translation[1] - translation[1];
|
||||
|
||||
/* Scale. */
|
||||
transform->scale_x = tdseq->orig_scale[0] * fabs(len_v2(handle_x));
|
||||
transform->scale_y = tdseq->orig_scale[1] * fabs(len_v2(handle_y));
|
||||
|
||||
/* Rotation. Scaling can cause negative rotation. */
|
||||
if (t->mode == TFM_ROTATION) {
|
||||
float rotation = angle_signed_v2v2(handle_x, (float[]){1, 0}) * mirror[0] * mirror[1];
|
||||
transform->rotation = tdseq->orig_rotation + rotation;
|
||||
transform->rotation += DEG2RAD(360.0);
|
||||
transform->rotation = fmod(transform->rotation, DEG2RAD(360.0));
|
||||
}
|
||||
SEQ_relations_invalidate_cache_preprocessed(t->scene, seq);
|
||||
}
|
||||
}
|
|
@ -95,7 +95,7 @@ static void drawArrow(const uint pos_id, const enum eArrowDirection dir)
|
|||
bool transform_draw_cursor_poll(bContext *C)
|
||||
{
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
return (region && region->regiontype == RGN_TYPE_WINDOW) ? 1 : 0;
|
||||
return (region && ELEM(region->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_PREVIEW)) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -59,6 +59,8 @@
|
|||
#include "UI_resources.h"
|
||||
#include "UI_view2d.h"
|
||||
|
||||
#include "SEQ_sequencer.h"
|
||||
|
||||
#include "transform.h"
|
||||
#include "transform_convert.h"
|
||||
#include "transform_mode.h"
|
||||
|
@ -335,6 +337,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
|
|||
t->options |= CTX_MASK;
|
||||
}
|
||||
}
|
||||
else if (t->spacetype == SPACE_SEQ && region->regiontype == RGN_TYPE_PREVIEW) {
|
||||
t->view = ®ion->v2d;
|
||||
t->around = SEQ_tool_settings_pivot_point_get(t->scene);
|
||||
t->options |= CTX_SEQUENCER_IMAGE;
|
||||
}
|
||||
else {
|
||||
if (region) {
|
||||
/* XXX: For now, get View2D from the active region. */
|
||||
|
|
|
@ -49,6 +49,11 @@
|
|||
#include "ED_screen.h"
|
||||
#include "ED_uvedit.h"
|
||||
|
||||
#include "SEQ_iterator.h"
|
||||
#include "SEQ_sequencer.h"
|
||||
#include "SEQ_time.h"
|
||||
#include "SEQ_transform.h"
|
||||
|
||||
#include "transform.h" /* own include */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
@ -234,17 +239,66 @@ static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min
|
|||
return changed;
|
||||
}
|
||||
|
||||
static float gizmo2d_calc_rotation(const bContext *C)
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
if (area->spacetype != SPACE_SEQ) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Editing *ed = SEQ_editing_get(scene);
|
||||
ListBase *seqbase = SEQ_active_seqbase_get(ed);
|
||||
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
|
||||
SEQ_filter_selected_strips(strips);
|
||||
|
||||
Sequence *seq;
|
||||
SEQ_ITERATOR_FOREACH (seq, strips) {
|
||||
if (seq == ed->act_seq) {
|
||||
StripTransform *transform = seq->strip->transform;
|
||||
float mirror[2];
|
||||
SEQ_image_transform_mirror_factor_get(seq, mirror);
|
||||
SEQ_collection_free(strips);
|
||||
return transform->rotation * mirror[0] * mirror[1];
|
||||
}
|
||||
}
|
||||
|
||||
SEQ_collection_free(strips);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
|
||||
{
|
||||
ScrArea *area = CTX_wm_area(C);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
bool has_select = false;
|
||||
zero_v2(r_center);
|
||||
if (area->spacetype == SPACE_IMAGE) {
|
||||
SpaceImage *sima = area->spacedata.first;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
|
||||
}
|
||||
else if (area->spacetype == SPACE_SEQ) {
|
||||
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
|
||||
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, 0);
|
||||
SEQ_filter_selected_strips(strips);
|
||||
|
||||
if (SEQ_collection_len(strips) <= 0) {
|
||||
SEQ_collection_free(strips);
|
||||
return false;
|
||||
}
|
||||
|
||||
has_select = true;
|
||||
Sequence *seq;
|
||||
SEQ_ITERATOR_FOREACH (seq, strips) {
|
||||
float origin[2];
|
||||
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, origin);
|
||||
add_v2_v2(r_center, origin);
|
||||
}
|
||||
mul_v2_fl(r_center, 1.0f / SEQ_collection_len(strips));
|
||||
|
||||
SEQ_collection_free(strips);
|
||||
}
|
||||
return has_select;
|
||||
}
|
||||
|
||||
|
@ -338,7 +392,7 @@ static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup
|
|||
}
|
||||
}
|
||||
|
||||
RNA_boolean_set(ptr, "release_confirm", 1);
|
||||
RNA_boolean_set(ptr, "release_confirm", true);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -539,6 +593,7 @@ void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
|
|||
typedef struct GizmoGroup_Resize2D {
|
||||
wmGizmo *gizmo_xy[3];
|
||||
float origin[2];
|
||||
float rotation;
|
||||
} GizmoGroup_Resize2D;
|
||||
|
||||
static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
|
||||
|
@ -571,6 +626,7 @@ static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
|
|||
ggd->gizmo_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
|
||||
}
|
||||
copy_v2_v2(ggd->origin, origin);
|
||||
ggd->rotation = gizmo2d_calc_rotation(C);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -595,6 +651,13 @@ static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup
|
|||
for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
|
||||
wmGizmo *gz = ggd->gizmo_xy[i];
|
||||
WM_gizmo_set_matrix_location(gz, origin);
|
||||
|
||||
if (i < 2) {
|
||||
float axis[3] = {0.0f}, rotated_axis[3];
|
||||
axis[i] = 1.0f;
|
||||
rotate_v3_v3v3fl(rotated_axis, axis, (float[3]){0, 0, 1}, ggd->rotation);
|
||||
WM_gizmo_set_matrix_rotation_from_z_axis(gz, rotated_axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -617,10 +680,6 @@ static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgrou
|
|||
|
||||
/* set up widget data */
|
||||
RNA_float_set(gz->ptr, "length", 1.0f);
|
||||
float axis[3] = {0.0f};
|
||||
axis[i] = 1.0f;
|
||||
WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
|
||||
|
||||
RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
|
||||
|
||||
WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
|
||||
|
|
|
@ -75,7 +75,7 @@ bool transdata_check_local_center(const TransInfo *t, short around)
|
|||
/* implicit: (t->flag & T_EDIT) */
|
||||
(ELEM(t->obedit_type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE, OB_GPENCIL)) ||
|
||||
(t->spacetype == SPACE_GRAPH) ||
|
||||
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE))));
|
||||
(t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE))));
|
||||
}
|
||||
|
||||
/* Informs if the mode can be switched during modal. */
|
||||
|
|
|
@ -254,6 +254,10 @@ static int seq_snap_threshold_get_frame_distance(const TransInfo *t)
|
|||
|
||||
TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
|
||||
{
|
||||
if (t->data_type == TC_SEQ_IMAGE_DATA) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TransSeqSnapData *snap_data = MEM_callocN(sizeof(TransSeqSnapData), __func__);
|
||||
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene));
|
||||
|
||||
|
|
|
@ -1344,6 +1344,7 @@ typedef struct SequencerToolSettings {
|
|||
/** When there are many snap points, 0-1 range corresponds to resolution from boundbox to all
|
||||
* possible snap points. */
|
||||
int snap_distance;
|
||||
int pivot_point;
|
||||
} SequencerToolSettings;
|
||||
|
||||
typedef enum eSeqOverlapMode {
|
||||
|
|
|
@ -74,6 +74,8 @@ typedef struct StripTransform {
|
|||
float scale_x;
|
||||
float scale_y;
|
||||
float rotation;
|
||||
/** 0-1 range, use SEQ_image_transform_origin_offset_pixelspace_get to convert to pixel space. */
|
||||
float origin[2];
|
||||
} StripTransform;
|
||||
|
||||
typedef struct StripColorBalance {
|
||||
|
|
|
@ -583,6 +583,7 @@ typedef struct SequencerPreviewOverlay {
|
|||
|
||||
/* SequencerPreviewOverlay.flag */
|
||||
typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag {
|
||||
SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2),
|
||||
SEQ_PREVIEW_SHOW_SAFE_MARGINS = (1 << 3),
|
||||
SEQ_PREVIEW_SHOW_GPENCIL = (1 << 4),
|
||||
SEQ_PREVIEW_SHOW_SAFE_CENTER = (1 << 9),
|
||||
|
@ -685,6 +686,7 @@ typedef enum eSpaceSeq_Flag {
|
|||
SPACE_SEQ_FLAG_UNUSED_15 = (1 << 15),
|
||||
SPACE_SEQ_FLAG_UNUSED_16 = (1 << 16),
|
||||
SEQ_USE_PROXIES = (1 << 17),
|
||||
SEQ_SHOW_GRID = (1 << 18),
|
||||
} eSpaceSeq_Flag;
|
||||
|
||||
/* SpaceSeq.view */
|
||||
|
|
|
@ -3525,6 +3525,16 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
|
|||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem pivot_points[] = {
|
||||
{V3D_AROUND_CENTER_MEDIAN, "MEDIAN", ICON_PIVOT_MEDIAN, "Median Point", ""},
|
||||
{V3D_AROUND_LOCAL_ORIGINS,
|
||||
"INDIVIDUAL_ORIGINS",
|
||||
ICON_PIVOT_INDIVIDUAL,
|
||||
"Individual Origins",
|
||||
"Pivot around each selected island's own median point"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
|
||||
};
|
||||
srna = RNA_def_struct(brna, "SequencerToolSettings", NULL);
|
||||
RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path");
|
||||
RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", "");
|
||||
|
@ -3568,6 +3578,10 @@ static void rna_def_sequencer_tool_settings(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "overlap_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, scale_overlap_modes);
|
||||
RNA_def_property_ui_text(prop, "Overlap Mode", "How to resolve overlap after transformation");
|
||||
|
||||
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, pivot_points);
|
||||
RNA_def_property_ui_text(prop, "Pivot Point", "Rotation or scaling pivot point");
|
||||
}
|
||||
|
||||
static void rna_def_unified_paint_settings(BlenderRNA *brna)
|
||||
|
|
|
@ -1442,6 +1442,12 @@ static void rna_def_strip_transform(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Rotation", "Rotate around image center");
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
|
||||
|
||||
prop = RNA_def_property(srna, "origin", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "origin");
|
||||
RNA_def_property_ui_text(prop, "Origin", "Origin of image for transformation");
|
||||
RNA_def_property_ui_range(prop, 0, 1, 1, 3);
|
||||
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceTransform_update");
|
||||
|
||||
RNA_def_struct_path_func(srna, "rna_SequenceTransform_path");
|
||||
}
|
||||
|
||||
|
|
|
@ -5371,6 +5371,11 @@ static void rna_def_space_sequencer_preview_overlay(BlenderRNA *brna)
|
|||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_PREVIEW_SHOW_GPENCIL);
|
||||
RNA_def_property_ui_text(prop, "Show Annotation", "Show annotations for this view");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_image_outline", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_PREVIEW_SHOW_OUTLINE_SELECTED);
|
||||
RNA_def_property_ui_text(prop, "Image Outline", "");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_sequencer_timeline_overlay(BlenderRNA *brna)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue