|
@@ -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;
|
|
|
Color color;
|
|
@@ -49,6 +55,8 @@ public:
|
|
|
private:
|
|
|
Vector<Point> points;
|
|
|
bool is_sorted;
|
|
|
+ InterpolationMode interpolation_mode = GRADIENT_INTERPOLATE_LINEAR;
|
|
|
+
|
|
|
_FORCE_INLINE_ void _update_sorting() {
|
|
|
if (!is_sorted) {
|
|
|
points.sort();
|
|
@@ -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.empty()) {
|
|
|
return Color(0, 0, 0, 1);
|
|
@@ -124,10 +139,44 @@ public:
|
|
|
}
|
|
|
const Point &pointFirst = points[first];
|
|
|
const Point &pointSecond = points[second];
|
|
|
- return pointFirst.color.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset));
|
|
|
+
|
|
|
+ switch (interpolation_mode) {
|
|
|
+ case GRADIENT_INTERPOLATE_LINEAR: {
|
|
|
+ return pointFirst.color.linear_interpolate(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.linear_interpolate(pointSecond.color, (p_offset - pointFirst.offset) / (pointSecond.offset - pointFirst.offset));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int get_points_count() const;
|
|
|
};
|
|
|
|
|
|
+VARIANT_ENUM_CAST(Gradient::InterpolationMode);
|
|
|
+
|
|
|
#endif // GRADIENT_H
|