diff options
author | Yuri Roubinsky <chaosus89@gmail.com> | 2021-11-08 22:32:25 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-08 22:32:25 +0300 |
commit | 38c698c4854bd42de1e88c61652ae09ec62bdd87 (patch) | |
tree | b86b2648a5c170da124a2c54d7de56be96cdd6e4 /scene/resources | |
parent | 236fd3305b90b72c7a345bef6d4ed3023222d27f (diff) | |
parent | ed0337c0b9f923d0fc3594916824549a43960043 (diff) |
Merge pull request #53321 from Geometror/gradient-improvements
Diffstat (limited to 'scene/resources')
-rw-r--r-- | scene/resources/gradient.cpp | 30 | ||||
-rw-r--r-- | scene/resources/gradient.h | 57 |
2 files changed, 83 insertions, 4 deletions
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index 7b9b942142..4559b4ce0a 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -51,6 +51,8 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); + ClassDB::bind_method(D_METHOD("reverse"), &Gradient::reverse); + ClassDB::bind_method(D_METHOD("set_color", "point", "color"), &Gradient::set_color); ClassDB::bind_method(D_METHOD("get_color", "point"), &Gradient::get_color); @@ -64,8 +66,18 @@ void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("set_colors", "colors"), &Gradient::set_colors); ClassDB::bind_method(D_METHOD("get_colors"), &Gradient::get_colors); + ClassDB::bind_method(D_METHOD("set_interpolation_mode", "interpolation_mode"), &Gradient::set_interpolation_mode); + ClassDB::bind_method(D_METHOD("get_interpolation_mode"), &Gradient::get_interpolation_mode); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "interpolation_mode", PROPERTY_HINT_ENUM, "Linear,Constant,Cubic"), "set_interpolation_mode", "get_interpolation_mode"); + + ADD_GROUP("Raw data", ""); ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "offsets"), "set_offsets", "get_offsets"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "colors"), "set_colors", "get_colors"); + + BIND_ENUM_CONSTANT(GRADIENT_INTERPOLATE_LINEAR); + BIND_ENUM_CONSTANT(GRADIENT_INTERPOLATE_CONSTANT); + BIND_ENUM_CONSTANT(GRADIENT_INTERPOLATE_CUBIC); } Vector<float> Gradient::get_offsets() const { @@ -86,6 +98,15 @@ Vector<Color> Gradient::get_colors() const { return colors; } +void Gradient::set_interpolation_mode(Gradient::InterpolationMode p_interp_mode) { + interpolation_mode = p_interp_mode; + emit_signal(CoreStringNames::get_singleton()->changed); +} + +Gradient::InterpolationMode Gradient::get_interpolation_mode() { + return interpolation_mode; +} + void Gradient::set_offsets(const Vector<float> &p_offsets) { points.resize(p_offsets.size()); for (int i = 0; i < points.size(); i++) { @@ -127,6 +148,15 @@ void Gradient::remove_point(int p_index) { emit_signal(CoreStringNames::get_singleton()->changed); } +void Gradient::reverse() { + for (int i = 0; i < points.size(); i++) { + points.write[i].offset = 1.0 - points[i].offset; + } + + _update_sorting(); + emit_signal(CoreStringNames::get_singleton()->changed); +} + void Gradient::set_points(Vector<Gradient::Point> &p_points) { points = p_points; is_sorted = false; diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index cf5b179c45..eb438d0bba 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -38,6 +38,12 @@ class Gradient : public Resource { OBJ_SAVE_TYPE(Gradient); public: + enum InterpolationMode { + GRADIENT_INTERPOLATE_LINEAR, + GRADIENT_INTERPOLATE_CONSTANT, + GRADIENT_INTERPOLATE_CUBIC, + }; + struct Point { float offset = 0.0; Color color; @@ -49,6 +55,8 @@ public: private: Vector<Point> points; bool is_sorted = true; + InterpolationMode interpolation_mode = GRADIENT_INTERPOLATE_LINEAR; + _FORCE_INLINE_ void _update_sorting() { if (!is_sorted) { points.sort(); @@ -65,9 +73,9 @@ public: void add_point(float p_offset, const Color &p_color); void remove_point(int p_index); - void set_points(Vector<Point> &p_points); Vector<Point> &get_points(); + void reverse(); void set_offset(int pos, const float offset); float get_offset(int pos); @@ -81,6 +89,13 @@ public: void set_colors(const Vector<Color> &p_colors); Vector<Color> get_colors() const; + void set_interpolation_mode(InterpolationMode p_interp_mode); + InterpolationMode get_interpolation_mode(); + + _FORCE_INLINE_ float cubic_interpolate(float p0, float p1, float p2, float p3, float x) { + return p1 + 0.5 * x * (p2 - p0 + x * (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3 + x * (3.0 * (p1 - p2) + p3 - p0))); + } + _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { if (points.is_empty()) { return Color(0, 0, 0, 1); @@ -88,7 +103,7 @@ public: _update_sorting(); - //binary search + // Binary search. int low = 0; int high = points.size() - 1; int middle = 0; @@ -111,7 +126,7 @@ public: } } - //return interpolated value + // Return interpolated value. if (points[middle].offset > p_offset) { middle--; } @@ -125,10 +140,44 @@ public: } const Point &pointFirst = points[first]; const Point &pointSecond = points[second]; - return pointFirst.color.lerp(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); + + switch (interpolation_mode) { + case GRADIENT_INTERPOLATE_LINEAR: { + return pointFirst.color.lerp(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); + } break; + case GRADIENT_INTERPOLATE_CONSTANT: { + return pointFirst.color; + } break; + case GRADIENT_INTERPOLATE_CUBIC: { + int p0 = first - 1; + int p3 = second + 1; + if (p3 >= points.size()) { + p3 = second; + } + if (p0 < 0) { + p0 = first; + } + const Point &pointP0 = points[p0]; + const Point &pointP3 = points[p3]; + + float x = (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset); + float r = cubic_interpolate(pointP0.color.r, pointFirst.color.r, pointSecond.color.r, pointP3.color.r, x); + float g = cubic_interpolate(pointP0.color.g, pointFirst.color.g, pointSecond.color.g, pointP3.color.g, x); + float b = cubic_interpolate(pointP0.color.b, pointFirst.color.b, pointSecond.color.b, pointP3.color.b, x); + float a = cubic_interpolate(pointP0.color.a, pointFirst.color.a, pointSecond.color.a, pointP3.color.a, x); + + return Color(r, g, b, a); + } break; + default: { + // Fallback to linear interpolation. + return pointFirst.color.lerp(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset)); + } + } } int get_points_count() const; }; +VARIANT_ENUM_CAST(Gradient::InterpolationMode); + #endif // GRADIENT_H |