summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2017-06-27 07:53:52 -0300
committerGitHub <noreply@github.com>2017-06-27 07:53:52 -0300
commit51442988b19d28be551c6ace75c57b50856ed2ad (patch)
tree587884f0efba28fb33431ad993277f70ff066a2c /scene
parent070384c9c9bcf5df5a85a4d786a29dc07ce40084 (diff)
parent69b8f61f253f950f2b72528ca86a44cff0a77b0d (diff)
Merge pull request #9404 from Zylann/curve_improvement
Curve improvement
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/particles.cpp11
-rw-r--r--scene/resources/curve.cpp118
-rw-r--r--scene/resources/curve.h31
-rw-r--r--scene/resources/texture.cpp44
-rw-r--r--scene/resources/texture.h9
5 files changed, 159 insertions, 54 deletions
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index c291aa33ed..edf97bc248 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -1052,16 +1052,11 @@ float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
static void _adjust_curve_range(const Ref<Texture> &p_texture, float p_min, float p_max) {
- Ref<CurveTexture> curve = p_texture;
- if (!curve.is_valid())
+ Ref<CurveTexture> curve_tex = p_texture;
+ if (!curve_tex.is_valid())
return;
- if (curve->get_max() == 1.0) {
- curve->set_max(p_max);
- }
- if (curve->get_min() == 0.0) {
- curve->set_min(p_min);
- }
+ curve_tex->ensure_default_setup(p_min, p_max);
}
void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture> &p_texture) {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 3957923c6a..0cd41f557a 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -380,9 +380,13 @@ Curve2D::Curve2D()
#endif
+const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed";
+
Curve::Curve() {
_bake_resolution = 100;
_baked_cache_dirty = false;
+ _min_value = 0;
+ _max_value = 1;
#ifdef TOOLS_ENABLED
_disable_set_data = false;
#endif
@@ -496,12 +500,38 @@ void Curve::clean_dupes() {
void Curve::set_point_left_tangent(int i, real_t tangent) {
ERR_FAIL_INDEX(i, _points.size());
_points[i].left_tangent = tangent;
+ _points[i].left_mode = TANGENT_FREE;
mark_dirty();
}
void Curve::set_point_right_tangent(int i, real_t tangent) {
ERR_FAIL_INDEX(i, _points.size());
_points[i].right_tangent = tangent;
+ _points[i].right_mode = TANGENT_FREE;
+ mark_dirty();
+}
+
+void Curve::set_point_left_mode(int i, TangentMode p_mode) {
+ ERR_FAIL_INDEX(i, _points.size());
+ _points[i].left_mode = p_mode;
+ if (i > 0) {
+ if (p_mode == TANGENT_LINEAR) {
+ Vector2 v = (_points[i - 1].pos - _points[i].pos).normalized();
+ _points[i].left_tangent = v.y / v.x;
+ }
+ }
+ mark_dirty();
+}
+
+void Curve::set_point_right_mode(int i, TangentMode p_mode) {
+ ERR_FAIL_INDEX(i, _points.size());
+ _points[i].right_mode = p_mode;
+ if (i + 1 < _points.size()) {
+ if (p_mode == TANGENT_LINEAR) {
+ Vector2 v = (_points[i + 1].pos - _points[i].pos).normalized();
+ _points[i].right_tangent = v.y / v.x;
+ }
+ }
mark_dirty();
}
@@ -515,6 +545,16 @@ real_t Curve::get_point_right_tangent(int i) const {
return _points[i].right_tangent;
}
+Curve::TangentMode Curve::get_point_left_mode(int i) const {
+ ERR_FAIL_INDEX_V(i, _points.size(), TANGENT_FREE);
+ return _points[i].left_mode;
+}
+
+Curve::TangentMode Curve::get_point_right_mode(int i) const {
+ ERR_FAIL_INDEX_V(i, _points.size(), TANGENT_FREE);
+ return _points[i].right_mode;
+}
+
void Curve::remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, _points.size());
_points.remove(p_index);
@@ -529,6 +569,7 @@ void Curve::clear_points() {
void Curve::set_point_value(int p_index, real_t pos) {
ERR_FAIL_INDEX(p_index, _points.size());
_points[p_index].pos.y = pos;
+ update_auto_tangents(p_index);
mark_dirty();
}
@@ -539,6 +580,11 @@ int Curve::set_point_offset(int p_index, float offset) {
int i = add_point(Vector2(offset, p.pos.y));
_points[i].left_tangent = p.left_tangent;
_points[i].right_tangent = p.right_tangent;
+ _points[i].left_mode = p.left_mode;
+ _points[i].right_mode = p.right_mode;
+ if (p_index != i)
+ update_auto_tangents(p_index);
+ update_auto_tangents(i);
return i;
}
@@ -547,6 +593,53 @@ Vector2 Curve::get_point_pos(int p_index) const {
return _points[p_index].pos;
}
+void Curve::update_auto_tangents(int i) {
+
+ Point &p = _points[i];
+
+ if (i > 0) {
+ if (p.left_mode == TANGENT_LINEAR) {
+ Vector2 v = (_points[i - 1].pos - p.pos).normalized();
+ p.left_tangent = v.y / v.x;
+ }
+ if (_points[i - 1].right_mode == TANGENT_LINEAR) {
+ Vector2 v = (_points[i - 1].pos - p.pos).normalized();
+ _points[i - 1].right_tangent = v.y / v.x;
+ }
+ }
+
+ if (i + 1 < _points.size()) {
+ if (p.right_mode == TANGENT_LINEAR && i + 1 < _points.size()) {
+ Vector2 v = (_points[i + 1].pos - p.pos).normalized();
+ p.right_tangent = v.y / v.x;
+ }
+ if (_points[i + 1].left_mode == TANGENT_LINEAR) {
+ Vector2 v = (_points[i + 1].pos - p.pos).normalized();
+ _points[i + 1].left_tangent = v.y / v.x;
+ }
+ }
+}
+
+#define MIN_Y_RANGE 0.01
+
+void Curve::set_min_value(float p_min) {
+ if (p_min > _max_value - MIN_Y_RANGE)
+ _min_value = _max_value - MIN_Y_RANGE;
+ else
+ _min_value = p_min;
+ // Note: min and max are indicative values,
+ // it's still possible that existing points are out of range at this point.
+ emit_signal(SIGNAL_RANGE_CHANGED);
+}
+
+void Curve::set_max_value(float p_max) {
+ if (p_max < _min_value + MIN_Y_RANGE)
+ _max_value = _min_value + MIN_Y_RANGE;
+ else
+ _max_value = p_max;
+ emit_signal(SIGNAL_RANGE_CHANGED);
+}
+
real_t Curve::interpolate(real_t offset) const {
if (_points.size() == 0)
return 0;
@@ -636,6 +729,14 @@ void Curve::set_data(Array input) {
ERR_FAIL_COND(input[i].get_type() != Variant::VECTOR2);
ERR_FAIL_COND(input[i + 1].get_type() != Variant::REAL);
ERR_FAIL_COND(input[i + 2].get_type() != Variant::REAL);
+
+ ERR_FAIL_COND(input[i + 3].get_type() != Variant::INT);
+ int left_mode = input[i + 3];
+ ERR_FAIL_COND(left_mode < 0 || left_mode >= TANGENT_MODE_COUNT);
+
+ ERR_FAIL_COND(input[i + 4].get_type() != Variant::INT);
+ int right_mode = input[i + 4];
+ ERR_FAIL_COND(right_mode < 0 || right_mode >= TANGENT_MODE_COUNT);
}
_points.resize(input.size() / 3);
@@ -648,6 +749,11 @@ void Curve::set_data(Array input) {
p.pos = input[i];
p.left_tangent = input[i + 1];
p.right_tangent = input[i + 2];
+ // TODO For some reason the compiler won't convert from Variant to enum
+ int left_mode = input[i + 3];
+ int right_mode = input[i + 4];
+ p.left_mode = (TangentMode)left_mode;
+ p.right_mode = (TangentMode)right_mode;
}
mark_dirty();
@@ -726,8 +832,16 @@ void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("interpolate_baked", "offset"), &Curve::interpolate_baked);
ClassDB::bind_method(D_METHOD("get_point_left_tangent", "index"), &Curve::get_point_left_tangent);
ClassDB::bind_method(D_METHOD("get_point_right_tangent", "index"), &Curve::get_point_left_tangent);
+ ClassDB::bind_method(D_METHOD("get_point_left_mode", "index"), &Curve::get_point_left_mode);
+ ClassDB::bind_method(D_METHOD("get_point_right_mode", "index"), &Curve::get_point_left_mode);
ClassDB::bind_method(D_METHOD("set_point_left_tangent", "index", "tangent"), &Curve::set_point_left_tangent);
ClassDB::bind_method(D_METHOD("set_point_right_tangent", "index", "tangent"), &Curve::set_point_left_tangent);
+ ClassDB::bind_method(D_METHOD("set_point_left_mode", "index", "mode"), &Curve::set_point_left_mode);
+ ClassDB::bind_method(D_METHOD("set_point_right_mode", "index", "mode"), &Curve::set_point_left_mode);
+ ClassDB::bind_method(D_METHOD("get_min_value"), &Curve::get_min_value);
+ ClassDB::bind_method(D_METHOD("set_min_value", "min"), &Curve::set_min_value);
+ ClassDB::bind_method(D_METHOD("get_max_value"), &Curve::get_max_value);
+ ClassDB::bind_method(D_METHOD("set_max_value", "max"), &Curve::set_max_value);
ClassDB::bind_method(D_METHOD("clean_dupes"), &Curve::clean_dupes);
ClassDB::bind_method(D_METHOD("bake"), &Curve::bake);
ClassDB::bind_method(D_METHOD("get_bake_resolution"), &Curve::get_bake_resolution);
@@ -735,8 +849,12 @@ void Curve::_bind_methods() {
ClassDB::bind_method(D_METHOD("_get_data"), &Curve::get_data);
ClassDB::bind_method(D_METHOD("_set_data", "data"), &Curve::set_data);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_min_value", "get_min_value");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+
+ ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
}
int Curve2D::get_point_count() const {
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 63b9a07f07..d45f9e202f 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -89,24 +89,38 @@ public:
static const int MIN_X = 0.f;
static const int MAX_X = 1.f;
+ static const char *SIGNAL_RANGE_CHANGED;
+
#ifdef TOOLS_ENABLED
bool _disable_set_data;
#endif
+ enum TangentMode {
+ TANGENT_FREE = 0,
+ TANGENT_LINEAR,
+ TANGENT_MODE_COUNT
+ };
+
struct Point {
Vector2 pos;
real_t left_tangent;
real_t right_tangent;
+ TangentMode left_mode;
+ TangentMode right_mode;
Point() {
left_tangent = 0;
right_tangent = 0;
+ left_mode = TANGENT_FREE;
+ right_mode = TANGENT_FREE;
}
Point(Vector2 p, real_t left = 0, real_t right = 0) {
pos = p;
left_tangent = left;
right_tangent = right;
+ left_mode = TANGENT_FREE;
+ right_mode = TANGENT_FREE;
}
};
@@ -124,6 +138,12 @@ public:
int set_point_offset(int p_index, float offset);
Vector2 get_point_pos(int p_index) const;
+ float get_min_value() const { return _min_value; }
+ void set_min_value(float p_min);
+
+ float get_max_value() const { return _max_value; }
+ void set_max_value(float p_max);
+
real_t interpolate(real_t offset) const;
real_t interpolate_local_nocheck(int index, real_t local_offset) const;
@@ -131,8 +151,15 @@ public:
void set_point_left_tangent(int i, real_t tangent);
void set_point_right_tangent(int i, real_t tangent);
+ void set_point_left_mode(int i, TangentMode p_mode);
+ void set_point_right_mode(int i, TangentMode p_mode);
+
real_t get_point_left_tangent(int i) const;
real_t get_point_right_tangent(int i) const;
+ TangentMode get_point_left_mode(int i) const;
+ TangentMode get_point_right_mode(int i) const;
+
+ void update_auto_tangents(int i);
Array get_data() const;
void set_data(Array input);
@@ -152,8 +179,12 @@ private:
bool _baked_cache_dirty;
Vector<real_t> _baked_cache;
int _bake_resolution;
+ float _min_value;
+ float _max_value;
};
+VARIANT_ENUM_CAST(Curve::TangentMode)
+
class Curve2D : public Resource {
GDCLASS(Curve2D, Resource);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 0bd8c41228..6c7ae2445c 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -1370,12 +1370,6 @@ CubeMap::~CubeMap() {
void CurveTexture::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_max", "max"), &CurveTexture::set_max);
- ClassDB::bind_method(D_METHOD("get_max"), &CurveTexture::get_max);
-
- ClassDB::bind_method(D_METHOD("set_min", "min"), &CurveTexture::set_min);
- ClassDB::bind_method(D_METHOD("get_min"), &CurveTexture::get_min);
-
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
ClassDB::bind_method(D_METHOD("set_curve", "curve:Curve"), &CurveTexture::set_curve);
@@ -1383,52 +1377,31 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "min", PROPERTY_HINT_RANGE, "-1024,1024"), "set_min", "get_min");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max", PROPERTY_HINT_RANGE, "-1024,1024"), "set_max", "get_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
}
-void CurveTexture::set_max(float p_max) {
-
- _max = p_max;
- emit_changed();
-}
-float CurveTexture::get_max() const {
- return _max;
-}
-
-void CurveTexture::set_min(float p_min) {
-
- _min = p_min;
- emit_changed();
-}
-float CurveTexture::get_min() const {
-
- return _min;
-}
void CurveTexture::set_width(int p_width) {
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
_width = p_width;
_update();
}
+
int CurveTexture::get_width() const {
return _width;
}
-void CurveTexture::ensure_default_setup() {
-
+void CurveTexture::ensure_default_setup(float p_min, float p_max) {
if (_curve.is_null()) {
Ref<Curve> curve = Ref<Curve>(memnew(Curve));
curve->add_point(Vector2(0, 1));
curve->add_point(Vector2(1, 1));
+ curve->set_min_value(p_min);
+ curve->set_max_value(p_max);
set_curve(curve);
- }
-
- if (get_min() == 0 && get_max() == 1) {
- set_max(32);
+ // Min and max is 0..1 by default
}
}
@@ -1457,11 +1430,9 @@ void CurveTexture::_update() {
if (_curve.is_valid()) {
Curve &curve = **_curve;
- float height = _max - _min;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- float v = curve.interpolate_baked(t);
- wd[i] = CLAMP(_min + v * height, _min, _max);
+ wd[i] = curve.interpolate_baked(t);
}
} else {
@@ -1490,9 +1461,6 @@ RID CurveTexture::get_rid() const {
}
CurveTexture::CurveTexture() {
-
- _max = 1;
- _min = 0;
_width = 2048;
_texture = VS::get_singleton()->texture_create();
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index ff5a58c221..9bbbd1d091 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -403,7 +403,6 @@ class CurveTexture : public Texture {
private:
RID _texture;
Ref<Curve> _curve;
- float _min, _max;
int _width;
void _update();
@@ -412,16 +411,10 @@ protected:
static void _bind_methods();
public:
- void set_max(float p_max);
- float get_max() const;
-
- void set_min(float p_min);
- float get_min() const;
-
void set_width(int p_width);
int get_width() const;
- void ensure_default_setup();
+ void ensure_default_setup(float p_min=0, float p_max=1);
void set_curve(Ref<Curve> p_curve);
Ref<Curve> get_curve() const;