Skip to content

Transform Improvements (Keyframe origin point) #496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions include/Clip.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ namespace openshot {
void reverse_buffer(juce::AudioSampleBuffer* buffer);

public:
openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent
openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent
openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to
openshot::FrameDisplayType display; ///< The format to display the frame number (if any)
openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips
openshot::GravityType gravity; ///< The gravity of a clip determines where it snaps to its parent
openshot::ScaleType scale; ///< The scale determines how a clip should be resized to fit its parent
openshot::AnchorType anchor; ///< The anchor determines what parent a clip should snap to
openshot::FrameDisplayType display; ///< The format to display the frame number (if any)
openshot::VolumeMixType mixing; ///< What strategy should be followed when mixing audio with other clips

/// Default Constructor
Clip();
Expand Down Expand Up @@ -208,15 +208,19 @@ namespace openshot {
bool Waveform() { return waveform; } ///< Get the waveform property of this clip
void Waveform(bool value) { waveform = value; } ///< Set the waveform property of this clip

// Scale and Location curves
// Scale, Location, and Alpha curves
openshot::Keyframe scale_x; ///< Curve representing the horizontal scaling in percent (0 to 1)
openshot::Keyframe scale_y; ///< Curve representing the vertical scaling in percent (0 to 1)
openshot::Keyframe location_x; ///< Curve representing the relative X position in percent based on the gravity (-1 to 1)
openshot::Keyframe location_y; ///< Curve representing the relative Y position in percent based on the gravity (-1 to 1)

// Alpha and Rotation curves
openshot::Keyframe alpha; ///< Curve representing the alpha (1 to 0)

// Rotation and Shear curves (origin point (x,y) is adjustable for both rotation and shear)
openshot::Keyframe rotation; ///< Curve representing the rotation (0 to 360)
openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
openshot::Keyframe origin_x; ///< Curve representing X origin point (0.0=0% (left), 1.0=100% (right))
openshot::Keyframe origin_y; ///< Curve representing Y origin point (0.0=0% (top), 1.0=100% (bottom))

// Time and Volume curves
openshot::Keyframe time; ///< Curve representing the frames over time to play (used for speed and direction of video)
Expand All @@ -232,9 +236,7 @@ namespace openshot {
openshot::Keyframe crop_x; ///< Curve representing X offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)
openshot::Keyframe crop_y; ///< Curve representing Y offset in percent (-1.0=-100%, 0.0=0%, 1.0=100%)

// Shear and perspective curves
openshot::Keyframe shear_x; ///< Curve representing X shear angle in degrees (-45.0=left, 45.0=right)
openshot::Keyframe shear_y; ///< Curve representing Y shear angle in degrees (-45.0=down, 45.0=up)
// Perspective curves
openshot::Keyframe perspective_c1_x; ///< Curves representing X for coordinate 1
openshot::Keyframe perspective_c1_y; ///< Curves representing Y for coordinate 1
openshot::Keyframe perspective_c2_x; ///< Curves representing X for coordinate 2
Expand Down
10 changes: 10 additions & 0 deletions src/Clip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ void Clip::init_settings()
// Init shear and perspective curves
shear_x = Keyframe(0.0);
shear_y = Keyframe(0.0);
origin_x = Keyframe(0.5);
origin_y = Keyframe(0.5);
perspective_c1_x = Keyframe(-1.0);
perspective_c1_y = Keyframe(-1.0);
perspective_c2_x = Keyframe(-1.0);
Expand Down Expand Up @@ -718,6 +720,8 @@ std::string Clip::PropertiesJSON(int64_t requested_frame) const {
root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", &shear_x, -1.0, 1.0, false, requested_frame);
root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", &shear_y, -1.0, 1.0, false, requested_frame);
root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", &rotation, -360, 360, false, requested_frame);
root["origin_x"] = add_property_json("Origin X", origin_x.GetValue(requested_frame), "float", "", &origin_x, 0.0, 1.0, false, requested_frame);
root["origin_y"] = add_property_json("Origin Y", origin_y.GetValue(requested_frame), "float", "", &origin_y, 0.0, 1.0, false, requested_frame);
root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", &volume, 0.0, 1.0, false, requested_frame);
root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", &time, 0.0, 30 * 60 * 60 * 48, false, requested_frame);
root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", &channel_filter, -1, 10, false, requested_frame);
Expand Down Expand Up @@ -774,6 +778,8 @@ Json::Value Clip::JsonValue() const {
root["crop_y"] = crop_y.JsonValue();
root["shear_x"] = shear_x.JsonValue();
root["shear_y"] = shear_y.JsonValue();
root["origin_x"] = origin_x.JsonValue();
root["origin_y"] = origin_y.JsonValue();
root["channel_filter"] = channel_filter.JsonValue();
root["channel_mapping"] = channel_mapping.JsonValue();
root["has_audio"] = has_audio.JsonValue();
Expand Down Expand Up @@ -871,6 +877,10 @@ void Clip::SetJsonValue(const Json::Value root) {
shear_x.SetJsonValue(root["shear_x"]);
if (!root["shear_y"].isNull())
shear_y.SetJsonValue(root["shear_y"]);
if (!root["origin_x"].isNull())
origin_x.SetJsonValue(root["origin_x"]);
if (!root["origin_y"].isNull())
origin_y.SetJsonValue(root["origin_y"]);
if (!root["channel_filter"].isNull())
channel_filter.SetJsonValue(root["channel_filter"]);
if (!root["channel_mapping"].isNull())
Expand Down
33 changes: 15 additions & 18 deletions src/Timeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,28 +677,31 @@ void Timeline::add_layer(std::shared_ptr<Frame> new_frame, Clip* source_clip, in
y += (Settings::Instance()->MAX_HEIGHT * source_clip->location_y.GetValue(clip_frame_number)); // move in percentage of final height
float shear_x = source_clip->shear_x.GetValue(clip_frame_number);
float shear_y = source_clip->shear_y.GetValue(clip_frame_number);
float origin_x = source_clip->origin_x.GetValue(clip_frame_number);
float origin_y = source_clip->origin_y.GetValue(clip_frame_number);

bool transformed = false;
QTransform transform;

// Transform source image (if needed)
ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Build QTransform - if needed)", "source_frame->number", source_frame->number, "x", x, "y", y, "r", r, "sx", sx, "sy", sy);

if (!isEqual(r, 0)) {
// ROTATE CLIP
float origin_x = x + (scaled_source_width / 2.0);
float origin_y = y + (scaled_source_height / 2.0);
transform.translate(origin_x, origin_y);
transform.rotate(r);
transform.translate(-origin_x,-origin_y);
if (!isEqual(x, 0) || !isEqual(y, 0)) {
// TRANSLATE/MOVE CLIP
transform.translate(x, y);
transformed = true;
}

if (!isEqual(x, 0) || !isEqual(y, 0)) {
// TRANSLATE/MOVE CLIP
transform.translate(x, y);
transformed = true;
}
if (!isEqual(r, 0) || !isEqual(shear_x, 0) || !isEqual(shear_y, 0)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code has related issue: OpenShot/openshot-qt#2794

// ROTATE CLIP (around origin_x, origin_y)
float origin_x_value = (scaled_source_width * origin_x);
float origin_y_value = (scaled_source_height * origin_y);
transform.translate(origin_x_value, origin_y_value);
transform.rotate(r);
transform.shear(shear_x, shear_y);
transform.translate(-origin_x_value,-origin_y_value);
transformed = true;
}

// SCALE CLIP (if needed)
float source_width_scale = (float(source_size.width()) / float(source_image->width())) * sx;
Expand All @@ -709,12 +712,6 @@ void Timeline::add_layer(std::shared_ptr<Frame> new_frame, Clip* source_clip, in
transformed = true;
}

if (!isEqual(shear_x, 0) || !isEqual(shear_y, 0)) {
// SHEAR HEIGHT/WIDTH
transform.shear(shear_x, shear_y);
transformed = true;
}

// Debug output
ZmqLogger::Instance()->AppendDebugMethod("Timeline::add_layer (Transform: Composite Image Layer: Prepare)", "source_frame->number", source_frame->number, "new_frame->GetImage()->width()", new_frame->GetImage()->width(), "transformed", transformed);

Expand Down