VSE: Remove retiming tool for 3.6 release

This reverts commits:
e1f6587f12
b4100ed377
6749593aec
a97cae3efc
559898709f
e4eb9e04e0
bb1c503bee
b21695a507
7bf56e5c75
4dc026ec8e
354ef89d20

Reason for reverting is to not introduce this feature with current UI.

Pull Request: https://projects.blender.org/blender/blender/pulls/108870
This commit is contained in:
Richard Antalik
2023-06-14 04:25:52 +02:00
committed by Richard Antalik
parent 962331c256
commit b77e7480ef
33 changed files with 51 additions and 2386 deletions

View File

@@ -1876,7 +1876,7 @@ class SEQUENCER_PT_time(SequencerButtonsPanel, Panel):
split.label(text="Channel")
split.prop(strip, "channel", text="")
if strip.type == 'SOUND':
if not is_effect:
split = layout.split(factor=0.5 + max_factor)
split.alignment = 'RIGHT'
split.label(text="Speed Factor")

View File

@@ -2529,18 +2529,6 @@ class _defs_sequencer_generic:
options={'KEYMAP_FALLBACK'},
)
@ToolDef.from_fn
def retime():
return dict(
idname="builtin.retime",
label="Retime",
icon="ops.sequencer.retime",
widget="SEQUENCER_GGT_gizmo_retime",
operator=None,
keymap=None,
options={'KEYMAP_FALLBACK'},
)
@ToolDef.from_fn
def sample():
return dict(
@@ -3222,7 +3210,6 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel):
'SEQUENCER': [
*_tools_select,
_defs_sequencer_generic.blade,
_defs_sequencer_generic.retime,
],
'SEQUENCER_PREVIEW': [
*_tools_select,

View File

@@ -154,13 +154,6 @@ void BKE_sound_set_scene_sound_volume(void *handle, float volume, char animated)
void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated);
void BKE_sound_set_scene_sound_pitch_at_frame(void *handle, int frame, float pitch, char animated);
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
int frame_start,
int frame_end,
float pitch);
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated);
void BKE_sound_update_sequencer(struct Main *main, struct bSound *sound);

View File

@@ -819,20 +819,6 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated);
}
void BKE_sound_set_scene_sound_pitch_at_frame(void *handle, int frame, float pitch, char animated)
{
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PITCH, frame, &pitch, animated);
}
void BKE_sound_set_scene_sound_pitch_constant_range(void *handle,
int frame_start,
int frame_end,
float pitch)
{
AUD_SequenceEntry_setConstantRangeAnimationData(
handle, AUD_AP_PITCH, frame_start, frame_end, &pitch);
}
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
@@ -1384,18 +1370,6 @@ void BKE_sound_set_scene_sound_pitch(void *UNUSED(handle),
char UNUSED(animated))
{
}
void BKE_sound_set_scene_sound_pitch_at_frame(void *UNUSED(handle),
int UNUSED(frame),
float UNUSED(pitch),
char UNUSED(animated))
{
}
void BKE_sound_set_scene_sound_pitch_constant_range(void *UNUSED(handle),
int UNUSED(frame_start),
int UNUSED(frame_end),
float UNUSED(pitch))
{
}
float BKE_sound_get_length(struct Main *UNUSED(bmain), bSound *UNUSED(sound))
{
return 0;

View File

@@ -81,7 +81,6 @@
#include "SEQ_channels.h"
#include "SEQ_effects.h"
#include "SEQ_iterator.h"
#include "SEQ_retiming.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
@@ -696,25 +695,6 @@ static bool seq_speed_factor_set(Sequence *seq, void *user_data)
return true;
}
static bool do_versions_sequencer_init_retiming_tool_data(Sequence *seq, void *user_data)
{
const Scene *scene = static_cast<const Scene *>(user_data);
if (seq->speed_factor == 1 || !SEQ_retiming_is_allowed(seq)) {
return true;
}
const int content_length = SEQ_time_strip_length_get(scene, seq);
SEQ_retiming_data_ensure(seq);
SeqRetimingHandle *handle = &seq->retiming_handles[seq->retiming_handle_num - 1];
handle->strip_frame_index = round_fl_to_int(content_length / seq->speed_factor);
seq->speed_factor = 1.0f;
return true;
}
static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *ntree)
{
using namespace blender;
@@ -1361,18 +1341,6 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
FOREACH_NODETREE_END;
}
if (!MAIN_VERSION_ATLEAST(bmain, 306, 6)) {
LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) {
Editing *ed = SEQ_editing_get(scene);
if (ed == nullptr) {
continue;
}
SEQ_for_each_callback(
&scene->ed->seqbase, do_versions_sequencer_init_retiming_tool_data, scene);
}
}
/**
* Versioning code until next subversion bump goes here.
*
@@ -1799,7 +1767,6 @@ static bool version_seq_fix_broken_sound_strips(Sequence *seq, void * /*user_dat
}
seq->speed_factor = 1.0f;
SEQ_retiming_data_clear(seq);
seq->startofs = 0.0f;
return true;
}

View File

@@ -872,7 +872,6 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.sculpt.mask_by_color
ops.sculpt.mesh_filter
ops.sequencer.blade
ops.sequencer.retime
ops.transform.bone_envelope
ops.transform.bone_size
ops.transform.edge_slide

View File

@@ -35,13 +35,10 @@ set(SRC
sequencer_drag_drop.c
sequencer_draw.c
sequencer_edit.c
sequencer_gizmo_retime.cc
sequencer_gizmo_retime_type.cc
sequencer_modifier.c
sequencer_ops.c
sequencer_preview.c
sequencer_proxy.c
sequencer_retiming.cc
sequencer_scopes.c
sequencer_select.c
sequencer_thumbnails.c

View File

@@ -414,6 +414,7 @@ static void draw_seq_waveform_overlay(
const float frames_per_pixel = BLI_rctf_size_x(&region->v2d.cur) / region->winx;
const float samples_per_frame = SOUND_WAVE_SAMPLES_PER_SECOND / FPS;
float samples_per_pixel = samples_per_frame * frames_per_pixel;
/* Align strip start with nearest pixel to prevent waveform flickering. */
const float x1_aligned = align_frame_with_pixel(x1, frames_per_pixel);
@@ -439,17 +440,15 @@ static void draw_seq_waveform_overlay(
size_t wave_data_len = 0;
/* Offset must be also aligned, otherwise waveform flickers when moving left handle. */
float start_frame = SEQ_time_left_handle_frame_get(scene, seq);
const float strip_offset = align_frame_with_pixel(seq->startofs + seq->anim_startofs,
frames_per_pixel);
float start_sample = strip_offset * samples_per_frame;
start_sample += seq->sound->offset_time * SOUND_WAVE_SAMPLES_PER_SECOND;
/* Add off-screen part of strip to offset. */
start_frame += (frame_start - x1_aligned);
start_frame += seq->sound->offset_time / FPS;
start_sample += (frame_start - x1_aligned) * samples_per_frame;
for (int i = 0; i < pixels_to_draw; i++) {
float timeline_frame = start_frame + i * frames_per_pixel;
/* TODO: Use linear interpolation between frames to avoid bad drawing quality. */
float frame_index = SEQ_give_frame_index(scene, seq, timeline_frame);
float sample = frame_index * samples_per_frame;
float sample = start_sample + i * samples_per_pixel;
int sample_index = round_fl_to_int(sample);
if (sample_index < 0) {
@@ -470,8 +469,6 @@ static void draw_seq_waveform_overlay(
value_min = (1.0f - f) * value_min + f * waveform->data[sample_index * 3 + 3];
value_max = (1.0f - f) * value_max + f * waveform->data[sample_index * 3 + 4];
rms = (1.0f - f) * rms + f * waveform->data[sample_index * 3 + 5];
float samples_per_pixel = samples_per_frame * frames_per_pixel;
if (samples_per_pixel > 1.0f) {
/* We need to sum up the values we skip over until the next step. */
float next_pos = sample + samples_per_pixel;

View File

@@ -1,106 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
/** \file
* \ingroup spseq
*/
#include "MEM_guardedalloc.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "BKE_context.h"
#include "BLI_span.hh"
#include "RNA_access.h"
#include "UI_resources.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_gizmo_library.h"
#include "ED_gizmo_utils.h"
#include "SEQ_iterator.h"
#include "SEQ_retiming.h"
#include "SEQ_retiming.hh"
#include "SEQ_sequencer.h"
/* Own include. */
#include "sequencer_intern.h"
typedef struct GizmoGroup_retime {
wmGizmo *add_handle_gizmo;
wmGizmo *move_handle_gizmo;
wmGizmo *remove_handle_gizmo;
} GizmoGroup_retime;
static bool gizmogroup_retime_poll(const bContext *C, wmGizmoGroupType *gzgt)
{
/* Needed to prevent drawing gizmos when retiming tool is not activated. */
if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
return false;
}
if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
return false;
}
ScrArea *area = CTX_wm_area(C);
if (area == nullptr && area->spacetype != SPACE_SEQ) {
return false;
}
const SpaceSeq *sseq = (SpaceSeq *)area->spacedata.first;
if (sseq->gizmo_flag & (SEQ_GIZMO_HIDE | SEQ_GIZMO_HIDE_TOOL)) {
return false;
}
Editing *ed = SEQ_editing_get(CTX_data_scene(C));
Sequence *seq = ed->act_seq;
if (ed == nullptr || seq == nullptr || !SEQ_retiming_is_allowed(seq)) {
return false;
}
return true;
}
static void gizmogroup_retime_setup(const bContext * /* C */, wmGizmoGroup *gzgroup)
{
GizmoGroup_retime *ggd = (GizmoGroup_retime *)MEM_callocN(sizeof(GizmoGroup_retime), __func__);
/* Assign gizmos. */
const wmGizmoType *gzt_add_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_add", true);
ggd->add_handle_gizmo = WM_gizmo_new_ptr(gzt_add_handle, gzgroup, nullptr);
const wmGizmoType *gzt_remove_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_remove", true);
ggd->remove_handle_gizmo = WM_gizmo_new_ptr(gzt_remove_handle, gzgroup, nullptr);
const wmGizmoType *gzt_move_handle = WM_gizmotype_find("GIZMO_GT_retime_handle_move", true);
ggd->move_handle_gizmo = WM_gizmo_new_ptr(gzt_move_handle, gzgroup, nullptr);
gzgroup->customdata = ggd;
/* Assign operators. */
wmOperatorType *ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_move", true);
WM_gizmo_operator_set(ggd->move_handle_gizmo, 0, ot, nullptr);
ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_add", true);
WM_gizmo_operator_set(ggd->add_handle_gizmo, 0, ot, nullptr);
ot = WM_operatortype_find("SEQUENCER_OT_retiming_handle_remove", true);
WM_gizmo_operator_set(ggd->remove_handle_gizmo, 0, ot, nullptr);
}
void SEQUENCER_GGT_gizmo_retime(wmGizmoGroupType *gzgt)
{
gzgt->name = "Sequencer Transform Gizmo Retime";
gzgt->idname = "SEQUENCER_GGT_gizmo_retime";
gzgt->flag = WM_GIZMOGROUPTYPE_DRAW_MODAL_ALL;
gzgt->gzmap_params.spaceid = SPACE_SEQ;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
gzgt->poll = gizmogroup_retime_poll;
gzgt->setup = gizmogroup_retime_setup;
}

View File

@@ -1,621 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
/** \file
* \ingroup spseq
*/
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_span.hh"
#include "DNA_anim_types.h"
#include "DNA_sequence_types.h"
#include "BKE_context.h"
#include "BKE_fcurve.h"
#include "BKE_scene.h"
#include "BLF_api.h"
#include "GPU_batch.h"
#include "GPU_batch_utils.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_select.h"
#include "GPU_state.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_gizmo_library.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "SEQ_iterator.h"
#include "SEQ_retiming.h"
#include "SEQ_retiming.hh"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
/* Own include. */
#include "sequencer_intern.h"
using blender::MutableSpan;
/** Size in pixels. */
#define RETIME_HANDLE_MOUSEOVER_THRESHOLD (16.0f * UI_SCALE_FAC)
/** Factor based on icon size. */
#define RETIME_BUTTON_SIZE 0.6f
static float remove_gizmo_height_get(const View2D *v2d)
{
const float max_size = (SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM) * UI_view2d_scale_get_y(v2d);
return min_ff(14.0f * UI_SCALE_FAC, max_size * 0.4f);
}
static float strip_y_rescale(const Sequence *seq, const float y_value)
{
const float y_range = SEQ_STRIP_OFSTOP - SEQ_STRIP_OFSBOTTOM;
return (y_value * y_range) + seq->machine + SEQ_STRIP_OFSBOTTOM;
}
static float handle_x_get(const Scene *scene, const Sequence *seq, const SeqRetimingHandle *handle)
{
const SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
const bool is_last_handle = (handle == last_handle);
return SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) + (is_last_handle ? 1 : 0);
}
static const SeqRetimingHandle *mouse_over_handle_get(const Scene *scene,
const Sequence *seq,
const View2D *v2d,
const int mval[2])
{
int best_distance = INT_MAX;
const SeqRetimingHandle *best_handle = nullptr;
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (const SeqRetimingHandle &handle : handles) {
int distance = round_fl_to_int(
fabsf(UI_view2d_view_to_region_x(v2d, handle_x_get(scene, seq, &handle)) - mval[0]));
if (distance < RETIME_HANDLE_MOUSEOVER_THRESHOLD && distance < best_distance) {
best_distance = distance;
best_handle = &handle;
}
}
return best_handle;
}
static float pixels_to_view_width(const bContext *C, const float width)
{
const View2D *v2d = UI_view2d_fromcontext(C);
float scale_x = UI_view2d_view_to_region_x(v2d, 1) - UI_view2d_view_to_region_x(v2d, 0.0f);
return width / scale_x;
}
static float pixels_to_view_height(const bContext *C, const float height)
{
const View2D *v2d = UI_view2d_fromcontext(C);
float scale_y = UI_view2d_view_to_region_y(v2d, 1) - UI_view2d_view_to_region_y(v2d, 0.0f);
return height / scale_y;
}
static float strip_start_screenspace_get(const bContext *C, const Sequence *seq)
{
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = CTX_data_scene(C);
return UI_view2d_view_to_region_x(v2d, SEQ_time_left_handle_frame_get(scene, seq));
}
static float strip_end_screenspace_get(const bContext *C, const Sequence *seq)
{
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = CTX_data_scene(C);
return UI_view2d_view_to_region_x(v2d, SEQ_time_right_handle_frame_get(scene, seq));
}
static Sequence *active_seq_from_context(const bContext *C)
{
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
return ed->act_seq;
}
static rctf strip_box_get(const bContext *C, const Sequence *seq)
{
const View2D *v2d = UI_view2d_fromcontext(C);
rctf rect;
rect.xmin = strip_start_screenspace_get(C, seq);
rect.xmax = strip_end_screenspace_get(C, seq);
rect.ymin = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0));
rect.ymax = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 1));
return rect;
}
static rctf remove_box_get(const bContext *C, const Sequence *seq)
{
const View2D *v2d = UI_view2d_fromcontext(C);
rctf rect = strip_box_get(C, seq);
rect.ymax = rect.ymin + remove_gizmo_height_get(v2d);
return rect;
}
static bool mouse_is_inside_box(const rctf *box, const int mval[2])
{
return mval[0] >= box->xmin && mval[0] <= box->xmax && mval[1] >= box->ymin &&
mval[1] <= box->ymax;
}
/* -------------------------------------------------------------------- */
/** \name Retiming Add Handle Gizmo
* \{ */
typedef struct RetimeButtonGizmo {
wmGizmo gizmo;
int icon_id;
const Sequence *seq_under_mouse;
bool is_mouse_over_gizmo;
} RetimeButtonGizmo;
typedef struct ButtonDimensions {
float height;
float width;
float x;
float y;
} ButtonDimensions;
static ButtonDimensions button_dimensions_get(const bContext *C, const RetimeButtonGizmo *gizmo)
{
const Scene *scene = CTX_data_scene(C);
const View2D *v2d = UI_view2d_fromcontext(C);
const Sequence *seq = active_seq_from_context(C);
const float icon_height = UI_icon_get_height(gizmo->icon_id) * UI_SCALE_FAC;
const float icon_width = UI_icon_get_width(gizmo->icon_id) * UI_SCALE_FAC;
const float icon_x = UI_view2d_view_to_region_x(v2d, BKE_scene_frame_get(scene)) +
icon_width / 2;
const float icon_y = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0.5)) -
icon_height / 2;
const ButtonDimensions dimensions = {icon_height, icon_width, icon_x, icon_y};
return dimensions;
}
static rctf button_box_get(const bContext *C, const RetimeButtonGizmo *gizmo)
{
ButtonDimensions button_dimensions = button_dimensions_get(C, gizmo);
float x_range = button_dimensions.width;
float y_range = button_dimensions.height;
rctf rect;
rect.xmin = button_dimensions.x;
rect.xmax = button_dimensions.x + x_range;
rect.ymin = button_dimensions.y;
rect.ymax = button_dimensions.y + y_range;
return rect;
}
static void gizmo_retime_handle_add_draw(const bContext *C, wmGizmo *gz)
{
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
return;
}
const Scene *scene = CTX_data_scene(C);
const Sequence *seq = active_seq_from_context(C);
const int frame_index = BKE_scene_frame_get(scene) - SEQ_time_start_frame_get(seq);
const SeqRetimingHandle *handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
if (handle != nullptr && SEQ_retiming_handle_is_transition_type(handle)) {
return;
}
const ButtonDimensions button = button_dimensions_get(C, gizmo);
const rctf strip_box = strip_box_get(C, active_seq_from_context(C));
if (!BLI_rctf_isect_pt(&strip_box, button.x, button.y)) {
return;
}
wmOrtho2_region_pixelspace(CTX_wm_region(C));
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
const float alpha = gizmo->is_mouse_over_gizmo ? 1.0f : 0.6f;
immUniformColor4f(0.2f, 0.2f, 0.2f, alpha);
imm_draw_circle_fill_2d(pos,
button.x + button.width / 2,
button.y + button.height / 2,
button.width * RETIME_BUTTON_SIZE,
32);
immUnbindProgram();
GPU_polygon_smooth(false);
UI_icon_draw_alpha(button.x, button.y, gizmo->icon_id, alpha);
GPU_polygon_smooth(true);
GPU_blend(GPU_BLEND_NONE);
}
static int gizmo_retime_handle_add_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
Sequence *seq = active_seq_from_context(C);
Sequence *mouse_over_seq = nullptr;
gizmo->is_mouse_over_gizmo = false;
/* Store strip under mouse cursor. */
const rctf strip_box = strip_box_get(C, seq);
if (mouse_is_inside_box(&strip_box, mval)) {
mouse_over_seq = seq;
}
if (gizmo->seq_under_mouse != mouse_over_seq) {
gizmo->seq_under_mouse = mouse_over_seq;
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C));
}
if (gizmo->seq_under_mouse == nullptr) {
return -1;
}
const rctf button_box = button_box_get(C, gizmo);
if (!mouse_is_inside_box(&button_box, mval)) {
return -1;
}
gizmo->is_mouse_over_gizmo = true;
const Scene *scene = CTX_data_scene(C);
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
RNA_int_set(&op_elem->ptr, "timeline_frame", BKE_scene_frame_get(scene));
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, CTX_data_scene(C));
return 0;
}
static void gizmo_retime_handle_add_setup(wmGizmo *gz)
{
RetimeButtonGizmo *gizmo = (RetimeButtonGizmo *)gz;
gizmo->icon_id = ICON_ADD;
}
void GIZMO_GT_retime_handle_add(wmGizmoType *gzt)
{
/* Identifiers. */
gzt->idname = "GIZMO_GT_retime_handle_add";
/* Api callbacks. */
gzt->setup = gizmo_retime_handle_add_setup;
gzt->draw = gizmo_retime_handle_add_draw;
gzt->test_select = gizmo_retime_handle_add_test_select;
gzt->struct_size = sizeof(RetimeButtonGizmo);
/* Currently only used for cursor display. */
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Retiming Move Handle Gizmo
* \{ */
typedef struct RetimeHandleMoveGizmo {
wmGizmo gizmo;
const Sequence *mouse_over_seq;
int mouse_over_handle_x;
bool create_transition_operation;
} RetimeHandleMoveGizmo;
static void retime_handle_draw(const bContext *C,
const RetimeHandleMoveGizmo *gizmo,
uint pos,
const Sequence *seq,
const SeqRetimingHandle *handle)
{
const Scene *scene = CTX_data_scene(C);
const float handle_x = handle_x_get(scene, seq, handle);
if (handle_x == SEQ_time_left_handle_frame_get(scene, seq)) {
return;
}
if (handle_x == SEQ_time_right_handle_frame_get(scene, seq)) {
return;
}
const View2D *v2d = UI_view2d_fromcontext(C);
const rctf strip_box = strip_box_get(C, seq);
if (!BLI_rctf_isect_x(&strip_box, UI_view2d_view_to_region_x(v2d, handle_x))) {
return; /* Handle out of strip bounds. */
}
const int ui_triangle_size = remove_gizmo_height_get(v2d);
const float bottom = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0.0f)) + 2;
const float top = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 1.0f)) - 2;
const float handle_position = UI_view2d_view_to_region_x(v2d, handle_x);
float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
if (seq == gizmo->mouse_over_seq && handle_x == gizmo->mouse_over_handle_x) {
if (gizmo->create_transition_operation) {
bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
if (!(handle_is_transition || prev_handle_is_transition)) {
col[0] = 0.5f;
col[2] = 0.4f;
}
}
}
else {
mul_v3_fl(col, 0.65f);
}
immUniformColor4fv(col);
immBegin(GPU_PRIM_TRI_FAN, 3);
immVertex2f(pos, handle_position - ui_triangle_size / 2, bottom);
immVertex2f(pos, handle_position + ui_triangle_size / 2, bottom);
immVertex2f(pos, handle_position, bottom + ui_triangle_size);
immEnd();
immBegin(GPU_PRIM_LINES, 2);
immVertex2f(pos, handle_position, bottom);
immVertex2f(pos, handle_position, top);
immEnd();
}
static void retime_speed_text_draw(const bContext *C,
const Sequence *seq,
const SeqRetimingHandle *handle)
{
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
if (handle == last_handle) {
return;
}
const Scene *scene = CTX_data_scene(C);
const int start_frame = SEQ_time_left_handle_frame_get(scene, seq);
const int end_frame = SEQ_time_right_handle_frame_get(scene, seq);
int next_handle_index = SEQ_retiming_handle_index_get(seq, handle) + 1;
const SeqRetimingHandle *next_handle = &SEQ_retiming_handles_get(seq)[next_handle_index];
if (handle_x_get(scene, seq, next_handle) < start_frame ||
handle_x_get(scene, seq, handle) > end_frame)
{
return; /* Label out of strip bounds. */
}
char label_str[40];
size_t label_len;
if (SEQ_retiming_handle_is_transition_type(handle)) {
const float prev_speed = SEQ_retiming_handle_speed_get(seq, handle - 1);
const float next_speed = SEQ_retiming_handle_speed_get(seq, next_handle + 1);
label_len = SNPRINTF_RLEN(label_str,
"%d%% - %d%%",
round_fl_to_int(prev_speed * 100.0f),
round_fl_to_int(next_speed * 100.0f));
}
else {
const float speed = SEQ_retiming_handle_speed_get(seq, next_handle);
label_len = SNPRINTF_RLEN(label_str, "%d%%", round_fl_to_int(speed * 100.0f));
}
const float width = pixels_to_view_width(C, BLF_width(BLF_default(), label_str, label_len));
const float xmin = max_ff(SEQ_time_left_handle_frame_get(scene, seq),
handle_x_get(scene, seq, handle));
const float xmax = min_ff(SEQ_time_right_handle_frame_get(scene, seq),
handle_x_get(scene, seq, next_handle));
const float text_x = (xmin + xmax - width) / 2;
const float text_y = strip_y_rescale(seq, 0) + pixels_to_view_height(C, 5);
if (width > xmax - xmin) {
return; /* Not enough space to draw label. */
}
const uchar col[4] = {255, 255, 255, 255};
UI_view2d_text_cache_add(UI_view2d_fromcontext(C), text_x, text_y, label_str, label_len, col);
}
static void gizmo_retime_handle_draw(const bContext *C, wmGizmo *gz)
{
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
const View2D *v2d = UI_view2d_fromcontext(C);
/* TODO: This is hard-coded behavior, same as pre-select gizmos in 3D view.
* Better solution would be to check operator keymap and display this information in status bar
* and tool-tip. */
wmEvent *event = CTX_wm_window(C)->eventstate;
gizmo->create_transition_operation = (event->modifier & KM_SHIFT) != 0;
wmOrtho2_region_pixelspace(CTX_wm_region(C));
GPU_blend(GPU_BLEND_ALPHA);
uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR);
Sequence *seq = active_seq_from_context(C);
SEQ_retiming_data_ensure(seq);
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (const SeqRetimingHandle &handle : handles) {
retime_speed_text_draw(C, seq, &handle);
if (&handle == handles.begin()) {
continue; /* Ignore first handle. */
}
retime_handle_draw(C, gizmo, pos, seq, &handle);
}
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
UI_view2d_text_cache_draw(CTX_wm_region(C));
UI_view2d_view_ortho(v2d); /* 'UI_view2d_text_cache_draw()' messes up current view. */
}
static int gizmo_retime_handle_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
RetimeHandleMoveGizmo *gizmo = (RetimeHandleMoveGizmo *)gz;
Scene *scene = CTX_data_scene(C);
gizmo->mouse_over_seq = nullptr;
Sequence *seq = active_seq_from_context(C);
SEQ_retiming_data_ensure(seq);
const SeqRetimingHandle *handle = mouse_over_handle_get(
scene, seq, UI_view2d_fromcontext(C), mval);
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
if (handle == nullptr) {
return -1;
}
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
handle_index == 0)
{
return -1;
}
const View2D *v2d = UI_view2d_fromcontext(C);
rctf strip_box = strip_box_get(C, seq);
BLI_rctf_resize_x(&strip_box, BLI_rctf_size_x(&strip_box) + 2 * remove_gizmo_height_get(v2d));
if (!mouse_is_inside_box(&strip_box, mval)) {
return -1;
}
gizmo->mouse_over_seq = seq;
gizmo->mouse_over_handle_x = handle_x_get(scene, seq, handle);
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return 0;
}
static int gizmo_retime_handle_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
return WM_CURSOR_EW_SCROLL;
}
return WM_CURSOR_DEFAULT;
}
static void gizmo_retime_handle_setup(wmGizmo *gz)
{
gz->flag = WM_GIZMO_DRAW_MODAL;
}
void GIZMO_GT_retime_handle(wmGizmoType *gzt)
{
/* Identifiers. */
gzt->idname = "GIZMO_GT_retime_handle_move";
/* Api callbacks. */
gzt->setup = gizmo_retime_handle_setup;
gzt->draw = gizmo_retime_handle_draw;
gzt->test_select = gizmo_retime_handle_test_select;
gzt->cursor_get = gizmo_retime_handle_cursor_get;
gzt->struct_size = sizeof(RetimeHandleMoveGizmo);
/* Currently only used for cursor display. */
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Retiming Remove Handle Gizmo
* \{ */
static void gizmo_retime_remove_draw(const bContext * /* C */, wmGizmo * /* gz */)
{
/* Pass. */
}
static int gizmo_retime_remove_test_select(bContext *C, wmGizmo *gz, const int mval[2])
{
Scene *scene = CTX_data_scene(C);
Sequence *seq = active_seq_from_context(C);
SEQ_retiming_data_ensure(seq);
const SeqRetimingHandle *handle = mouse_over_handle_get(
scene, seq, UI_view2d_fromcontext(C), mval);
const int handle_index = SEQ_retiming_handle_index_get(seq, handle);
if (handle == nullptr) {
return -1;
}
if (handle_x_get(scene, seq, handle) == SEQ_time_left_handle_frame_get(scene, seq) ||
handle_index == 0)
{
return -1; /* Ignore first handle. */
}
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
if (handle == last_handle) {
return -1; /* Last handle can not be removed. */
}
const View2D *v2d = UI_view2d_fromcontext(C);
rctf box = remove_box_get(C, seq);
BLI_rctf_resize_x(&box, BLI_rctf_size_x(&box) + 2 * remove_gizmo_height_get(v2d));
if (!mouse_is_inside_box(&box, mval)) {
return -1;
}
wmGizmoOpElem *op_elem = WM_gizmo_operator_get(gz, 0);
RNA_int_set(&op_elem->ptr, "handle_index", handle_index);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return 0;
}
static int gizmo_retime_remove_cursor_get(wmGizmo *gz)
{
if (RNA_boolean_get(gz->ptr, "show_drag")) {
return WM_CURSOR_ERASER;
}
return WM_CURSOR_DEFAULT;
}
void GIZMO_GT_retime_remove(wmGizmoType *gzt)
{
/* Identifiers. */
gzt->idname = "GIZMO_GT_retime_handle_remove";
/* Api callbacks. */
gzt->draw = gizmo_retime_remove_draw;
gzt->test_select = gizmo_retime_remove_test_select;
gzt->cursor_get = gizmo_retime_remove_cursor_get;
gzt->struct_size = sizeof(wmGizmo);
/* Currently only used for cursor display. */
RNA_def_boolean(gzt->srna, "show_drag", true, "Show Drag", "");
}
/** \} */

View File

@@ -10,17 +10,11 @@
#include "DNA_sequence_types.h"
#include "RNA_access.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Internal exports only. */
struct ARegion;
struct ARegionType;
struct Depsgraph;
struct wmGizmoGroupType;
struct wmGizmoType;
struct Main;
struct Scene;
struct SeqCollection;
@@ -305,21 +299,3 @@ int sequencer_image_seq_get_minmax_frame(struct wmOperator *op,
int *r_numdigits);
void sequencer_image_seq_reserve_frames(
struct wmOperator *op, struct StripElem *se, int len, int minframe, int numdigits);
/* sequencer_retiming.c */
void SEQUENCER_OT_retiming_reset(struct wmOperatorType *ot);
void SEQUENCER_OT_retiming_handle_move(struct wmOperatorType *ot);
void SEQUENCER_OT_retiming_handle_add(struct wmOperatorType *ot);
void SEQUENCER_OT_retiming_handle_remove(struct wmOperatorType *ot);
/* sequencer_gizmo_retime.c */
void SEQUENCER_GGT_gizmo_retime(struct wmGizmoGroupType *gzgt);
/* sequencer_gizmo_retime_type.c */
void GIZMO_GT_retime_handle_add(struct wmGizmoType *gzt);
void GIZMO_GT_retime_handle(struct wmGizmoType *gzt);
void GIZMO_GT_retime_remove(struct wmGizmoType *gzt);
#ifdef __cplusplus
}
#endif

View File

@@ -68,12 +68,6 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_cursor_set);
WM_operatortype_append(SEQUENCER_OT_scene_frame_range_update);
/* sequencer_retiming.c */
WM_operatortype_append(SEQUENCER_OT_retiming_reset);
WM_operatortype_append(SEQUENCER_OT_retiming_handle_move);
WM_operatortype_append(SEQUENCER_OT_retiming_handle_add);
WM_operatortype_append(SEQUENCER_OT_retiming_handle_remove);
/* sequencer_select.c */
WM_operatortype_append(SEQUENCER_OT_select_all);
WM_operatortype_append(SEQUENCER_OT_select);

View File

@@ -1,442 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
/** \file
* \ingroup spseq
*/
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_retiming.h"
#include "SEQ_retiming.hh"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "WM_api.h"
#include "RNA_define.h"
#include "UI_interface.h"
#include "UI_view2d.h"
#include "DEG_depsgraph.h"
/* Own include. */
#include "sequencer_intern.h"
using blender::MutableSpan;
static bool retiming_poll(bContext *C)
{
const Editing *ed = SEQ_editing_get(CTX_data_scene(C));
if (ed == nullptr) {
return false;
}
Sequence *seq = ed->act_seq;
if (seq == nullptr) {
return false;
}
if (!SEQ_retiming_is_allowed(seq)) {
CTX_wm_operator_poll_msg_set(C, "This strip type can not be retimed");
return false;
}
return true;
}
static void retiming_handle_overlap(Scene *scene, Sequence *seq)
{
ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
SeqCollection *strips = SEQ_collection_create(__func__);
SEQ_collection_append_strip(seq, strips);
SeqCollection *dependant = SEQ_collection_create(__func__);
SEQ_collection_expand(scene, seqbase, strips, SEQ_query_strip_effect_chain);
SEQ_collection_remove_strip(seq, dependant);
SEQ_transform_handle_overlap(scene, seqbase, strips, dependant, true);
SEQ_collection_free(strips);
SEQ_collection_free(dependant);
}
/*-------------------------------------------------------------------- */
/** \name Retiming Reset
* \{ */
static int sequencer_retiming_reset_exec(bContext *C, wmOperator * /* op */)
{
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
Sequence *seq = ed->act_seq;
SEQ_retiming_data_clear(seq);
retiming_handle_overlap(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_retiming_reset(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Reset Retiming";
ot->description = "Reset strip retiming";
ot->idname = "SEQUENCER_OT_retiming_reset";
/* api callbacks */
ot->exec = sequencer_retiming_reset_exec;
ot->poll = retiming_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Retiming Move Handle
* \{ */
static SeqRetimingHandle *closest_retiming_handle_get(const bContext *C,
const Sequence *seq,
const float mouse_x)
{
const View2D *v2d = UI_view2d_fromcontext(C);
const Scene *scene = CTX_data_scene(C);
int best_distance = INT_MAX;
SeqRetimingHandle *closest_handle = nullptr;
const float distance_threshold = UI_view2d_region_to_view_x(v2d, 10);
const float mouse_x_view = UI_view2d_region_to_view_x(v2d, mouse_x);
for (int i = 0; i < SEQ_retiming_handles_count(seq); i++) {
SeqRetimingHandle *handle = seq->retiming_handles + i;
const int distance = round_fl_to_int(
fabsf(SEQ_retiming_handle_timeline_frame_get(scene, seq, handle) - mouse_x_view));
if (distance < distance_threshold && distance < best_distance) {
best_distance = distance;
closest_handle = handle;
}
}
return closest_handle;
}
static int sequencer_retiming_handle_move_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
Sequence *seq = ed->act_seq;
int handle_index = 0;
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
handle_index = RNA_int_get(op->ptr, "handle_index");
}
/* Ensure retiming handle at left handle position. This way user gets more predictable result
* when strips have offsets. */
const int left_handle_frame = SEQ_time_left_handle_frame_get(scene, seq);
if (SEQ_retiming_add_handle(scene, seq, left_handle_frame) != nullptr) {
handle_index++; /* Advance index, because new handle was created. */
}
MutableSpan handles = SEQ_retiming_handles_get(seq);
SeqRetimingHandle *handle = nullptr;
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
BLI_assert(handle_index < handles.size());
handle = &handles[handle_index];
}
else {
handle = closest_retiming_handle_get(C, seq, event->mval[0]);
}
if (handle == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No handle available");
return OPERATOR_CANCELLED;
}
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, handle));
if ((event->modifier & KM_SHIFT) != 0) {
op->customdata = (void *)1;
}
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int sequencer_retiming_handle_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
const ARegion *region = CTX_wm_region(C);
const View2D *v2d = &region->v2d;
const Editing *ed = SEQ_editing_get(scene);
Sequence *seq = ed->act_seq;
int handle_index = RNA_int_get(op->ptr, "handle_index");
SeqRetimingHandle *handle = &SEQ_retiming_handles_get(seq)[handle_index];
switch (event->type) {
case MOUSEMOVE: {
float mouse_x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
int offset = 0;
offset = mouse_x - SEQ_retiming_handle_timeline_frame_get(scene, seq, handle);
if (offset == 0) {
return OPERATOR_RUNNING_MODAL;
}
/* Add retiming gradient and move handle. */
if (op->customdata) {
SeqRetimingHandle *transition_handle = SEQ_retiming_add_transition(
scene, seq, handle, abs(offset));
/* New gradient handle was created - update operator properties. */
if (transition_handle != nullptr) {
if (offset < 0) {
handle = transition_handle;
}
else {
handle = transition_handle + 1;
}
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, handle));
}
}
const bool handle_is_transition = SEQ_retiming_handle_is_transition_type(handle);
const bool prev_handle_is_transition = SEQ_retiming_handle_is_transition_type(handle - 1);
/* When working with transition, change handles when moving past pivot point. */
if (handle_is_transition || prev_handle_is_transition) {
SeqRetimingHandle *transition_start, *transition_end;
if (handle_is_transition) {
transition_start = handle;
transition_end = handle + 1;
}
else {
transition_start = handle - 1;
transition_end = handle;
}
const int offset_l = mouse_x -
SEQ_retiming_handle_timeline_frame_get(scene, seq, transition_start);
const int offset_r = mouse_x -
SEQ_retiming_handle_timeline_frame_get(scene, seq, transition_end);
if (prev_handle_is_transition && offset_l < 0) {
RNA_int_set(
op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, transition_start));
}
if (handle_is_transition && offset_r > 0) {
RNA_int_set(op->ptr, "handle_index", SEQ_retiming_handle_index_get(seq, transition_end));
}
}
SEQ_retiming_offset_handle(scene, seq, handle, offset);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_RUNNING_MODAL;
}
case LEFTMOUSE:
case EVT_RETKEY:
case EVT_SPACEKEY: {
retiming_handle_overlap(scene, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
case EVT_ESCKEY:
case RIGHTMOUSE: {
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_CANCELLED;
}
}
return OPERATOR_RUNNING_MODAL;
}
void SEQUENCER_OT_retiming_handle_move(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Move Retiming Handle";
ot->description = "Move retiming handle";
ot->idname = "SEQUENCER_OT_retiming_handle_move";
/* api callbacks */
ot->invoke = sequencer_retiming_handle_move_invoke;
ot->modal = sequencer_retiming_handle_move_modal;
ot->poll = retiming_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop = RNA_def_int(ot->srna,
"handle_index",
0,
0,
INT_MAX,
"Handle Index",
"Index of handle to be moved",
0,
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Retiming Add Handle
* \{ */
static int sequesequencer_retiming_handle_add_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
Sequence *seq = ed->act_seq;
SEQ_retiming_data_ensure(seq);
float timeline_frame;
if (RNA_struct_property_is_set(op->ptr, "timeline_frame")) {
timeline_frame = RNA_int_get(op->ptr, "timeline_frame");
}
else {
timeline_frame = BKE_scene_frame_get(scene);
}
const int frame_index = BKE_scene_frame_get(scene) - SEQ_time_start_frame_get(seq);
const SeqRetimingHandle *handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
if (SEQ_retiming_handle_is_transition_type(handle)) {
BKE_report(op->reports, RPT_ERROR, "Can not create handle inside of speed transition");
return OPERATOR_CANCELLED;
}
bool inserted = false;
const float end_frame = seq->start + SEQ_time_strip_length_get(scene, seq);
if (seq->start < timeline_frame && end_frame > timeline_frame) {
SEQ_retiming_add_handle(scene, seq, timeline_frame);
inserted = true;
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return inserted ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH;
}
void SEQUENCER_OT_retiming_handle_add(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Add Retiming Handle";
ot->description = "Add retiming Handle";
ot->idname = "SEQUENCER_OT_retiming_handle_add";
/* api callbacks */
ot->exec = sequesequencer_retiming_handle_add_exec;
ot->poll = retiming_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_int(ot->srna,
"timeline_frame",
0,
0,
INT_MAX,
"Timeline Frame",
"Frame where handle will be added",
0,
INT_MAX);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Retiming Remove Handle
* \{ */
static int sequencer_retiming_handle_remove_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
Sequence *seq = ed->act_seq;
SeqRetimingHandle *handle = (SeqRetimingHandle *)op->customdata;
SEQ_retiming_remove_handle(scene, seq, handle);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
}
static int sequencer_retiming_handle_remove_invoke(bContext *C,
wmOperator *op,
const wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
const Editing *ed = SEQ_editing_get(scene);
const Sequence *seq = ed->act_seq;
if (seq == nullptr) {
return OPERATOR_CANCELLED;
}
MutableSpan handles = SEQ_retiming_handles_get(seq);
SeqRetimingHandle *handle = nullptr;
if (RNA_struct_property_is_set(op->ptr, "handle_index")) {
const int handle_index = RNA_int_get(op->ptr, "handle_index");
BLI_assert(handle_index < handles.size());
handle = &handles[handle_index];
}
else {
handle = closest_retiming_handle_get(C, seq, event->mval[0]);
}
if (handle == nullptr) {
BKE_report(op->reports, RPT_ERROR, "No handle available");
return OPERATOR_CANCELLED;
}
op->customdata = handle;
return sequencer_retiming_handle_remove_exec(C, op);
}
void SEQUENCER_OT_retiming_handle_remove(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Remove Retiming Handle";
ot->description = "Remove retiming handle";
ot->idname = "SEQUENCER_OT_retiming_handle_remove";
/* api callbacks */
ot->invoke = sequencer_retiming_handle_remove_invoke;
ot->exec = sequencer_retiming_handle_remove_exec;
ot->poll = retiming_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
PropertyRNA *prop = RNA_def_int(ot->srna,
"handle_index",
0,
0,
INT_MAX,
"Handle Index",
"Index of handle to be removed",
0,
INT_MAX);
RNA_def_property_flag(prop, PROP_HIDDEN);
}
/** \} */

View File

@@ -426,15 +426,10 @@ static void sequencer_gizmos(void)
wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(
&(const struct wmGizmoMapType_Params){SPACE_SEQ, RGN_TYPE_PREVIEW});
WM_gizmotype_append(GIZMO_GT_retime_handle_add);
WM_gizmotype_append(GIZMO_GT_retime_handle);
WM_gizmotype_append(GIZMO_GT_retime_remove);
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(SEQUENCER_GGT_gizmo_retime);
WM_gizmogrouptype_append_and_link(gzmap_type, SEQUENCER_GGT_navigate);
}
@@ -589,7 +584,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
case ND_SEQUENCER:
case ND_RENDER_RESULT:
ED_region_tag_redraw(region);
WM_gizmomap_tag_refresh(region->gizmo_map);
break;
}
break;
@@ -603,7 +597,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
case NC_SPACE:
if (wmn->data == ND_SPACE_SEQUENCER) {
ED_region_tag_redraw(region);
WM_gizmomap_tag_refresh(region->gizmo_map);
}
break;
case NC_ID:
@@ -614,7 +607,6 @@ static void sequencer_main_region_listener(const wmRegionListenerParams *params)
case NC_SCREEN:
if (ELEM(wmn->data, ND_ANIMPLAY)) {
ED_region_tag_redraw(region);
WM_gizmomap_tag_refresh(region->gizmo_map);
}
break;
}
@@ -1031,6 +1023,7 @@ void ED_spacetype_sequencer(void)
art->on_view2d_changed = sequencer_main_region_view2d_changed;
art->listener = sequencer_main_region_listener;
art->message_subscribe = sequencer_main_region_message_subscribe;
/* NOTE: inclusion of #ED_KEYMAP_GIZMO is currently for scripts and isn't used by default. */
art->keymapflag = ED_KEYMAP_TOOL | ED_KEYMAP_GIZMO | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES |
ED_KEYMAP_ANIMATION;
BLI_addhead(&st->regiontypes, art);

View File

@@ -121,20 +121,6 @@ typedef struct Strip {
ColorManagedColorspaceSettings colorspace_settings;
} Strip;
typedef enum eSeqRetimingHandleFlag {
SPEED_TRANSITION = (1 << 0),
} eSeqRetimingHandleFlag;
typedef struct SeqRetimingHandle {
int strip_frame_index;
int flag; /* eSeqRetimingHandleFlag */
int _pad0;
float retiming_factor; /* Value between 0-1 mapped to original content range. */
int original_strip_frame_index; /* Used for transition handles only. */
float original_retiming_factor; /* Used for transition handles only. */
} SeqRetimingHandle;
typedef struct SequenceRuntime {
SessionUUID session_uuid;
} SequenceRuntime;
@@ -179,12 +165,12 @@ typedef struct Sequence {
float startstill, endstill;
/** Machine: the strip channel */
int machine;
int _pad;
int _pad3;
/** Starting and ending points of the effect strip. Undefined for other strip types. */
int startdisp, enddisp;
float sat;
float mul;
float _pad1;
float _pad;
short anim_preseek; /* UNUSED. */
/** Streamindex for movie or sound files with several streams. */
@@ -246,7 +232,7 @@ typedef struct Sequence {
int8_t color_tag;
char alpha_mode;
char _pad2[2];
char _pad4[2];
int cache_flag;
@@ -256,7 +242,7 @@ typedef struct Sequence {
/* Multiview */
char views_format;
char _pad3[3];
char _pad1[3];
struct Stereo3dFormat *stereo3d_format;
struct IDProperty *prop;
@@ -266,13 +252,9 @@ typedef struct Sequence {
/* Playback rate of strip content in frames per second. */
float media_playback_rate;
/* Multiply strip playback speed. */
float speed_factor;
struct SeqRetimingHandle *retiming_handles;
void *_pad5;
int retiming_handle_num;
char _pad6[4];
SequenceRuntime runtime;
} Sequence;

View File

@@ -468,7 +468,6 @@ void RNA_api_region_view3d(struct StructRNA *srna);
void RNA_api_texture(struct StructRNA *srna);
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, bool metastrip);
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sequence_retiming_handles(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sound(struct StructRNA *srna);
void RNA_api_vfont(struct StructRNA *srna);
void RNA_api_workspace(struct StructRNA *srna);

View File

@@ -43,7 +43,6 @@
#include "SEQ_prefetch.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_retiming.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
@@ -273,7 +272,7 @@ static int rna_SequenceEditor_elements_length(PointerRNA *ptr)
return (int)olen;
}
static void rna_Sequence_elements_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
static void rna_SequenceEditor_elements_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
Sequence *seq = (Sequence *)ptr->data;
rna_iterator_array_begin(iter,
@@ -284,85 +283,6 @@ static void rna_Sequence_elements_begin(CollectionPropertyIterator *iter, Pointe
NULL);
}
static int rna_Sequence_retiming_handles_length(PointerRNA *ptr)
{
return SEQ_retiming_handles_count((Sequence *)ptr->data);
}
static void rna_SequenceEditor_retiming_handles_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
Sequence *seq = (Sequence *)ptr->data;
rna_iterator_array_begin(iter,
(void *)seq->retiming_handles,
sizeof(SeqRetimingHandle),
SEQ_retiming_handles_count(seq),
0,
NULL);
}
static Sequence *strip_by_handle_find(Scene *scene, SeqRetimingHandle *handle)
{
Editing *ed = SEQ_editing_get(scene);
SeqCollection *strips = SEQ_query_all_strips_recursive(&ed->seqbase);
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
const int retiming_handle_count = SEQ_retiming_handles_count(seq);
SeqRetimingHandle *first = seq->retiming_handles;
SeqRetimingHandle *last = seq->retiming_handles + retiming_handle_count - 1;
if (handle >= first && handle <= last) {
return seq;
}
}
return NULL;
}
static void rna_Sequence_retiming_handle_remove(ID *id, SeqRetimingHandle *handle)
{
Scene *scene = (Scene *)id;
Sequence *seq = strip_by_handle_find(scene, handle);
if (seq == NULL) {
return;
}
SEQ_retiming_remove_handle(scene, seq, handle);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
static int rna_Sequence_retiming_handle_frame_get(PointerRNA *ptr)
{
SeqRetimingHandle *handle = (SeqRetimingHandle *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
Sequence *seq = strip_by_handle_find(scene, handle);
if (seq == NULL) {
return 0;
}
return SEQ_time_start_frame_get(seq) + handle->strip_frame_index;
}
static void rna_Sequence_retiming_handle_frame_set(PointerRNA *ptr, int value)
{
SeqRetimingHandle *handle = (SeqRetimingHandle *)ptr->data;
Scene *scene = (Scene *)ptr->owner_id;
Sequence *seq = strip_by_handle_find(scene, handle);
if (seq == NULL) {
return;
}
const int offset = value - (SEQ_time_start_frame_get(seq) + handle->strip_frame_index);
SEQ_retiming_offset_handle(scene, seq, handle, offset);
SEQ_relations_invalidate_cache_raw(scene, seq);
}
static void rna_Sequence_views_format_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
rna_Sequence_invalidate_raw_update(bmain, scene, ptr);
@@ -1579,31 +1499,6 @@ static void rna_def_strip_element(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Orig FPS", "Original frames per second");
}
static void rna_def_retiming_handle(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "RetimingHandle", NULL);
RNA_def_struct_ui_text(
srna,
"Retiming Handle",
"Handle mapped to particular frame that can be moved to change playback speed");
RNA_def_struct_sdna(srna, "SeqRetimingHandle");
prop = RNA_def_property(srna, "timeline_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "strip_frame_index");
RNA_def_property_int_funcs(prop,
"rna_Sequence_retiming_handle_frame_get",
"rna_Sequence_retiming_handle_frame_set",
NULL);
RNA_def_property_ui_text(prop, "Timeline Frame", "Position of retiming handle in timeline");
FunctionRNA *func = RNA_def_function(srna, "remove", "rna_Sequence_retiming_handle_remove");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Remove retiming handle");
}
static void rna_def_strip_crop(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2675,7 +2570,7 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SequenceElement");
RNA_def_property_ui_text(prop, "Elements", "");
RNA_def_property_collection_funcs(prop,
"rna_Sequence_elements_begin",
"rna_SequenceEditor_elements_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
@@ -2707,6 +2602,7 @@ static void rna_def_image(BlenderRNA *brna)
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_color_management(srna);
rna_def_speed_factor(srna);
}
static void rna_def_meta(BlenderRNA *brna)
@@ -2738,6 +2634,7 @@ static void rna_def_meta(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_speed_factor(srna);
}
static void rna_def_scene(BlenderRNA *brna)
@@ -2786,6 +2683,7 @@ static void rna_def_scene(BlenderRNA *brna)
rna_def_proxy(srna);
rna_def_input(srna);
rna_def_movie_types(srna);
rna_def_speed_factor(srna);
}
static void rna_def_movie(BlenderRNA *brna)
@@ -2813,7 +2711,7 @@ static void rna_def_movie(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "SequenceElement");
RNA_def_property_ui_text(prop, "Elements", "");
RNA_def_property_collection_funcs(prop,
"rna_Sequence_elements_begin",
"rna_SequenceEditor_elements_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
@@ -2822,21 +2720,6 @@ static void rna_def_movie(BlenderRNA *brna)
NULL,
NULL);
prop = RNA_def_property(srna, "retiming_handles", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "retiming_handles", NULL);
RNA_def_property_struct_type(prop, "RetimingHandle");
RNA_def_property_ui_text(prop, "Retiming Handles", "");
RNA_def_property_collection_funcs(prop,
"rna_SequenceEditor_retiming_handles_begin",
"rna_iterator_array_next",
"rna_iterator_array_end",
"rna_iterator_array_get",
"rna_Sequence_retiming_handles_length",
NULL,
NULL,
NULL);
RNA_api_sequence_retiming_handles(brna, prop);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
RNA_def_property_ui_text(prop, "File", "");
RNA_def_property_string_funcs(prop,
@@ -2884,6 +2767,7 @@ static void rna_def_movie(BlenderRNA *brna)
rna_def_input(srna);
rna_def_color_management(srna);
rna_def_movie_types(srna);
rna_def_speed_factor(srna);
}
static void rna_def_movieclip(BlenderRNA *brna)
@@ -2911,6 +2795,7 @@ static void rna_def_movieclip(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_input(srna);
rna_def_movie_types(srna);
rna_def_speed_factor(srna);
}
static void rna_def_mask(BlenderRNA *brna)
@@ -2929,6 +2814,7 @@ static void rna_def_mask(BlenderRNA *brna)
rna_def_filter_video(srna);
rna_def_input(srna);
rna_def_speed_factor(srna);
}
static void rna_def_sound(BlenderRNA *brna)
@@ -3734,7 +3620,6 @@ void RNA_def_sequencer(BlenderRNA *brna)
rna_def_color_balance(brna);
rna_def_strip_element(brna);
rna_def_retiming_handle(brna);
rna_def_strip_proxy(brna);
rna_def_strip_color_balance(brna);
rna_def_strip_crop(brna);

View File

@@ -44,7 +44,6 @@
# include "SEQ_effects.h"
# include "SEQ_relations.h"
# include "SEQ_render.h"
# include "SEQ_retiming.h"
# include "SEQ_sequencer.h"
# include "SEQ_time.h"
@@ -644,29 +643,6 @@ static void rna_Sequence_invalidate_cache_rnafunc(ID *id, Sequence *self, int ty
}
}
static SeqRetimingHandle *rna_Sequence_retiming_handles_add(ID *id,
Sequence *seq,
int timeline_frame)
{
Scene *scene = (Scene *)id;
SeqRetimingHandle *handle = SEQ_retiming_add_handle(scene, seq, timeline_frame);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
return handle;
}
static void rna_Sequence_retiming_handles_reset(ID *id, Sequence *seq)
{
Scene *scene = (Scene *)id;
SEQ_retiming_data_clear(seq);
SEQ_relations_invalidate_cache_raw(scene, seq);
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, NULL);
}
#else
void RNA_api_sequence_strip(StructRNA *srna)
@@ -774,30 +750,6 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
}
void RNA_api_sequence_retiming_handles(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
RNA_def_property_srna(cprop, "RetimingHandles");
srna = RNA_def_struct(brna, "RetimingHandles", NULL);
RNA_def_struct_sdna(srna, "Sequence");
RNA_def_struct_ui_text(srna, "RetimingHandles", "Collection of RetimingHandle");
FunctionRNA *func = RNA_def_function(srna, "add", "rna_Sequence_retiming_handles_add");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_int(
func, "timeline_frame", 0, -MAXFRAME, MAXFRAME, "Timeline Frame", "", -MAXFRAME, MAXFRAME);
RNA_def_function_ui_description(func, "Add retiming handle");
/* return type */
PropertyRNA *parm = RNA_def_pointer(
func, "retiming_handle", "RetimingHandle", "", "New RetimingHandle");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "reset", "rna_Sequence_retiming_handles_reset");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Remove all retiming handles");
}
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip)
{
StructRNA *srna;

View File

@@ -42,8 +42,6 @@ set(SRC
SEQ_proxy.h
SEQ_relations.h
SEQ_render.h
SEQ_retiming.h
SEQ_retiming.hh
SEQ_select.h
SEQ_sequencer.h
SEQ_sound.h
@@ -78,7 +76,6 @@ set(SRC
intern/strip_add.c
intern/strip_edit.c
intern/strip_relations.c
intern/strip_retiming.cc
intern/strip_select.c
intern/strip_time.c
intern/strip_time.h

View File

@@ -1,57 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2004 Blender Foundation. */
#pragma once
/** \file
* \ingroup sequencer
*/
#ifdef __cplusplus
extern "C" {
#endif
struct Scene;
struct Sequence;
struct SeqRetimingHandle;
int SEQ_retiming_handles_count(const struct Sequence *seq);
bool SEQ_retiming_is_active(const struct Sequence *seq);
void SEQ_retiming_data_ensure(struct Sequence *seq);
void SEQ_retiming_data_clear(struct Sequence *seq);
bool SEQ_retiming_is_allowed(const struct Sequence *seq);
/**
* Add new retiming handle.
* This function always reallocates memory, so when function is used all stored pointers will
* become invalid.
*/
struct SeqRetimingHandle *SEQ_retiming_add_handle(const struct Scene *scene,
struct Sequence *seq,
const int timeline_frame);
SeqRetimingHandle *SEQ_retiming_add_transition(const struct Scene *scene,
struct Sequence *seq,
struct SeqRetimingHandle *handle,
const int offset);
struct SeqRetimingHandle *SEQ_retiming_last_handle_get(const struct Sequence *seq);
void SEQ_retiming_remove_handle(const struct Scene *scene,
struct Sequence *seq,
struct SeqRetimingHandle *handle);
void SEQ_retiming_offset_handle(const struct Scene *scene,
struct Sequence *seq,
struct SeqRetimingHandle *handle,
const int offset);
float SEQ_retiming_handle_speed_get(const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
int SEQ_retiming_handle_index_get(const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
void SEQ_retiming_sound_animation_data_set(const struct Scene *scene, const struct Sequence *seq);
float SEQ_retiming_handle_timeline_frame_get(const struct Scene *scene,
const struct Sequence *seq,
const struct SeqRetimingHandle *handle);
const SeqRetimingHandle *SEQ_retiming_find_segment_start_handle(const struct Sequence *seq,
const int frame_index);
bool SEQ_retiming_handle_is_transition_type(const struct SeqRetimingHandle *handle);
#ifdef __cplusplus
}
#endif

View File

@@ -1,15 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
#pragma once
/** \file
* \ingroup sequencer
*/
#include "BLI_span.hh"
struct Sequence;
struct SeqRetimingHandle;
blender::MutableSpan<SeqRetimingHandle> SEQ_retiming_handles_get(const Sequence *seq);

View File

@@ -73,8 +73,6 @@ int SEQ_time_find_next_prev_edit(struct Scene *scene,
bool SEQ_time_strip_intersects_frame(const struct Scene *scene,
const struct Sequence *seq,
int timeline_frame);
/* Convert timeline frame so strip frame index. */
float SEQ_give_frame_index(const struct Scene *scene, struct Sequence *seq, float timeline_frame);
/**
* Returns true if strip has frames without content to render.
*/
@@ -140,6 +138,7 @@ void SEQ_time_start_frame_set(const struct Scene *scene, struct Sequence *seq, i
* \note this function is currently only used internally and in versioning code.
*/
void SEQ_time_update_meta_strip_range(const struct Scene *scene, struct Sequence *seq_meta);
#ifdef __cplusplus
}
#endif

View File

@@ -2615,7 +2615,7 @@ float seq_speed_effect_target_frame_get(Scene *scene,
}
SEQ_effect_handle_get(seq_speed); /* Ensure, that data are initialized. */
int frame_index = SEQ_give_frame_index(scene, seq_speed, timeline_frame);
int frame_index = seq_give_frame_index(scene, seq_speed, timeline_frame);
SpeedControlVars *s = (SpeedControlVars *)seq_speed->effectdata;
const Sequence *source = seq_speed->seq1;

View File

@@ -142,7 +142,7 @@ static float seq_cache_timeline_frame_to_frame_index(Scene *scene,
* images or extended frame range of movies will only generate one cache entry. No special
* treatment in converting frame index to timeline_frame is needed. */
if (ELEM(type, SEQ_CACHE_STORE_RAW, SEQ_CACHE_STORE_THUMBNAIL)) {
return SEQ_give_frame_index(scene, seq, timeline_frame);
return seq_give_frame_index(scene, seq, timeline_frame);
}
return timeline_frame - SEQ_time_start_frame_get(seq);

View File

@@ -211,7 +211,7 @@ ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int timeline
}
if (proxy->storage & SEQ_STORAGE_PROXY_CUSTOM_FILE) {
int frameno = (int)SEQ_give_frame_index(context->scene, seq, timeline_frame) +
int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
seq->anim_startofs;
if (proxy->anim == NULL) {
if (seq_proxy_get_fname(

View File

@@ -238,7 +238,7 @@ StripElem *SEQ_render_give_stripelem(const Scene *scene, Sequence *seq, int time
* all other strips don't use this...
*/
int frame_index = (int)SEQ_give_frame_index(scene, seq, timeline_frame);
int frame_index = (int)seq_give_frame_index(scene, seq, timeline_frame);
if (frame_index == -1 || se == NULL) {
return NULL;
@@ -1047,7 +1047,7 @@ static ImBuf *seq_render_movie_strip_custom_file_proxy(const SeqRenderData *cont
}
}
int frameno = (int)SEQ_give_frame_index(context->scene, seq, timeline_frame) +
int frameno = (int)seq_give_frame_index(context->scene, seq, timeline_frame) +
seq->anim_startofs;
return IMB_anim_absolute(proxy->anim, frameno, IMB_TC_NONE, IMB_PROXY_NONE);
}
@@ -1664,7 +1664,7 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context,
bool *r_is_proxy_image)
{
ImBuf *ibuf = NULL;
float frame_index = SEQ_give_frame_index(context->scene, seq, timeline_frame);
float frame_index = seq_give_frame_index(context->scene, seq, timeline_frame);
int type = (seq->type & SEQ_TYPE_EFFECT) ? SEQ_TYPE_EFFECT : seq->type;
switch (type) {
case SEQ_TYPE_META: {

View File

@@ -18,7 +18,6 @@
#include "BLI_listbase.h"
#include "BKE_fcurve.h"
#include "BKE_idprop.h"
#include "BKE_lib_id.h"
#include "BKE_sound.h"
@@ -35,7 +34,6 @@
#include "SEQ_modifier.h"
#include "SEQ_proxy.h"
#include "SEQ_relations.h"
#include "SEQ_retiming.h"
#include "SEQ_select.h"
#include "SEQ_sequencer.h"
#include "SEQ_sound.h"
@@ -220,12 +218,6 @@ static void seq_sequence_free_ex(Scene *scene,
SEQ_channels_free(&seq->channels);
}
if (seq->retiming_handles != NULL) {
MEM_freeN(seq->retiming_handles);
seq->retiming_handles = NULL;
seq->retiming_handle_num = 0;
}
MEM_freeN(seq);
}
@@ -584,11 +576,6 @@ static Sequence *seq_dupli(const Scene *scene_src,
}
}
if (seq->retiming_handles != NULL) {
seqn->retiming_handles = MEM_dupallocN(seq->retiming_handles);
seqn->retiming_handle_num = seq->retiming_handle_num;
}
return seqn;
}
@@ -762,12 +749,6 @@ static bool seq_write_data_cb(Sequence *seq, void *userdata)
LISTBASE_FOREACH (SeqTimelineChannel *, channel, &seq->channels) {
BLO_write_struct(writer, SeqTimelineChannel, channel);
}
if (seq->retiming_handles != NULL) {
int size = SEQ_retiming_handles_count(seq);
BLO_write_struct_array(writer, SeqRetimingHandle, size, seq->retiming_handles);
}
return true;
}
@@ -837,11 +818,6 @@ static bool seq_read_data_cb(Sequence *seq, void *user_data)
SEQ_modifier_blend_read_data(reader, &seq->modifiers);
BLO_read_list(reader, &seq->channels);
if (seq->retiming_handles != NULL) {
BLO_read_data_address(reader, &seq->retiming_handles);
}
return true;
}
void SEQ_blend_read(BlendDataReader *reader, ListBase *seqbase)
@@ -991,7 +967,9 @@ static bool seq_update_seq_cb(Sequence *seq, void *user_data)
}
BKE_sound_set_scene_sound_volume(
seq->scene_sound, seq->volume, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
SEQ_retiming_sound_animation_data_set(scene, seq);
BKE_sound_set_scene_sound_pitch(seq->scene_sound,
SEQ_sound_pitch_get(scene, seq),
(seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
BKE_sound_set_scene_sound_pan(
seq->scene_sound, seq->pan, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}

View File

@@ -440,7 +440,6 @@ Sequence *SEQ_add_movie_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL
if (load_data->flags & SEQ_LOAD_MOVIE_SYNC_FPS) {
scene->r.frs_sec = fps_denom;
scene->r.frs_sec_base = fps_num;
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_FPS | ID_RECALC_SEQUENCER_STRIPS);
}
load_data->r_video_stream_start = IMD_anim_get_offset(anim_arr[0]);

View File

@@ -275,7 +275,9 @@ static void seq_split_set_right_hold_offset(Main *bmain,
/* Adjust within range of strip contents. */
else if ((timeline_frame >= content_start) && (timeline_frame <= content_end)) {
seq->endofs = 0;
float speed_factor = seq_time_media_playback_rate_factor_get(scene, seq);
float speed_factor = (seq->type == SEQ_TYPE_SOUND_RAM) ?
seq_time_media_playback_rate_factor_get(scene, seq) :
seq_time_playback_rate_factor_get(scene, seq);
seq->anim_endofs += round_fl_to_int((content_end - timeline_frame) * speed_factor);
}
@@ -294,7 +296,9 @@ static void seq_split_set_left_hold_offset(Main *bmain,
/* Adjust within range of strip contents. */
if ((timeline_frame >= content_start) && (timeline_frame <= content_end)) {
float speed_factor = seq_time_media_playback_rate_factor_get(scene, seq);
float speed_factor = (seq->type == SEQ_TYPE_SOUND_RAM) ?
seq_time_media_playback_rate_factor_get(scene, seq) :
seq_time_playback_rate_factor_get(scene, seq);
seq->anim_startofs += round_fl_to_int((timeline_frame - content_start) * speed_factor);
seq->start = timeline_frame;
seq->startofs = 0;

View File

@@ -1,742 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. */
/** \file
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_span.hh"
#include "BLI_vector.hh"
#include "BKE_fcurve.h"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "DNA_anim_types.h"
#include "DNA_sound_types.h"
#include "IMB_imbuf.h"
#include "RNA_prototypes.h"
#include "SEQ_channels.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_retiming.h"
#include "SEQ_retiming.hh"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
#include "sequencer.h"
#include "strip_time.h"
#include "utils.h"
using blender::MutableSpan;
MutableSpan<SeqRetimingHandle> SEQ_retiming_handles_get(const Sequence *seq)
{
blender::MutableSpan<SeqRetimingHandle> handles(seq->retiming_handles, seq->retiming_handle_num);
return handles;
}
struct SeqRetimingHandle *SEQ_retiming_last_handle_get(const struct Sequence *seq)
{
return seq->retiming_handles + seq->retiming_handle_num - 1;
}
int SEQ_retiming_handle_index_get(const Sequence *seq, const SeqRetimingHandle *handle)
{
return handle - seq->retiming_handles;
}
static bool seq_retiming_is_last_handle(const Sequence *seq, const SeqRetimingHandle *handle)
{
return SEQ_retiming_handle_index_get(seq, handle) == seq->retiming_handle_num - 1;
}
const SeqRetimingHandle *SEQ_retiming_find_segment_start_handle(const Sequence *seq,
const int frame_index)
{
const SeqRetimingHandle *start_handle = nullptr;
for (auto const &handle : SEQ_retiming_handles_get(seq)) {
if (seq_retiming_is_last_handle(seq, &handle)) {
break;
}
if (handle.strip_frame_index > frame_index) {
break;
}
start_handle = &handle;
}
return start_handle;
}
int SEQ_retiming_handles_count(const Sequence *seq)
{
return seq->retiming_handle_num;
}
void SEQ_retiming_data_ensure(Sequence *seq)
{
if (!SEQ_retiming_is_allowed(seq)) {
return;
}
if (seq->retiming_handles != nullptr) {
return;
}
seq->retiming_handles = (SeqRetimingHandle *)MEM_calloc_arrayN(
2, sizeof(SeqRetimingHandle), __func__);
SeqRetimingHandle *handle = seq->retiming_handles + 1;
handle->strip_frame_index = seq->len;
handle->retiming_factor = 1.0f;
seq->retiming_handle_num = 2;
}
void SEQ_retiming_data_clear(Sequence *seq)
{
seq->retiming_handles = nullptr;
seq->retiming_handle_num = 0;
}
bool SEQ_retiming_is_active(const Sequence *seq)
{
return seq->retiming_handle_num > 1;
}
bool SEQ_retiming_is_allowed(const Sequence *seq)
{
return ELEM(seq->type,
SEQ_TYPE_SOUND_RAM,
SEQ_TYPE_IMAGE,
SEQ_TYPE_META,
SEQ_TYPE_SCENE,
SEQ_TYPE_MOVIE,
SEQ_TYPE_MOVIECLIP,
SEQ_TYPE_MASK);
}
static int seq_retiming_segment_length_get(const SeqRetimingHandle *start_handle)
{
const SeqRetimingHandle *end_handle = start_handle + 1;
return end_handle->strip_frame_index - start_handle->strip_frame_index;
}
static float seq_retiming_segment_step_get(const SeqRetimingHandle *start_handle)
{
const SeqRetimingHandle *end_handle = start_handle + 1;
const int segment_length = seq_retiming_segment_length_get(start_handle);
const float segment_fac_diff = end_handle->retiming_factor - start_handle->retiming_factor;
return segment_fac_diff / segment_length;
}
static void seq_retiming_segment_as_line_segment(const SeqRetimingHandle *start_handle,
double r_v1[2],
double r_v2[2])
{
const SeqRetimingHandle *end_handle = start_handle + 1;
r_v1[0] = start_handle->strip_frame_index;
r_v1[1] = start_handle->retiming_factor;
r_v2[0] = end_handle->strip_frame_index;
r_v2[1] = end_handle->retiming_factor;
}
static void seq_retiming_line_segments_tangent_circle(const SeqRetimingHandle *start_handle,
double r_center[2],
double *radius)
{
double s1_1[2], s1_2[2], s2_1[2], s2_2[2], p1_2[2];
/* Get 2 segments. */
seq_retiming_segment_as_line_segment(start_handle - 1, s1_1, s1_2);
seq_retiming_segment_as_line_segment(start_handle + 1, s2_1, s2_2);
/* Backup first segment end point - needed to calculate arc radius. */
copy_v2_v2_db(p1_2, s1_2);
/* Convert segments to vectors. */
double v1[2], v2[2];
sub_v2_v2v2_db(v1, s1_1, s1_2);
sub_v2_v2v2_db(v2, s2_1, s2_2);
/* Rotate segments by 90 degrees around seg. 1 end and seg. 2 start point. */
SWAP(double, v1[0], v1[1]);
SWAP(double, v2[0], v2[1]);
v1[0] *= -1;
v2[0] *= -1;
copy_v2_v2_db(s1_1, s1_2);
add_v2_v2_db(s1_2, v1);
copy_v2_v2_db(s2_2, s2_1);
add_v2_v2_db(s2_2, v2);
/* Get center and radius of arc segment between 2 linear segments. */
double lambda, mu;
isect_seg_seg_v2_lambda_mu_db(s1_1, s1_2, s2_1, s2_2, &lambda, &mu);
r_center[0] = s1_1[0] + lambda * (s1_2[0] - s1_1[0]);
r_center[1] = s1_1[1] + lambda * (s1_2[1] - s1_1[1]);
*radius = len_v2v2_db(p1_2, r_center);
}
bool SEQ_retiming_handle_is_transition_type(const SeqRetimingHandle *handle)
{
return (handle->flag & SPEED_TRANSITION) != 0;
}
/* Check colinearity of 2 segments allowing for some imprecision.
* `isect_seg_seg_v2_lambda_mu_db()` return value does not work well in this case. */
static bool seq_retiming_transition_is_linear(const Sequence *seq, const SeqRetimingHandle *handle)
{
const float prev_speed = SEQ_retiming_handle_speed_get(seq, handle - 1);
const float next_speed = SEQ_retiming_handle_speed_get(seq, handle + 1);
return abs(prev_speed - next_speed) < 0.01f;
}
static float seq_retiming_evaluate_arc_segment(const SeqRetimingHandle *handle,
const float frame_index)
{
double c[2], r;
seq_retiming_line_segments_tangent_circle(handle, c, &r);
const int side = c[1] > handle->retiming_factor ? -1 : 1;
const float y = c[1] + side * sqrt(pow(r, 2) - pow((frame_index - c[0]), 2));
return y;
}
float seq_retiming_evaluate(const Sequence *seq, const float frame_index)
{
const SeqRetimingHandle *start_handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
const int start_handle_index = start_handle - seq->retiming_handles;
BLI_assert(start_handle_index < seq->retiming_handle_num);
const float segment_frame_index = frame_index - start_handle->strip_frame_index;
if (!SEQ_retiming_handle_is_transition_type(start_handle)) {
const float segment_step = seq_retiming_segment_step_get(start_handle);
return start_handle->retiming_factor + segment_step * segment_frame_index;
}
if (seq_retiming_transition_is_linear(seq, start_handle)) {
const float segment_step = seq_retiming_segment_step_get(start_handle - 1);
return start_handle->retiming_factor + segment_step * segment_frame_index;
}
/* Sanity check for transition type. */
BLI_assert(start_handle_index > 0);
BLI_assert(start_handle_index < seq->retiming_handle_num - 1);
UNUSED_VARS_NDEBUG(start_handle_index);
return seq_retiming_evaluate_arc_segment(start_handle, frame_index);
}
SeqRetimingHandle *SEQ_retiming_add_handle(const Scene *scene,
Sequence *seq,
const int timeline_frame)
{
float frame_index = (timeline_frame - SEQ_time_start_frame_get(seq)) *
seq_time_media_playback_rate_factor_get(scene, seq);
float value = seq_retiming_evaluate(seq, frame_index);
const SeqRetimingHandle *start_handle = SEQ_retiming_find_segment_start_handle(seq, frame_index);
if (start_handle->strip_frame_index == frame_index) {
return nullptr; /* Retiming handle already exists. */
}
if (SEQ_retiming_handle_is_transition_type(start_handle)) {
return nullptr;
}
SeqRetimingHandle *handles = seq->retiming_handles;
size_t handle_count = SEQ_retiming_handles_count(seq);
const int new_handle_index = start_handle - handles + 1;
BLI_assert(new_handle_index >= 0);
BLI_assert(new_handle_index < handle_count);
SeqRetimingHandle *new_handles = (SeqRetimingHandle *)MEM_callocN(
(handle_count + 1) * sizeof(SeqRetimingHandle), __func__);
if (new_handle_index > 0) {
memcpy(new_handles, handles, new_handle_index * sizeof(SeqRetimingHandle));
}
if (new_handle_index < handle_count) {
memcpy(new_handles + new_handle_index + 1,
handles + new_handle_index,
(handle_count - new_handle_index) * sizeof(SeqRetimingHandle));
}
MEM_freeN(handles);
seq->retiming_handles = new_handles;
seq->retiming_handle_num++;
SeqRetimingHandle *added_handle = (new_handles + new_handle_index);
added_handle->strip_frame_index = frame_index;
added_handle->retiming_factor = value;
return added_handle;
}
static void seq_retiming_offset_linear_handle(const Scene *scene,
Sequence *seq,
SeqRetimingHandle *handle,
const int offset)
{
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (SeqRetimingHandle *next_handle = handle; next_handle < handles.end(); next_handle++) {
next_handle->strip_frame_index += offset * seq_time_media_playback_rate_factor_get(scene, seq);
}
/* Handle affected transitions: remove and re-create transition. This way transition won't change
* length.
* Alternative solution is to find where in arc segment the `y` value is closest to `handle`
* retiming factor, then trim transition to that point. This would change transition length. */
if (SEQ_retiming_handle_is_transition_type(handle - 2)) {
SeqRetimingHandle *transition_handle = handle - 2;
const int transition_offset = transition_handle->strip_frame_index -
transition_handle->original_strip_frame_index;
const int transition_handle_index = SEQ_retiming_handle_index_get(seq, transition_handle);
SEQ_retiming_remove_handle(scene, seq, transition_handle);
SeqRetimingHandle *orig_handle = seq->retiming_handles + transition_handle_index;
SEQ_retiming_add_transition(scene, seq, orig_handle, -transition_offset);
}
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
seq_time_update_effects_strip_range(scene, seq_sequence_lookup_effects_by_seq(scene, seq));
}
static void seq_retiming_offset_transition_handle(const Scene *scene,
const Sequence *seq,
SeqRetimingHandle *handle,
const int offset)
{
SeqRetimingHandle *handle_start, *handle_end;
int corrected_offset;
if (SEQ_retiming_handle_is_transition_type(handle)) {
handle_start = handle;
handle_end = handle + 1;
corrected_offset = offset;
}
else {
handle_start = handle - 1;
handle_end = handle;
corrected_offset = -1 * offset;
}
/* Prevent transition handles crossing each other. */
const float start_frame = SEQ_retiming_handle_timeline_frame_get(scene, seq, handle_start);
const float end_frame = SEQ_retiming_handle_timeline_frame_get(scene, seq, handle_end);
int xmax = ((start_frame + end_frame) / 2) - 1;
int max_offset = xmax - start_frame;
corrected_offset = min_ii(corrected_offset, max_offset);
/* Prevent mirrored movement crossing any handle. */
SeqRetimingHandle *prev_segment_end = handle_start - 1, *next_segment_start = handle_end + 1;
const int offset_min_left = SEQ_retiming_handle_timeline_frame_get(
scene, seq, prev_segment_end) +
1 - start_frame;
const int offset_min_right =
end_frame - SEQ_retiming_handle_timeline_frame_get(scene, seq, next_segment_start) - 1;
corrected_offset = max_iii(corrected_offset, offset_min_left, offset_min_right);
const float prev_segment_step = seq_retiming_segment_step_get(handle_start - 1);
const float next_segment_step = seq_retiming_segment_step_get(handle_end);
handle_start->strip_frame_index += corrected_offset;
handle_start->retiming_factor += corrected_offset * prev_segment_step;
handle_end->strip_frame_index -= corrected_offset;
handle_end->retiming_factor -= corrected_offset * next_segment_step;
}
void SEQ_retiming_offset_handle(const Scene *scene,
Sequence *seq,
SeqRetimingHandle *handle,
const int offset)
{
if (handle->strip_frame_index == 0) {
return; /* First handle can not be moved. */
}
SeqRetimingHandle *prev_handle = handle - 1;
SeqRetimingHandle *next_handle = handle + 1;
/* Limit retiming handle movement. */
int corrected_offset = offset;
int handle_frame = SEQ_retiming_handle_timeline_frame_get(scene, seq, handle);
int offset_min = SEQ_retiming_handle_timeline_frame_get(scene, seq, prev_handle) + 1 -
handle_frame;
int offset_max;
if (SEQ_retiming_handle_index_get(seq, handle) == seq->retiming_handle_num - 1) {
offset_max = INT_MAX;
}
else {
offset_max = SEQ_retiming_handle_timeline_frame_get(scene, seq, next_handle) - 1 -
handle_frame;
}
corrected_offset = max_ii(corrected_offset, offset_min);
corrected_offset = min_ii(corrected_offset, offset_max);
if (SEQ_retiming_handle_is_transition_type(handle) ||
SEQ_retiming_handle_is_transition_type(prev_handle))
{
seq_retiming_offset_transition_handle(scene, seq, handle, corrected_offset);
}
else {
seq_retiming_offset_linear_handle(scene, seq, handle, corrected_offset);
}
}
static void seq_retiming_remove_handle_ex(Sequence *seq, SeqRetimingHandle *handle)
{
SeqRetimingHandle *last_handle = SEQ_retiming_last_handle_get(seq);
if (handle->strip_frame_index == 0 || handle == last_handle) {
return; /* First and last handle can not be removed. */
}
size_t handle_count = SEQ_retiming_handles_count(seq);
SeqRetimingHandle *handles = (SeqRetimingHandle *)MEM_callocN(
(handle_count - 1) * sizeof(SeqRetimingHandle), __func__);
const int handle_index = handle - seq->retiming_handles;
memcpy(handles, seq->retiming_handles, (handle_index) * sizeof(SeqRetimingHandle));
memcpy(handles + handle_index,
seq->retiming_handles + handle_index + 1,
(handle_count - handle_index - 1) * sizeof(SeqRetimingHandle));
MEM_freeN(seq->retiming_handles);
seq->retiming_handles = handles;
seq->retiming_handle_num--;
}
/* This function removes transition segment and creates retiming handle where it originally was. */
static void seq_retiming_remove_transition(const Scene *scene,
Sequence *seq,
SeqRetimingHandle *handle)
{
const int orig_frame_index = handle->original_strip_frame_index;
const float orig_retiming_factor = handle->original_retiming_factor;
/* Remove both handles defining transition. */
int handle_index = SEQ_retiming_handle_index_get(seq, handle);
seq_retiming_remove_handle_ex(seq, handle);
seq_retiming_remove_handle_ex(seq, seq->retiming_handles + handle_index);
/* Create original linear handle. */
SeqRetimingHandle *orig_handle = SEQ_retiming_add_handle(
scene, seq, SEQ_time_start_frame_get(seq) + orig_frame_index);
orig_handle->retiming_factor = orig_retiming_factor;
}
void SEQ_retiming_remove_handle(const Scene *scene, Sequence *seq, SeqRetimingHandle *handle)
{
if (SEQ_retiming_handle_is_transition_type(handle)) {
seq_retiming_remove_transition(scene, seq, handle);
return;
}
SeqRetimingHandle *previous_handle = handle - 1;
if (SEQ_retiming_handle_is_transition_type(previous_handle)) {
seq_retiming_remove_transition(scene, seq, previous_handle);
return;
}
seq_retiming_remove_handle_ex(seq, handle);
}
SeqRetimingHandle *SEQ_retiming_add_transition(const Scene *scene,
Sequence *seq,
SeqRetimingHandle *handle,
const int offset)
{
if (SEQ_retiming_handle_is_transition_type(handle) ||
SEQ_retiming_handle_is_transition_type(handle - 1))
{
return nullptr;
}
const int orig_handle_index = SEQ_retiming_handle_index_get(seq, handle);
const int orig_timeline_frame = SEQ_retiming_handle_timeline_frame_get(scene, seq, handle);
const int orig_frame_index = handle->strip_frame_index;
const float orig_retiming_factor = handle->retiming_factor;
SEQ_retiming_add_handle(scene, seq, orig_timeline_frame + offset);
SeqRetimingHandle *transition_handle = SEQ_retiming_add_handle(
scene, seq, orig_timeline_frame - offset);
transition_handle->flag |= SPEED_TRANSITION;
transition_handle->original_strip_frame_index = orig_frame_index;
transition_handle->original_retiming_factor = orig_retiming_factor;
seq_retiming_remove_handle_ex(seq, seq->retiming_handles + orig_handle_index + 1);
return seq->retiming_handles + orig_handle_index;
}
float SEQ_retiming_handle_speed_get(const Sequence *seq, const SeqRetimingHandle *handle)
{
if (handle->strip_frame_index == 0) {
return 1.0f;
}
const SeqRetimingHandle *handle_prev = handle - 1;
const int frame_index_max = seq->len - 1;
const int frame_retimed_prev = round_fl_to_int(handle_prev->retiming_factor * frame_index_max);
const int frame_index_prev = handle_prev->strip_frame_index;
const int frame_retimed = round_fl_to_int(handle->retiming_factor * frame_index_max);
const int frame_index = handle->strip_frame_index;
const int fragment_length_retimed = frame_retimed - frame_retimed_prev;
const int fragment_length_original = frame_index - frame_index_prev;
const float speed = float(fragment_length_retimed) / float(fragment_length_original);
return speed;
}
enum eRangeType {
LINEAR = 0,
TRANSITION = 1,
};
enum eIntersectType {
FULL,
PARTIAL_START,
PARTIAL_END,
INSIDE,
NONE,
};
class RetimingRange {
public:
int start, end;
float speed;
blender::Vector<float> speed_table;
eRangeType type;
RetimingRange(const Sequence *seq, int start_frame, int end_frame, float speed, eRangeType type)
: start(start_frame), end(end_frame), speed(speed), type(type)
{
if (type == TRANSITION) {
speed = 1.0f;
claculate_speed_table_from_seq(seq);
}
}
RetimingRange(int start_frame, int end_frame, float speed, eRangeType type)
: start(start_frame), end(end_frame), speed(speed), type(type)
{
}
RetimingRange duplicate()
{
RetimingRange new_range = RetimingRange(start, end, speed, type);
for (int i = 0; i < speed_table.size(); i++) {
new_range.speed_table.append(speed_table[i]);
}
return new_range;
}
/* Create new range representing overlap of 2 ranges.
* Returns overlapping range. */
RetimingRange operator*(const RetimingRange rhs_range)
{
RetimingRange new_range = RetimingRange(0, 0, 0, LINEAR);
/* Offsets to merge speed tables. */
int range_offset = 0, rhs_range_offset = 0;
if (intersect_type(rhs_range) == FULL) {
new_range.start = start;
new_range.end = end;
rhs_range_offset = start - rhs_range.start;
}
else if (intersect_type(rhs_range) == PARTIAL_START) {
new_range.start = start;
new_range.end = rhs_range.end;
rhs_range_offset = start - rhs_range.start;
}
else if (intersect_type(rhs_range) == PARTIAL_END) {
new_range.start = rhs_range.start;
new_range.end = end;
range_offset = rhs_range.start - start;
}
else if (intersect_type(rhs_range) == INSIDE) {
new_range.start = rhs_range.start;
new_range.end = rhs_range.end;
range_offset = rhs_range.start - start;
}
if (type != TRANSITION && rhs_range.type != TRANSITION) {
new_range.speed = speed * rhs_range.speed;
return new_range;
}
/* One of ranges is transition type, so speed tables has to be copied. */
new_range.type = TRANSITION;
new_range.speed = 1.0f;
const int new_range_len = new_range.end - new_range.start;
if (type == TRANSITION && rhs_range.type == TRANSITION) {
for (int i = 0; i < new_range_len; i++) {
const float range_speed = speed_table[i + range_offset];
const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
new_range.speed_table.append(range_speed * rhs_range_speed);
}
}
else if (type == TRANSITION) {
for (int i = 0; i < new_range_len; i++) {
const float range_speed = speed_table[i + range_offset];
new_range.speed_table.append(range_speed * rhs_range.speed);
}
}
else if (rhs_range.type == TRANSITION) {
for (int i = 0; i < new_range_len; i++) {
const float rhs_range_speed = rhs_range.speed_table[i + rhs_range_offset];
new_range.speed_table.append(speed * rhs_range_speed);
}
}
return new_range;
}
void claculate_speed_table_from_seq(const Sequence *seq)
{
for (int frame = start; frame <= end; frame++) {
/* We need number actual number of frames here. */
const double normal_step = 1 / (double)seq->len;
/* Who needs calculus, when you can have slow code? */
const double val_prev = seq_retiming_evaluate(seq, frame - 1);
const double val = seq_retiming_evaluate(seq, frame);
const double speed_at_frame = (val - val_prev) / normal_step;
speed_table.append(speed_at_frame);
}
}
const eIntersectType intersect_type(const RetimingRange &other) const
{
if (other.start <= start && other.end >= end) {
return FULL;
}
if (other.start > start && other.start < end && other.end > start && other.end < end) {
return INSIDE;
}
if (other.start > start && other.start < end) {
return PARTIAL_END;
}
if (other.end > start && other.end < end) {
return PARTIAL_START;
}
return NONE;
}
};
class RetimingRangeData {
public:
blender::Vector<RetimingRange> ranges;
RetimingRangeData(const Sequence *seq)
{
MutableSpan handles = SEQ_retiming_handles_get(seq);
for (const SeqRetimingHandle &handle : handles) {
if (handle.strip_frame_index == 0) {
continue;
}
const SeqRetimingHandle *handle_prev = &handle - 1;
float speed = SEQ_retiming_handle_speed_get(seq, &handle);
int frame_start = SEQ_time_start_frame_get(seq) + handle_prev->strip_frame_index;
int frame_end = SEQ_time_start_frame_get(seq) + handle.strip_frame_index;
eRangeType type = SEQ_retiming_handle_is_transition_type(handle_prev) ? TRANSITION : LINEAR;
RetimingRange range = RetimingRange(seq, frame_start, frame_end, speed, type);
ranges.append(range);
}
}
RetimingRangeData &operator*=(const RetimingRangeData rhs)
{
if (ranges.is_empty()) {
for (const RetimingRange &rhs_range : rhs.ranges) {
RetimingRange range = RetimingRange(
rhs_range.start, rhs_range.end, rhs_range.speed, rhs_range.type);
ranges.append(range);
}
return *this;
}
for (int i = 0; i < ranges.size(); i++) {
RetimingRange &range = ranges[i];
for (const RetimingRange &rhs_range : rhs.ranges) {
if (range.intersect_type(rhs_range) == NONE) {
continue;
}
else if (range.intersect_type(rhs_range) == FULL) {
RetimingRange isect = range * rhs_range;
ranges.remove(i);
ranges.insert(i, isect);
}
if (range.intersect_type(rhs_range) == PARTIAL_START) {
ranges.insert(i, range * rhs_range);
ranges.insert(i, range * rhs_range);
range.start = rhs_range.end + 1;
}
else if (range.intersect_type(rhs_range) == PARTIAL_END) {
ranges.insert(i, range * rhs_range);
range.end = rhs_range.start;
}
else if (range.intersect_type(rhs_range) == INSIDE) {
RetimingRange left_range = range.duplicate();
left_range.end = rhs_range.start;
range.start = rhs_range.end + 1;
ranges.insert(i, left_range);
ranges.insert(i, range * rhs_range);
}
}
}
return *this;
}
};
static RetimingRangeData seq_retiming_range_data_get(const Scene *scene, const Sequence *seq)
{
RetimingRangeData strip_retiming_data = RetimingRangeData(seq);
const Sequence *meta_parent = seq_sequence_lookup_meta_by_seq(scene, seq);
if (meta_parent == nullptr) {
return strip_retiming_data;
}
RetimingRangeData meta_retiming_data = RetimingRangeData(meta_parent);
strip_retiming_data *= meta_retiming_data;
return strip_retiming_data;
}
void SEQ_retiming_sound_animation_data_set(const Scene *scene, const Sequence *seq)
{
RetimingRangeData retiming_data = seq_retiming_range_data_get(scene, seq);
for (int i = 0; i < retiming_data.ranges.size(); i++) {
RetimingRange range = retiming_data.ranges[i];
if (range.type == TRANSITION) {
const int range_length = range.end - range.start;
for (int i = 0; i <= range_length; i++) {
const int frame = range.start + i;
BKE_sound_set_scene_sound_pitch_at_frame(
seq->scene_sound, frame, range.speed_table[i], true);
}
}
else {
BKE_sound_set_scene_sound_pitch_constant_range(
seq->scene_sound, range.start, range.end, range.speed);
}
}
}
float SEQ_retiming_handle_timeline_frame_get(const Scene *scene,
const Sequence *seq,
const SeqRetimingHandle *handle)
{
return SEQ_time_start_frame_get(seq) +
handle->strip_frame_index / seq_time_media_playback_rate_factor_get(scene, seq);
}

View File

@@ -7,31 +7,22 @@
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BKE_fcurve.h"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "DNA_anim_types.h"
#include "DNA_sound_types.h"
#include "IMB_imbuf.h"
#include "RNA_prototypes.h"
#include "SEQ_channels.h"
#include "SEQ_iterator.h"
#include "SEQ_relations.h"
#include "SEQ_render.h"
#include "SEQ_retiming.h"
#include "SEQ_sequencer.h"
#include "SEQ_time.h"
#include "SEQ_transform.h"
@@ -53,21 +44,17 @@ float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence
return seq->media_playback_rate / scene_playback_rate;
}
int seq_time_strip_original_content_length_get(const Scene *scene, const Sequence *seq)
{
if (seq->type == SEQ_TYPE_SOUND_RAM) {
return seq->len;
}
float seq_time_playback_rate_factor_get(const Scene *scene, const Sequence *seq)
return seq->len / seq_time_media_playback_rate_factor_get(scene, seq);
{
return seq_time_media_playback_rate_factor_get(scene, seq) * seq->speed_factor;
}
float SEQ_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame)
{
float frame_index;
float sta = SEQ_time_start_frame_get(seq);
float end = SEQ_time_content_end_frame_get(scene, seq) - 1;
const float length = seq->len;
if (seq->type & SEQ_TYPE_EFFECT) {
end = SEQ_time_right_handle_frame_get(scene, seq);
@@ -88,16 +75,9 @@ float SEQ_give_frame_index(const Scene *scene, Sequence *seq, float timeline_fra
frame_index = timeline_frame - sta;
}
frame_index = max_ff(frame_index, 0);
frame_index *= seq_time_media_playback_rate_factor_get(scene, seq);
if (SEQ_retiming_is_active(seq)) {
const float retiming_factor = seq_retiming_evaluate(seq, frame_index);
frame_index = retiming_factor * (length);
}
/* Clamp frame index to strip content frame range. */
frame_index = clamp_f(frame_index, 0, length);
/* Clamp frame index to strip frame range. */
frame_index = clamp_f(frame_index, 0, end - sta);
frame_index *= seq_time_playback_rate_factor_get(scene, seq);
if (seq->strobe < 1.0f) {
seq->strobe = 1.0f;
@@ -503,14 +483,11 @@ bool SEQ_time_has_still_frames(const Scene *scene, const Sequence *seq)
int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq)
{
if (SEQ_retiming_is_active(seq)) {
SeqRetimingHandle *handle_start = seq->retiming_handles;
SeqRetimingHandle *handle_end = seq->retiming_handles + (SEQ_retiming_handles_count(seq) - 1);
return handle_end->strip_frame_index / seq_time_media_playback_rate_factor_get(scene, seq) -
(handle_start->strip_frame_index) / seq_time_media_playback_rate_factor_get(scene, seq);
if (seq->type == SEQ_TYPE_SOUND_RAM) {
return seq->len;
}
return seq->len / seq_time_media_playback_rate_factor_get(scene, seq);
return seq->len / seq_time_playback_rate_factor_get(scene, seq);
}
float SEQ_time_start_frame_get(const Sequence *seq)

View File

@@ -16,6 +16,7 @@ struct Scene;
struct Sequence;
struct SeqCollection;
float seq_give_frame_index(const struct Scene *scene, struct Sequence *seq, float timeline_frame);
void seq_update_sound_bounds_recursive(const struct Scene *scene, struct Sequence *metaseq);
/* Describes gap between strips in timeline. */
@@ -45,9 +46,7 @@ void seq_time_update_effects_strip_range(const struct Scene *scene, struct SeqCo
void seq_time_translate_handles(const struct Scene *scene, struct Sequence *seq, const int offset);
float seq_time_media_playback_rate_factor_get(const struct Scene *scene,
const struct Sequence *seq);
int seq_time_strip_original_content_length_get(const struct Scene *scene,
const struct Sequence *seq);
float seq_retiming_evaluate(const struct Sequence *seq, const float frame_index);
float seq_time_playback_rate_factor_get(const struct Scene *scene, const struct Sequence *seq);
#ifdef __cplusplus
}