diff --git a/include/ClipBase.h b/include/ClipBase.h index f3e38c85..8a4e2763 100644 --- a/include/ClipBase.h +++ b/include/ClipBase.h @@ -37,6 +37,7 @@ #include #include "Exceptions.h" #include "Point.h" +#include "KeyFrame.h" #include "Json.h" using namespace std; @@ -61,7 +62,7 @@ namespace openshot { int max_height; ///< The maximium image height needed by this clip (used for optimizations) /// Generate JSON for a property - Json::Value add_property_json(string name, float value, string type, string memo, bool contains_point, int number_of_points, float min_value, float max_value, InterpolationType intepolation, int closest_point_x, bool readonly); + Json::Value add_property_json(string name, float value, string type, string memo, Keyframe* keyframe, float min_value, float max_value, bool readonly, long int requested_frame); /// Generate JSON choice for a property (dropdown properties) Json::Value add_property_choice_json(string name, int value, int selected_value); diff --git a/include/KeyFrame.h b/include/KeyFrame.h index 8a3fcfd5..6ee68c31 100644 --- a/include/KeyFrame.h +++ b/include/KeyFrame.h @@ -91,7 +91,6 @@ namespace openshot { public: vector Points; ///< Vector of all Points vector Values; ///< Vector of all Values (i.e. the processed coordinates from the curve) - float Auto_Handle_Percentage; ///< Percentage the left and right handles should be adjusted to, to create a smooth curve /// Default constructor for the Keyframe class Keyframe(); @@ -102,7 +101,7 @@ namespace openshot { /// Add a new point on the key-frame. Each point has a primary coordinate, a left handle, and a right handle. void AddPoint(Point p); - /// Add a new point on the key-frame, with some defaults set (BEZIER, AUTO Handles, etc...) + /// Add a new point on the key-frame, with some defaults set (BEZIER) void AddPoint(float x, float y); /// Add a new point on the key-frame, with a specific interpolation type @@ -111,9 +110,6 @@ namespace openshot { /// Does this keyframe contain a specific point bool Contains(Point p); - /// Set the handles, used for smooth curves. The handles are based on the surrounding points. - void SetHandles(Point current); - /// Flip all the points in this openshot::Keyframe (useful for reversing an effect or transition, etc...) void FlipPoints(); @@ -138,9 +134,16 @@ namespace openshot { /// Get a point at a specific index Point& GetPoint(long int index) throw(OutOfBoundsPoint); - /// Get current point (or closest point) from the X coordinate (i.e. the frame number) + /// Get current point (or closest point to the right) from the X coordinate (i.e. the frame number) Point GetClosestPoint(Point p); + /// Get current point (or closest point) from the X coordinate (i.e. the frame number) + /// Either use the closest left point, or right point + Point GetClosestPoint(Point p, bool useLeft); + + /// Get previous point ( + Point GetPreviousPoint(Point p); + /// Get max point (by Y coordinate) Point GetMaxPoint(); diff --git a/include/Point.h b/include/Point.h index f5fb7296..ffa0d6d4 100644 --- a/include/Point.h +++ b/include/Point.h @@ -81,8 +81,8 @@ namespace openshot class Point { public: Coordinate co; ///< This is the primary coordinate - Coordinate handle_left; ///< This is the left handle coordinate - Coordinate handle_right; ///< This is the right handle coordinate + Coordinate handle_left; ///< This is the left handle coordinate (in percentages from 0 to 1) + Coordinate handle_right; ///< This is the right handle coordinate (in percentages from 0 to 1) InterpolationType interpolation; ///< This is the interpolation mode HandleType handle_type; ///< This is the handle mode @@ -98,21 +98,24 @@ namespace openshot /// Constructor which also creates a Point and sets the X,Y, and interpolation of the Point. Point(float x, float y, InterpolationType interpolation); - // Constructor which takes a coordinate + /// Constructor which takes a coordinate Point(Coordinate co); - // Constructor which takes a coordinate and interpolation mode + /// Constructor which takes a coordinate and interpolation mode Point(Coordinate co, InterpolationType interpolation); - // Constructor which takes a coordinate, interpolation mode, and handle type + /// Constructor which takes a coordinate, interpolation mode, and handle type Point(Coordinate co, InterpolationType interpolation, HandleType handle_type); - /** - * Set the left and right handles to the same Y coordinate as the primary - * coordinate, but offset the X value by a given amount. This is typically used - * to smooth the curve (if BEZIER interpolation mode is used) - */ - void Initialize_Handles(float Offset = 0.0f); + /// Set the left and right handles to a percent of the primary coordinate (0 to 1) + /// Defaults to a smooth curve (Ease in and out) + void Initialize_Handles(); + + /// Set the left handle to a percent of the primary coordinate (0 to 1) + void Initialize_LeftHandle(float x, float y); + + /// Set the right handle to a percent of the primary coordinate (0 to 1) + void Initialize_RightHandle(float x, float y); /// Get and Set JSON methods string Json(); ///< Generate JSON string of this object diff --git a/src/Clip.cpp b/src/Clip.cpp index 8d2ac24d..a254199e 100644 --- a/src/Clip.cpp +++ b/src/Clip.cpp @@ -659,22 +659,19 @@ string Clip::Json() { // Get all properties for a specific frame string Clip::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); - root["gravity"] = add_property_json("Gravity", gravity, "int", "", false, 0, 0, 8, CONSTANT, -1, false); - root["scale"] = add_property_json("Scale", scale, "int", "", false, 0, 0, 3, CONSTANT, -1, false); - root["anchor"] = add_property_json("Anchor", anchor, "int", "", false, 0, 0, 1, CONSTANT, -1, false); - root["handles"] = add_property_json("Handles", handles, "int", "", false, 0, 0, 1, CONSTANT, -1, false); - root["waveform"] = add_property_json("Waveform", waveform, "int", "", false, 0, 0, 1, CONSTANT, -1, false); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); + root["gravity"] = add_property_json("Gravity", gravity, "int", "", NULL, 0, 8, false, requested_frame); + root["scale"] = add_property_json("Scale", scale, "int", "", NULL, 0, 3, false, requested_frame); + root["anchor"] = add_property_json("Anchor", anchor, "int", "", NULL, 0, 1, false, requested_frame); + root["handles"] = add_property_json("Handles", handles, "int", "", NULL, 0, 1, false, requested_frame); + root["waveform"] = add_property_json("Waveform", waveform, "int", "", NULL, 0, 1, false, requested_frame); // Add gravity choices (dropdown style) root["gravity"]["choices"].append(add_property_choice_json("Top Left", GRAVITY_TOP_LEFT, gravity)); @@ -706,25 +703,25 @@ string Clip::PropertiesJSON(long int requested_frame) { root["waveform"]["choices"].append(add_property_choice_json("No", false, waveform)); // Keyframes - root["location_x"] = add_property_json("Location X", location_x.GetValue(requested_frame), "float", "", location_x.Contains(requested_point), location_x.GetCount(), -1.0, 1.0, location_x.GetClosestPoint(requested_point).interpolation, location_x.GetClosestPoint(requested_point).co.X, false); - root["location_y"] = add_property_json("Location Y", location_y.GetValue(requested_frame), "float", "", location_y.Contains(requested_point), location_y.GetCount(), -1.0, 1.0, location_y.GetClosestPoint(requested_point).interpolation, location_y.GetClosestPoint(requested_point).co.X, false); - root["scale_x"] = add_property_json("Scale X", scale_x.GetValue(requested_frame), "float", "", scale_x.Contains(requested_point), scale_x.GetCount(), 0.0, 1.0, scale_x.GetClosestPoint(requested_point).interpolation, scale_x.GetClosestPoint(requested_point).co.X, false); - root["scale_y"] = add_property_json("Scale Y", scale_y.GetValue(requested_frame), "float", "", scale_y.Contains(requested_point), scale_y.GetCount(), 0.0, 1.0, scale_y.GetClosestPoint(requested_point).interpolation, scale_y.GetClosestPoint(requested_point).co.X, false); - root["alpha"] = add_property_json("Alpha", alpha.GetValue(requested_frame), "float", "", alpha.Contains(requested_point), alpha.GetCount(), 0.0, 1.0, alpha.GetClosestPoint(requested_point).interpolation, alpha.GetClosestPoint(requested_point).co.X, false); - root["shear_x"] = add_property_json("Shear X", shear_x.GetValue(requested_frame), "float", "", shear_x.Contains(requested_point), shear_x.GetCount(), -1.0, 1.0, shear_x.GetClosestPoint(requested_point).interpolation, shear_x.GetClosestPoint(requested_point).co.X, false); - root["shear_y"] = add_property_json("Shear Y", shear_y.GetValue(requested_frame), "float", "", shear_y.Contains(requested_point), shear_y.GetCount(), -1.0, 1.0, shear_y.GetClosestPoint(requested_point).interpolation, shear_y.GetClosestPoint(requested_point).co.X, false); - root["rotation"] = add_property_json("Rotation", rotation.GetValue(requested_frame), "float", "", rotation.Contains(requested_point), rotation.GetCount(), -360, 360, rotation.GetClosestPoint(requested_point).interpolation, rotation.GetClosestPoint(requested_point).co.X, false); - root["volume"] = add_property_json("Volume", volume.GetValue(requested_frame), "float", "", volume.Contains(requested_point), volume.GetCount(), 0.0, 1.0, volume.GetClosestPoint(requested_point).interpolation, volume.GetClosestPoint(requested_point).co.X, false); - root["time"] = add_property_json("Time", time.GetValue(requested_frame), "float", "", time.Contains(requested_point), time.GetCount(), 0.0, 30 * 60 * 60 * 48, time.GetClosestPoint(requested_point).interpolation, time.GetClosestPoint(requested_point).co.X, false); - root["channel_filter"] = add_property_json("Channel Filter", channel_filter.GetValue(requested_frame), "int", "", channel_filter.Contains(requested_point), channel_filter.GetCount(), -1, 10, channel_filter.GetClosestPoint(requested_point).interpolation, channel_filter.GetClosestPoint(requested_point).co.X, false); - root["channel_mapping"] = add_property_json("Channel Mapping", channel_mapping.GetValue(requested_frame), "int", "", channel_mapping.Contains(requested_point), channel_mapping.GetCount(), -1, 10, channel_mapping.GetClosestPoint(requested_point).interpolation, channel_mapping.GetClosestPoint(requested_point).co.X, false); - root["has_audio"] = add_property_json("Enable Audio", has_audio.GetValue(requested_frame), "int", "", has_audio.Contains(requested_point), has_audio.GetCount(), -1, 1.0, has_audio.GetClosestPoint(requested_point).interpolation, has_audio.GetClosestPoint(requested_point).co.X, false); - root["has_video"] = add_property_json("Enable Video", has_video.GetValue(requested_frame), "int", "", has_video.Contains(requested_point), has_video.GetCount(), -1, 1.0, has_video.GetClosestPoint(requested_point).interpolation, has_video.GetClosestPoint(requested_point).co.X, false); + root["location_x"] = add_property_json("Location X", location_x.GetValue(requested_frame), "float", "", &location_x, -1.0, 1.0, false, requested_frame); + root["location_y"] = add_property_json("Location Y", location_y.GetValue(requested_frame), "float", "", &location_y, -1.0, 1.0, false, requested_frame); + root["scale_x"] = add_property_json("Scale X", scale_x.GetValue(requested_frame), "float", "", &scale_x, 0.0, 1.0, false, requested_frame); + root["scale_y"] = add_property_json("Scale Y", scale_y.GetValue(requested_frame), "float", "", &scale_y, 0.0, 1.0, false, requested_frame); + root["alpha"] = add_property_json("Alpha", alpha.GetValue(requested_frame), "float", "", &alpha, 0.0, 1.0, false, requested_frame); + 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["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); + root["channel_mapping"] = add_property_json("Channel Mapping", channel_mapping.GetValue(requested_frame), "int", "", &channel_mapping, -1, 10, false, requested_frame); + root["has_audio"] = add_property_json("Enable Audio", has_audio.GetValue(requested_frame), "int", "", &has_audio, -1, 1.0, false, requested_frame); + root["has_video"] = add_property_json("Enable Video", has_video.GetValue(requested_frame), "int", "", &has_video, -1, 1.0, false, requested_frame); - root["wave_color"] = add_property_json("Wave Color", 0.0, "color", "", wave_color.red.Contains(requested_point), wave_color.red.GetCount(), 0, 255, wave_color.red.GetClosestPoint(requested_point).interpolation, wave_color.red.GetClosestPoint(requested_point).co.X, false); - root["wave_color"]["red"] = add_property_json("Red", wave_color.red.GetValue(requested_frame), "float", "", wave_color.red.Contains(requested_point), wave_color.red.GetCount(), 0, 255, wave_color.red.GetClosestPoint(requested_point).interpolation, wave_color.red.GetClosestPoint(requested_point).co.X, false); - root["wave_color"]["blue"] = add_property_json("Blue", wave_color.blue.GetValue(requested_frame), "float", "", wave_color.blue.Contains(requested_point), wave_color.blue.GetCount(), 0, 255, wave_color.blue.GetClosestPoint(requested_point).interpolation, wave_color.blue.GetClosestPoint(requested_point).co.X, false); - root["wave_color"]["green"] = add_property_json("Green", wave_color.green.GetValue(requested_frame), "float", "", wave_color.green.Contains(requested_point), wave_color.green.GetCount(), 0, 255, wave_color.green.GetClosestPoint(requested_point).interpolation, wave_color.green.GetClosestPoint(requested_point).co.X, false); + root["wave_color"] = add_property_json("Wave Color", 0.0, "color", "", &wave_color.red, 0, 255, false, requested_frame); + root["wave_color"]["red"] = add_property_json("Red", wave_color.red.GetValue(requested_frame), "float", "", &wave_color.red, 0, 255, false, requested_frame); + root["wave_color"]["blue"] = add_property_json("Blue", wave_color.blue.GetValue(requested_frame), "float", "", &wave_color.blue, 0, 255, false, requested_frame); + root["wave_color"]["green"] = add_property_json("Green", wave_color.green.GetValue(requested_frame), "float", "", &wave_color.green, 0, 255, false, requested_frame); // Return formatted string diff --git a/src/ClipBase.cpp b/src/ClipBase.cpp index 66363284..a5c24342 100644 --- a/src/ClipBase.cpp +++ b/src/ClipBase.cpp @@ -62,7 +62,10 @@ void ClipBase::SetJsonValue(Json::Value root) { } // Generate JSON for a property -Json::Value ClipBase::add_property_json(string name, float value, string type, string memo, bool contains_point, int number_of_points, float min_value, float max_value, InterpolationType intepolation, int closest_point_x, bool readonly) { +Json::Value ClipBase::add_property_json(string name, float value, string type, string memo, Keyframe* keyframe, float min_value, float max_value, bool readonly, long int requested_frame) { + + // Requested Point + Point requested_point(requested_frame, requested_frame); // Create JSON Object Json::Value prop = Json::Value(Json::objectValue); @@ -72,11 +75,23 @@ Json::Value ClipBase::add_property_json(string name, float value, string type, s prop["type"] = type; prop["min"] = min_value; prop["max"] = max_value; - prop["keyframe"] = contains_point; - prop["points"] = number_of_points; + if (keyframe) { + prop["keyframe"] = keyframe->Contains(requested_point); + prop["points"] = int(keyframe->GetCount()); + Point closest_point = keyframe->GetClosestPoint(requested_point); + prop["interpolation"] = closest_point.interpolation; + prop["closest_point_x"] = closest_point.co.X; + prop["previous_point_x"] = keyframe->GetPreviousPoint(closest_point).co.X; + } + else { + prop["keyframe"] = false; + prop["points"] = 0; + prop["interpolation"] = CONSTANT; + prop["closest_point_x"] = -1; + prop["previous_point_x"] = -1; + } + prop["readonly"] = readonly; - prop["interpolation"] = intepolation; - prop["closest_point_x"] = closest_point_x; prop["choices"] = Json::Value(Json::arrayValue); // return JsonValue diff --git a/src/KeyFrame.cpp b/src/KeyFrame.cpp index 4bb4b062..6c0c8178 100644 --- a/src/KeyFrame.cpp +++ b/src/KeyFrame.cpp @@ -53,7 +53,7 @@ void Keyframe::ReorderPoints() { } // Constructor which sets the default point & coordinate at X=0 -Keyframe::Keyframe(float value) : Auto_Handle_Percentage(0.4f), needs_update(true) { +Keyframe::Keyframe(float value) : needs_update(true) { // Init the factorial table, needed by bezier curves CreateFactorialTable(); @@ -62,7 +62,7 @@ Keyframe::Keyframe(float value) : Auto_Handle_Percentage(0.4f), needs_update(tru } // Keyframe constructor -Keyframe::Keyframe() : Auto_Handle_Percentage(0.4f), needs_update(true) { +Keyframe::Keyframe() : needs_update(true) { // Init the factorial table, needed by bezier curves CreateFactorialTable(); } @@ -84,12 +84,9 @@ void Keyframe::AddPoint(Point p) { // Sort / Re-order points based on X coordinate ReorderPoints(); - - // Set Handles (used for smooth curves). - SetHandles(p); } -// Add a new point on the key-frame, with some defaults set (BEZIER, AUTO Handles, etc...) +// Add a new point on the key-frame, with some defaults set (BEZIER) void Keyframe::AddPoint(float x, float y) { // Create a point @@ -109,50 +106,6 @@ void Keyframe::AddPoint(float x, float y, InterpolationType interpolate) AddPoint(new_point); } -// Set the handles, used for smooth curves. The handles are based -// on the surrounding points. -void Keyframe::SetHandles(Point current) -{ - // mark as dirty - needs_update = true; - - // Lookup the index of this point - long int index = FindIndex(current); - Point *Current_Point = &Points[index]; - - // Find the previous point and next points (if any) - Point *Previous_Point = NULL; - Point *Next_Point = NULL; - float Previous_X_diff = 0.0f; - float Next_X_diff = 0.0f; - - // If not the 1st point - if (index > 0) - Previous_Point = &Points[index - 1]; - - // If not the last point - if (index < (Points.size() - 1)) - Next_Point = &Points[index + 1]; - - // Update the previous point's right handle - if (Previous_Point) - Previous_X_diff = (Current_Point->co.X - Previous_Point->co.X) * Auto_Handle_Percentage; // Use the keyframe handle percentage to size the handle - if (Previous_Point && Previous_Point->handle_type == AUTO) - Previous_Point->handle_right.X = Previous_Point->co.X + Previous_X_diff; - // Update the current point's left handle - if (Current_Point->handle_type == AUTO) - Current_Point->handle_left.X = Current_Point->co.X - Previous_X_diff; - - // Update the next point's left handle - if (Next_Point) - Next_X_diff = (Next_Point->co.X - Current_Point->co.X) * Auto_Handle_Percentage; // Use the keyframe handle percentage to size the handle - if (Next_Point && Next_Point->handle_type == AUTO) - Next_Point->handle_left.X = Next_Point->co.X - Next_X_diff; - // Update the next point's right handle - if (Current_Point->handle_type == AUTO) - Current_Point->handle_right.X = Current_Point->co.X + Next_X_diff; -} - // Get the index of a point by matching a coordinate long int Keyframe::FindIndex(Point p) throw(OutOfBoundsPoint) { // loop through points, and find a matching coordinate @@ -190,7 +143,7 @@ bool Keyframe::Contains(Point p) { } // Get current point (or closest point) from the X coordinate (i.e. the frame number) -Point Keyframe::GetClosestPoint(Point p) { +Point Keyframe::GetClosestPoint(Point p, bool useLeft) { Point closest(-1, -1); // loop through points, and find a matching coordinate @@ -199,16 +152,22 @@ Point Keyframe::GetClosestPoint(Point p) { Point existing_point = Points[x]; // find a match - if (existing_point.co.X >= p.co.X) { - // New closest point found + if (existing_point.co.X >= p.co.X && !useLeft) { + // New closest point found (to the Right) closest = existing_point; break; + } else if (existing_point.co.X < p.co.X && useLeft) { + // New closest point found (to the Left) + closest = existing_point; + } else if (existing_point.co.X >= p.co.X && useLeft) { + // We've gone past the left point... so break + break; } } // Handle edge cases (if no point was found) if (closest.co.X == -1) { - if (p.co.X < 1 && Points.size() > 0) + if (p.co.X <= 1 && Points.size() > 0) // Assign 1st point closest = Points[0]; else if (Points.size() > 0) @@ -220,6 +179,30 @@ Point Keyframe::GetClosestPoint(Point p) { return closest; } +// Get current point (or closest point to the right) from the X coordinate (i.e. the frame number) +Point Keyframe::GetClosestPoint(Point p) { + return GetClosestPoint(p, false); +} + +// Get previous point (if any) +Point Keyframe::GetPreviousPoint(Point p) { + + // Lookup the index of this point + try { + long int index = FindIndex(p); + + // If not the 1st point + if (index > 0) + return Points[index - 1]; + else + return Points[0]; + + } catch (OutOfBoundsPoint) { + // No previous point + return Point(-1, -1); + } +} + // Get max point (by Y coordinate) Point Keyframe::GetMaxPoint() { Point maxPoint(-1, -1); @@ -399,9 +382,6 @@ void Keyframe::SetJsonValue(Json::Value root) { // Add Point to Keyframe AddPoint(p); } - - if (!root["Auto_Handle_Percentage"].isNull()) - Auto_Handle_Percentage = root["Auto_Handle_Percentage"].asBool(); } // Get the fraction that represents how many times this value is repeated in the curve @@ -709,10 +689,14 @@ void Keyframe::ProcessSegment(int Segment, Point p1, Point p2) { number_of_values++; number_of_values *= 4; // We need a higher resolution curve (4X) + // Diff between points + float X_diff = p2.co.X - p1.co.X; + float Y_diff = p2.co.Y - p1.co.Y; + vector segment_coordinates; segment_coordinates.push_back(p1.co); - segment_coordinates.push_back(p1.handle_right); - segment_coordinates.push_back(p2.handle_left); + segment_coordinates.push_back(Coordinate(p1.co.X + (p1.handle_right.X * X_diff), p1.co.Y + (p1.handle_right.Y * Y_diff))); + segment_coordinates.push_back(Coordinate(p1.co.X + (p2.handle_left.X * X_diff), p1.co.Y + (p2.handle_left.Y * Y_diff))); segment_coordinates.push_back(p2.co); vector raw_coordinates; diff --git a/src/Point.cpp b/src/Point.cpp index 0f0917b8..b4646df8 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -87,10 +87,21 @@ Point::Point(Coordinate co, InterpolationType interpolation, HandleType handle_t Initialize_Handles(); } -void Point::Initialize_Handles(float Offset) { - // initialize left and right handles - handle_left = Coordinate(co.X - Offset, co.Y); - handle_right = Coordinate(co.X + Offset, co.Y); +void Point::Initialize_Handles() { + // initialize left and right handles (in percentages from 0 to 1) + // default to a smooth curve + Initialize_LeftHandle(0.5, 1.0); + Initialize_RightHandle(0.5, 0.0); +} + +void Point::Initialize_LeftHandle(float x, float y) { + // initialize left handle (in percentages from 0 to 1) + handle_left = Coordinate(x, y); +} + +void Point::Initialize_RightHandle(float x, float y) { + // initialize right handle (in percentages from 0 to 1) + handle_right = Coordinate(x, y); } // Generate JSON string of this object diff --git a/src/effects/Blur.cpp b/src/effects/Blur.cpp index 60a5592e..f47cf303 100644 --- a/src/effects/Blur.cpp +++ b/src/effects/Blur.cpp @@ -301,23 +301,20 @@ void Blur::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Blur::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 1000 * 60 * 30, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 1000 * 60 * 30, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 1000 * 60 * 30, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 1000 * 60 * 30, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 1000 * 60 * 30, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 1000 * 60 * 30, true, requested_frame); // Keyframes - root["horizontal_radius"] = add_property_json("Horizontal Radius", horizontal_radius.GetValue(requested_frame), "float", "", horizontal_radius.Contains(requested_point), horizontal_radius.GetCount(), 0, 100, horizontal_radius.GetClosestPoint(requested_point).interpolation, horizontal_radius.GetClosestPoint(requested_point).co.X, false); - root["vertical_radius"] = add_property_json("Vertical Radius", vertical_radius.GetValue(requested_frame), "float", "", vertical_radius.Contains(requested_point), vertical_radius.GetCount(), 0, 100, vertical_radius.GetClosestPoint(requested_point).interpolation, vertical_radius.GetClosestPoint(requested_point).co.X, false); - root["sigma"] = add_property_json("Sigma", sigma.GetValue(requested_frame), "float", "", sigma.Contains(requested_point), sigma.GetCount(), 0, 100, sigma.GetClosestPoint(requested_point).interpolation, sigma.GetClosestPoint(requested_point).co.X, false); - root["iterations"] = add_property_json("Iterations", iterations.GetValue(requested_frame), "float", "", iterations.Contains(requested_point), iterations.GetCount(), 0, 100, iterations.GetClosestPoint(requested_point).interpolation, iterations.GetClosestPoint(requested_point).co.X, false); + root["horizontal_radius"] = add_property_json("Horizontal Radius", horizontal_radius.GetValue(requested_frame), "float", "", &horizontal_radius, 0, 100, false, requested_frame); + root["vertical_radius"] = add_property_json("Vertical Radius", vertical_radius.GetValue(requested_frame), "float", "", &vertical_radius, 0, 100, false, requested_frame); + root["sigma"] = add_property_json("Sigma", sigma.GetValue(requested_frame), "float", "", &sigma, 0, 100, false, requested_frame); + root["iterations"] = add_property_json("Iterations", iterations.GetValue(requested_frame), "float", "", &iterations, 0, 100, false, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/src/effects/Brightness.cpp b/src/effects/Brightness.cpp index 28520a5e..daf9a09a 100644 --- a/src/effects/Brightness.cpp +++ b/src/effects/Brightness.cpp @@ -176,21 +176,18 @@ void Brightness::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Brightness::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); // Keyframes - root["brightness"] = add_property_json("Brightness", brightness.GetValue(requested_frame), "float", "", brightness.Contains(requested_point), brightness.GetCount(), -1.0, 1.0, brightness.GetClosestPoint(requested_point).interpolation, brightness.GetClosestPoint(requested_point).co.X, false); - root["contrast"] = add_property_json("Contrast", contrast.GetValue(requested_frame), "float", "", contrast.Contains(requested_point), contrast.GetCount(), 0.0, 100.0, contrast.GetClosestPoint(requested_point).interpolation, contrast.GetClosestPoint(requested_point).co.X, false); + root["brightness"] = add_property_json("Brightness", brightness.GetValue(requested_frame), "float", "", &brightness, -1.0, 1.0, false, requested_frame); + root["contrast"] = add_property_json("Contrast", contrast.GetValue(requested_frame), "float", "", &contrast, 0.0, 100.0, false, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/src/effects/ChromaKey.cpp b/src/effects/ChromaKey.cpp index 8f354b4c..ae59dfc4 100644 --- a/src/effects/ChromaKey.cpp +++ b/src/effects/ChromaKey.cpp @@ -156,24 +156,21 @@ void ChromaKey::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string ChromaKey::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); // Keyframes - root["color"] = add_property_json("Key Color", 0.0, "color", "", color.red.Contains(requested_point), color.red.GetCount(), 0, 255, color.red.GetClosestPoint(requested_point).interpolation, color.red.GetClosestPoint(requested_point).co.X, false); - root["color"]["red"] = add_property_json("Red", color.red.GetValue(requested_frame), "float", "", color.red.Contains(requested_point), color.red.GetCount(), 0, 255, color.red.GetClosestPoint(requested_point).interpolation, color.red.GetClosestPoint(requested_point).co.X, false); - root["color"]["blue"] = add_property_json("Blue", color.blue.GetValue(requested_frame), "float", "", color.blue.Contains(requested_point), color.blue.GetCount(), 0, 255, color.blue.GetClosestPoint(requested_point).interpolation, color.blue.GetClosestPoint(requested_point).co.X, false); - root["color"]["green"] = add_property_json("Green", color.green.GetValue(requested_frame), "float", "", color.green.Contains(requested_point), color.green.GetCount(), 0, 255, color.green.GetClosestPoint(requested_point).interpolation, color.green.GetClosestPoint(requested_point).co.X, false); - root["fuzz"] = add_property_json("Fuzz", fuzz.GetValue(requested_frame), "float", "", fuzz.Contains(requested_point), fuzz.GetCount(), 0, 25, fuzz.GetClosestPoint(requested_point).interpolation, fuzz.GetClosestPoint(requested_point).co.X, false); + root["color"] = add_property_json("Key Color", 0.0, "color", "", NULL, 0, 255, false, requested_frame); + root["color"]["red"] = add_property_json("Red", color.red.GetValue(requested_frame), "float", "", &color.red, 0, 255, false, requested_frame); + root["color"]["blue"] = add_property_json("Blue", color.blue.GetValue(requested_frame), "float", "", &color.blue, 0, 255, false, requested_frame); + root["color"]["green"] = add_property_json("Green", color.green.GetValue(requested_frame), "float", "", &color.green, 0, 255, false, requested_frame); + root["fuzz"] = add_property_json("Fuzz", fuzz.GetValue(requested_frame), "float", "", &fuzz, 0, 25, false, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/src/effects/Deinterlace.cpp b/src/effects/Deinterlace.cpp index 2ec25a5b..c78b5b3f 100644 --- a/src/effects/Deinterlace.cpp +++ b/src/effects/Deinterlace.cpp @@ -148,18 +148,15 @@ void Deinterlace::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Deinterlace::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); - root["isOdd"] = add_property_json("Is Odd Frame", isOdd, "bool", "", false, 0, 0, 1, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); + root["isOdd"] = add_property_json("Is Odd Frame", isOdd, "bool", "", NULL, 0, 1, true, requested_frame); // Add Is Odd Frame choices (dropdown style) root["isOdd"]["choices"].append(add_property_choice_json("Yes", true, isOdd)); diff --git a/src/effects/Mask.cpp b/src/effects/Mask.cpp index fda3342e..7e316f23 100644 --- a/src/effects/Mask.cpp +++ b/src/effects/Mask.cpp @@ -277,26 +277,23 @@ void Mask::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Mask::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); - root["replace_image"] = add_property_json("Replace Image", replace_image, "int", "", false, 0, 0, 1, CONSTANT, -1, false); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); + root["replace_image"] = add_property_json("Replace Image", replace_image, "int", "", NULL, 0, 1, false, requested_frame); // Add replace_image choices (dropdown style) root["replace_image"]["choices"].append(add_property_choice_json("Yes", true, replace_image)); root["replace_image"]["choices"].append(add_property_choice_json("No", false, replace_image)); // Keyframes - root["brightness"] = add_property_json("Brightness", brightness.GetValue(requested_frame), "float", "", brightness.Contains(requested_point), brightness.GetCount(), -1.0, 1.0, brightness.GetClosestPoint(requested_point).interpolation, brightness.GetClosestPoint(requested_point).co.X, false); - root["contrast"] = add_property_json("Contrast", contrast.GetValue(requested_frame), "float", "", contrast.Contains(requested_point), contrast.GetCount(), 0, 20, contrast.GetClosestPoint(requested_point).interpolation, contrast.GetClosestPoint(requested_point).co.X, false); + root["brightness"] = add_property_json("Brightness", brightness.GetValue(requested_frame), "float", "", &brightness, -1.0, 1.0, false, requested_frame); + root["contrast"] = add_property_json("Contrast", contrast.GetValue(requested_frame), "float", "", &contrast, 0, 20, false, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/src/effects/Negate.cpp b/src/effects/Negate.cpp index 08b6e50f..fa3eae35 100644 --- a/src/effects/Negate.cpp +++ b/src/effects/Negate.cpp @@ -106,17 +106,14 @@ void Negate::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Negate::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/src/effects/Saturation.cpp b/src/effects/Saturation.cpp index b8bd4996..03c487fa 100644 --- a/src/effects/Saturation.cpp +++ b/src/effects/Saturation.cpp @@ -178,20 +178,17 @@ void Saturation::SetJsonValue(Json::Value root) { // Get all properties for a specific frame string Saturation::PropertiesJSON(long int requested_frame) { - // Requested Point - Point requested_point(requested_frame, requested_frame); - // Generate JSON properties list Json::Value root; - root["id"] = add_property_json("ID", 0.0, "string", Id(), false, 0, -1, -1, CONSTANT, -1, true); - root["position"] = add_property_json("Position", Position(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["layer"] = add_property_json("Track", Layer(), "int", "", false, 0, 0, 20, CONSTANT, -1, false); - root["start"] = add_property_json("Start", Start(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["end"] = add_property_json("End", End(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, false); - root["duration"] = add_property_json("Duration", Duration(), "float", "", false, 0, 0, 30 * 60 * 60 * 48, CONSTANT, -1, true); + root["id"] = add_property_json("ID", 0.0, "string", Id(), NULL, -1, -1, true, requested_frame); + root["position"] = add_property_json("Position", Position(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["layer"] = add_property_json("Track", Layer(), "int", "", NULL, 0, 20, false, requested_frame); + root["start"] = add_property_json("Start", Start(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["end"] = add_property_json("End", End(), "float", "", NULL, 0, 30 * 60 * 60 * 48, false, requested_frame); + root["duration"] = add_property_json("Duration", Duration(), "float", "", NULL, 0, 30 * 60 * 60 * 48, true, requested_frame); // Keyframes - root["saturation"] = add_property_json("Saturation", saturation.GetValue(requested_frame), "float", "", saturation.Contains(requested_point), saturation.GetCount(), 0.0, 4.0, saturation.GetClosestPoint(requested_point).interpolation, saturation.GetClosestPoint(requested_point).co.X, false); + root["saturation"] = add_property_json("Saturation", saturation.GetValue(requested_frame), "float", "", &saturation, 0.0, 4.0, false, requested_frame); // Return formatted string return root.toStyledString(); diff --git a/tests/KeyFrame_Tests.cpp b/tests/KeyFrame_Tests.cpp index 0a8739c2..fe96ea5a 100644 --- a/tests/KeyFrame_Tests.cpp +++ b/tests/KeyFrame_Tests.cpp @@ -57,7 +57,6 @@ TEST(Keyframe_AddPoint_With_1_Point) { // Create an empty keyframe Keyframe k1; - k1.Auto_Handle_Percentage = 0.4f; k1.AddPoint(openshot::Point(2,9)); CHECK_CLOSE(2.0f, k1.GetPoint(0).co.X, 0.00001); @@ -69,7 +68,6 @@ TEST(Keyframe_AddPoint_With_2_Points) { // Create an empty keyframe Keyframe k1; - k1.Auto_Handle_Percentage = 0.4f; k1.AddPoint(openshot::Point(2,9)); k1.AddPoint(openshot::Point(5,20)); @@ -83,7 +81,6 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_2_Points) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(50, 4), BEZIER)); @@ -91,9 +88,9 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_2_Points) CHECK_CLOSE(1.0f, kf.GetValue(-1), 0.0001); CHECK_CLOSE(1.0f, kf.GetValue(0), 0.0001); CHECK_CLOSE(1.00023f, kf.GetValue(1), 0.0001); - CHECK_CLOSE(1.18398f, kf.GetValue(9), 0.0001); - CHECK_CLOSE(1.99988f, kf.GetValue(20), 0.0001); - CHECK_CLOSE(3.75424f, kf.GetValue(40), 0.0001); + CHECK_CLOSE(1.14025f, kf.GetValue(9), 0.0001); + CHECK_CLOSE(1.91492f, kf.GetValue(20), 0.0001); + CHECK_CLOSE(3.81602f, kf.GetValue(40), 0.0001); CHECK_CLOSE(4.0f, kf.GetValue(50), 0.0001); // Check the expected number of values CHECK_EQUAL(kf.Values.size(), 51); @@ -103,7 +100,6 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_5_Points_40_Percent_Handle) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(50, 4), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(100, 10), BEZIER)); @@ -114,10 +110,10 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_5_Points_40_Percent_Handle) CHECK_CLOSE(kf.GetValue(-1), 1.0f, 0.0001); CHECK_CLOSE(1.0f, kf.GetValue(0), 0.0001); CHECK_CLOSE(1.00023f, kf.GetValue(1), 0.0001); - CHECK_CLOSE(2.69174f, kf.GetValue(27), 0.0001); - CHECK_CLOSE(7.46386f, kf.GetValue(77), 0.0001); - CHECK_CLOSE(4.22691f, kf.GetValue(127), 0.0001); - CHECK_CLOSE(1.73193f, kf.GetValue(177), 0.0001); + CHECK_CLOSE(2.73656f, kf.GetValue(27), 0.0001); + CHECK_CLOSE(7.55139f, kf.GetValue(77), 0.0001); + CHECK_CLOSE(4.08102f, kf.GetValue(127), 0.0001); + CHECK_CLOSE(1.77569f, kf.GetValue(177), 0.0001); CHECK_CLOSE(3.0f, kf.GetValue(200), 0.0001); // Check the expected number of values CHECK_EQUAL(kf.Values.size(), 201); @@ -127,7 +123,6 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_5_Points_25_Percent_Handle) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.25f; kf.AddPoint(openshot::Point(Coordinate(1, 1), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(50, 4), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(100, 10), BEZIER)); @@ -137,11 +132,11 @@ TEST(Keyframe_GetValue_For_Bezier_Curve_5_Points_25_Percent_Handle) // Spot check values from the curve CHECK_CLOSE(1.0f, kf.GetValue(-1), 0.0001); CHECK_CLOSE(1.0f, kf.GetValue(0), 0.0001); - CHECK_CLOSE(1.0009f, kf.GetValue(1), 0.0001); - CHECK_CLOSE(2.64678f, kf.GetValue(27), 0.0001); - CHECK_CLOSE(7.37597f, kf.GetValue(77), 0.0001); - CHECK_CLOSE(4.37339f, kf.GetValue(127), 0.0001); - CHECK_CLOSE(1.68798f, kf.GetValue(177), 0.0001); + CHECK_CLOSE(1.00023f, kf.GetValue(1), 0.0001); + CHECK_CLOSE(2.73656f, kf.GetValue(27), 0.0001); + CHECK_CLOSE(7.55139f, kf.GetValue(77), 0.0001); + CHECK_CLOSE(4.08102f, kf.GetValue(127), 0.0001); + CHECK_CLOSE(1.77569f, kf.GetValue(177), 0.0001); CHECK_CLOSE(3.0f, kf.GetValue(200), 0.0001); // Check the expected number of values CHECK_EQUAL(kf.Values.size(), 201); @@ -151,7 +146,6 @@ TEST(Keyframe_GetValue_For_Linear_Curve_3_Points) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), LINEAR)); kf.AddPoint(openshot::Point(Coordinate(25, 8), LINEAR)); kf.AddPoint(openshot::Point(Coordinate(50, 2), LINEAR)); @@ -172,7 +166,6 @@ TEST(Keyframe_GetValue_For_Constant_Curve_3_Points) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), CONSTANT)); kf.AddPoint(openshot::Point(Coordinate(25, 8), CONSTANT)); kf.AddPoint(openshot::Point(Coordinate(50, 2), CONSTANT)); @@ -202,26 +195,26 @@ TEST(Keyframe_Check_Direction_and_Repeat_Fractions) CHECK_EQUAL(kf.GetInt(1), 500); CHECK_EQUAL(kf.IsIncreasing(1), false); CHECK_EQUAL(kf.GetRepeatFraction(1).num, 1); - CHECK_EQUAL(kf.GetRepeatFraction(1).den, 10); + CHECK_EQUAL(kf.GetRepeatFraction(1).den, 12); CHECK_EQUAL(kf.GetDelta(1), 500); - CHECK_EQUAL(kf.GetInt(24), 497); + CHECK_EQUAL(kf.GetInt(24), 498); CHECK_EQUAL(kf.IsIncreasing(24), false); - CHECK_EQUAL(kf.GetRepeatFraction(24).num, 2); - CHECK_EQUAL(kf.GetRepeatFraction(24).den, 4); + CHECK_EQUAL(kf.GetRepeatFraction(24).num, 3); + CHECK_EQUAL(kf.GetRepeatFraction(24).den, 6); CHECK_EQUAL(kf.GetDelta(24), 0); - CHECK_EQUAL(kf.GetLong(390), 101); - CHECK_EQUAL(kf.IsIncreasing(390), false); - CHECK_EQUAL(kf.GetRepeatFraction(390).num, 8); - CHECK_EQUAL(kf.GetRepeatFraction(390).den, 8); + CHECK_EQUAL(kf.GetLong(390), 100); + CHECK_EQUAL(kf.IsIncreasing(390), true); + CHECK_EQUAL(kf.GetRepeatFraction(390).num, 3); + CHECK_EQUAL(kf.GetRepeatFraction(390).den, 15); CHECK_EQUAL(kf.GetDelta(390), 0); CHECK_EQUAL(kf.GetLong(391), 100); CHECK_EQUAL(kf.IsIncreasing(391), true); - CHECK_EQUAL(kf.GetRepeatFraction(391).num, 1); - CHECK_EQUAL(kf.GetRepeatFraction(391).den, 12); - CHECK_EQUAL(kf.GetDelta(391), -1); + CHECK_EQUAL(kf.GetRepeatFraction(391).num, 4); + CHECK_EQUAL(kf.GetRepeatFraction(391).den, 15); + CHECK_EQUAL(kf.GetDelta(388), -1); } @@ -233,7 +226,7 @@ TEST(Keyframe_Get_Closest_Point) kf.AddPoint(1000, 1.0); kf.AddPoint(2500, 0.0); - // Spot check values from the curve + // Spot check values from the curve (to the right) CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(900, 900)).co.X, 1000); CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(1, 1)).co.X, 1); CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(5, 5)).co.X, 1000); @@ -242,9 +235,36 @@ TEST(Keyframe_Get_Closest_Point) CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(2500, 2500)).co.X, 2500); CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(3000, 3000)).co.X, 2500); + // Spot check values from the curve (to the left) + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(900, 900), true).co.X, 1); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(1, 1), true).co.X, 1); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(5, 5), true).co.X, 1); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(1000, 1000), true).co.X, 1); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(1001, 1001), true).co.X, 1000); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(2500, 2500), true).co.X, 1000); + CHECK_EQUAL(kf.GetClosestPoint(openshot::Point(3000, 3000), true).co.X, 2500); } +TEST(Keyframe_Get_Previous_Point) +{ + // Create a keyframe curve with 2 points + Keyframe kf; + kf.AddPoint(1, 0.0); + kf.AddPoint(1000, 1.0); + kf.AddPoint(2500, 0.0); + + // Spot check values from the curve + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(900, 900))).co.X, 1); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(1, 1))).co.X, 1); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(5, 5))).co.X, 1); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(1000, 1000))).co.X, 1); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(1001, 1001))).co.X, 1000); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(2500, 2500))).co.X, 1000); + CHECK_EQUAL(kf.GetPreviousPoint(kf.GetClosestPoint(openshot::Point(3000, 3000))).co.X, 1000); + +} + TEST(Keyframe_Get_Max_Point) { // Create a keyframe curve @@ -274,7 +294,6 @@ TEST(Keyframe_Scale_Keyframe) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(25, 8), BEZIER)); kf.AddPoint(openshot::Point(Coordinate(50, 2), BEZIER)); @@ -283,7 +302,7 @@ TEST(Keyframe_Scale_Keyframe) CHECK_CLOSE(1.0f, kf.GetValue(1), 0.01); CHECK_CLOSE(7.99f, kf.GetValue(24), 0.01); CHECK_CLOSE(8.0f, kf.GetValue(25), 0.01); - CHECK_CLOSE(3.84f, kf.GetValue(40), 0.01); + CHECK_CLOSE(3.68f, kf.GetValue(40), 0.01); CHECK_CLOSE(2.0f, kf.GetValue(49), 0.01); CHECK_CLOSE(2.0f, kf.GetValue(50), 0.01); @@ -292,12 +311,12 @@ TEST(Keyframe_Scale_Keyframe) // Spot check values from the curve CHECK_CLOSE(1.0f, kf.GetValue(1), 0.01); - CHECK_CLOSE(6.25f, kf.GetValue(24), 0.01); - CHECK_CLOSE(6.38f, kf.GetValue(25), 0.01); - CHECK_CLOSE(7.80f, kf.GetValue(40), 0.01); + CHECK_CLOSE(4.21f, kf.GetValue(24), 0.01); + CHECK_CLOSE(4.47f, kf.GetValue(25), 0.01); + CHECK_CLOSE(7.57f, kf.GetValue(40), 0.01); CHECK_CLOSE(7.99f, kf.GetValue(49), 0.01); CHECK_CLOSE(8.0f, kf.GetValue(50), 0.01); - CHECK_CLOSE(2.06f, kf.GetValue(90), 0.01); + CHECK_CLOSE(2.35f, kf.GetValue(90), 0.01); CHECK_CLOSE(2.0f, kf.GetValue(100), 0.01); // Resize / Scale the keyframe @@ -307,7 +326,7 @@ TEST(Keyframe_Scale_Keyframe) CHECK_CLOSE(1.0f, kf.GetValue(1), 0.01); CHECK_CLOSE(7.99f, kf.GetValue(24), 0.01); CHECK_CLOSE(8.0f, kf.GetValue(25), 0.01); - CHECK_CLOSE(3.84f, kf.GetValue(40), 0.01); + CHECK_CLOSE(3.68f, kf.GetValue(40), 0.01); CHECK_CLOSE(2.0f, kf.GetValue(49), 0.01); CHECK_CLOSE(2.0f, kf.GetValue(50), 0.01); @@ -317,7 +336,6 @@ TEST(Keyframe_Flip_Keyframe) { // Create a keyframe curve with 2 points Keyframe kf; - kf.Auto_Handle_Percentage = 0.4f; kf.AddPoint(openshot::Point(Coordinate(1, 1), LINEAR)); kf.AddPoint(openshot::Point(Coordinate(25, 8), LINEAR)); kf.AddPoint(openshot::Point(Coordinate(50, 2), LINEAR)); diff --git a/tests/Point_Tests.cpp b/tests/Point_Tests.cpp index 27d1a599..376a69d1 100644 --- a/tests/Point_Tests.cpp +++ b/tests/Point_Tests.cpp @@ -111,27 +111,3 @@ TEST(Point_Constructor_With_Coordinate_And_BEZIER_And_MANUAL_Handle) CHECK_EQUAL(BEZIER, p1.interpolation); CHECK_EQUAL(MANUAL, p1.handle_type); } - -TEST(Point_Set_Handles_Auto_No_Value) -{ - // Create a point with X and Y values - openshot::Point p1(2,8); - p1.Initialize_Handles(); - - CHECK_EQUAL(p1.co.Y, p1.handle_left.Y); - CHECK_EQUAL(p1.co.Y, p1.handle_right.Y); - CHECK_CLOSE(p1.co.X, p1.handle_left.X, 0.000001); - CHECK_CLOSE(p1.co.X, p1.handle_right.X, 0.000001); -} - -TEST(Point_Set_Handles_Auto_With_Values) -{ - // Create a point with X and Y values - openshot::Point p1(2,8); - p1.Initialize_Handles(4.2); - - CHECK_EQUAL(p1.co.Y, p1.handle_left.Y); - CHECK_EQUAL(p1.co.Y, p1.handle_right.Y); - CHECK_CLOSE(p1.co.X - 4.2, p1.handle_left.X, 0.000001); - CHECK_CLOSE(p1.co.X + 4.2, p1.handle_right.X, 0.000001); -}