summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2017-06-23 20:07:01 -0300
committerGitHub <noreply@github.com>2017-06-23 20:07:01 -0300
commit693eb0fa06a5be6e9664f7a413199f0100b7d289 (patch)
treedb94c76d34d51e9ec97213a08c9654825707fad4 /scene
parent00e5ba314393ce2cc4df883bc1742306007ed117 (diff)
parent659897cfb8bda0377d798a6f73505d537e521cf9 (diff)
Merge pull request #8591 from Zylann/curve_1d
Added Curve resource
Diffstat (limited to 'scene')
-rw-r--r--scene/3d/particles.cpp22
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/curve.cpp359
-rw-r--r--scene/resources/curve.h72
-rw-r--r--scene/resources/texture.cpp242
-rw-r--r--scene/resources/texture.h27
6 files changed, 510 insertions, 213 deletions
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 8508962521..722b698b75 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -1082,16 +1082,9 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture>
case PARAM_SCALE: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture);
- Ref<CurveTexture> curve = p_texture;
- if (curve.is_valid()) {
- if (curve->get_min() == 0 && curve->get_max() == 1) {
-
- curve->set_max(32);
- PoolVector<Vector2> points;
- points.push_back(Vector2(0, 1));
- points.push_back(Vector2(1, 1));
- curve->set_points(points);
- }
+ Ref<CurveTexture> curve_tex = p_texture;
+ if (curve_tex.is_valid()) {
+ curve_tex->ensure_default_setup();
}
} break;
@@ -1257,14 +1250,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail
Ref<CurveTexture> curve = trail_size_modifier;
if (curve.is_valid()) {
- if (curve->get_min() == 0 && curve->get_max() == 1) {
-
- curve->set_max(32);
- PoolVector<Vector2> points;
- points.push_back(Vector2(0, 1));
- points.push_back(Vector2(1, 1));
- curve->set_points(points);
- }
+ curve->ensure_default_setup();
}
RID texture;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 69d1a3aeb8..151bc80321 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -580,6 +580,7 @@ void register_scene_types() {
ClassDB::register_class<Animation>();
ClassDB::register_virtual_class<Font>();
ClassDB::register_class<BitmapFont>();
+ ClassDB::register_class<Curve>();
ClassDB::register_class<DynamicFontData>();
ClassDB::register_class<DynamicFont>();
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 10c12c9411..006e7de562 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -380,6 +380,365 @@ Curve2D::Curve2D()
#endif
+Curve::Curve() {
+ _bake_resolution = 100;
+ _baked_cache_dirty = false;
+#ifdef TOOLS_ENABLED
+ _disable_set_data = false;
+#endif
+}
+
+int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent) {
+ // Add a point and preserve order
+
+ // Curve bounds is in 0..1
+ if (p_pos.x > MAX_X)
+ p_pos.x = MAX_X;
+ else if (p_pos.x < MIN_X)
+ p_pos.x = MIN_X;
+
+ int ret = -1;
+
+ if (_points.size() == 0) {
+ _points.push_back(Point(p_pos, left_tangent, right_tangent));
+ ret = 0;
+
+ } else if (_points.size() == 1) {
+ // TODO Is the `else` able to handle this block already?
+
+ real_t diff = p_pos.x - _points[0].pos.x;
+
+ if (diff > 0) {
+ _points.push_back(Point(p_pos, left_tangent, right_tangent));
+ ret = 1;
+ } else {
+ _points.insert(0, Point(p_pos, left_tangent, right_tangent));
+ ret = 0;
+ }
+
+ } else {
+
+ int i = get_index(p_pos.x);
+
+ int nearest_index = i;
+ if (i + 1 < _points.size()) {
+ real_t diff0 = p_pos.x - _points[i].pos.x;
+ real_t diff1 = _points[i + 1].pos.x - p_pos.x;
+
+ if (diff1 < diff0)
+ nearest_index = i + 1;
+ }
+
+ if (i == 0 && p_pos.x < _points[0].pos.x) {
+ // Insert before anything else
+ _points.insert(0, Point(p_pos, left_tangent, right_tangent));
+ ret = 0;
+ } else {
+ // Insert between i and i+1
+ ++i;
+ _points.insert(i, Point(p_pos, left_tangent, right_tangent));
+ ret = i;
+ }
+ }
+
+ mark_dirty();
+
+ return ret;
+}
+
+int Curve::get_index(real_t offset) const {
+
+ // Lower-bound float binary search
+
+ int imin = 0;
+ int imax = _points.size() - 1;
+
+ while (imax - imin > 1) {
+ int m = (imin + imax) / 2;
+
+ real_t a = _points[m].pos.x;
+ real_t b = _points[m + 1].pos.x;
+
+ if (a < offset && b < offset) {
+ imin = m;
+
+ } else if (a > offset) {
+ imax = m;
+
+ } else {
+ return m;
+ }
+ }
+
+ // Will happen if the offset is out of bounds
+ if (offset > _points[imax].pos.x)
+ return imax;
+ return imin;
+}
+
+void Curve::clean_dupes() {
+
+ bool dirty = false;
+
+ for (int i = 1; i < _points.size(); ++i) {
+ real_t diff = _points[i - 1].pos.x - _points[i].pos.x;
+ if (diff <= CMP_EPSILON) {
+ _points.remove(i);
+ --i;
+ dirty = true;
+ }
+ }
+
+ if (dirty)
+ mark_dirty();
+}
+
+void Curve::set_point_left_tangent(int i, real_t tangent) {
+ ERR_FAIL_INDEX(i, _points.size());
+ _points[i].left_tangent = tangent;
+ mark_dirty();
+}
+
+void Curve::set_point_right_tangent(int i, real_t tangent) {
+ ERR_FAIL_INDEX(i, _points.size());
+ _points[i].right_tangent = tangent;
+ mark_dirty();
+}
+
+real_t Curve::get_point_left_tangent(int i) const {
+ ERR_FAIL_INDEX_V(i, _points.size(), 0);
+ return _points[i].left_tangent;
+}
+
+real_t Curve::get_point_right_tangent(int i) const {
+ ERR_FAIL_INDEX_V(i, _points.size(), 0);
+ return _points[i].right_tangent;
+}
+
+void Curve::remove_point(int p_index) {
+ ERR_FAIL_INDEX(p_index, _points.size());
+ _points.remove(p_index);
+ mark_dirty();
+}
+
+void Curve::clear_points() {
+ _points.clear();
+ mark_dirty();
+}
+
+void Curve::set_point_value(int p_index, real_t pos) {
+ ERR_FAIL_INDEX(p_index, _points.size());
+ _points[p_index].pos.y = pos;
+ mark_dirty();
+}
+
+int Curve::set_point_offset(int p_index, float offset) {
+ ERR_FAIL_INDEX_V(p_index, _points.size(), -1);
+ Point p = _points[p_index];
+ remove_point(p_index);
+ int i = add_point(Vector2(offset, p.pos.y));
+ _points[i].left_tangent = p.left_tangent;
+ _points[i].right_tangent = p.right_tangent;
+ return i;
+}
+
+Vector2 Curve::get_point_pos(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, _points.size(), Vector2(0, 0));
+ return _points[p_index].pos;
+}
+
+real_t Curve::interpolate(real_t offset) const {
+ if (_points.size() == 0)
+ return 0;
+ if (_points.size() == 1)
+ return _points[0].pos.y;
+
+ int i = get_index(offset);
+
+ if (i == _points.size() - 1)
+ return _points[i].pos.y;
+
+ real_t local = offset - _points[i].pos.x;
+
+ if (i == 0 && local <= 0)
+ return _points[0].pos.y;
+
+ return interpolate_local_nocheck(i, local);
+}
+
+real_t Curve::interpolate_local_nocheck(int index, real_t local_offset) const {
+
+ const Point a = _points[index];
+ const Point b = _points[index + 1];
+
+ // Cubic bezier
+
+ // ac-----bc
+ // / \
+ // / \ Here with a.right_tangent > 0
+ // / \ and b.left_tangent < 0
+ // / \
+ // a b
+ //
+ // |-d1--|-d2--|-d3--|
+ //
+ // d1 == d2 == d3 == d / 3
+
+ // Control points are chosen at equal distances
+ real_t d = b.pos.x - a.pos.x;
+ if (Math::abs(d) <= CMP_EPSILON)
+ return b.pos.y;
+ local_offset /= d;
+ d /= 3.0;
+ real_t yac = a.pos.y + d * a.right_tangent;
+ real_t ybc = b.pos.y - d * b.left_tangent;
+
+ real_t y = _bezier_interp(local_offset, a.pos.y, yac, ybc, b.pos.y);
+
+ return y;
+}
+
+void Curve::mark_dirty() {
+ _baked_cache_dirty = true;
+ emit_signal(CoreStringNames::get_singleton()->changed);
+}
+
+Array Curve::get_data() const {
+
+ Array output;
+ output.resize(_points.size() * 3);
+
+ for (int j = 0; j < _points.size(); ++j) {
+
+ const Point p = _points[j];
+ int i = j * 3;
+
+ output[i] = p.pos;
+ output[i + 1] = p.left_tangent;
+ output[i + 2] = p.right_tangent;
+ }
+
+ return output;
+}
+
+void Curve::set_data(Array input) {
+ ERR_FAIL_COND(input.size() % 3 != 0);
+
+#ifdef TOOLS_ENABLED
+ if (_disable_set_data)
+ return;
+#endif
+
+ _points.clear();
+
+ // Validate input
+ for (int i = 0; i < input.size(); i += 3) {
+ 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);
+ }
+
+ _points.resize(input.size() / 3);
+
+ for (int j = 0; j < _points.size(); ++j) {
+
+ Point &p = _points[j];
+ int i = j * 3;
+
+ p.pos = input[i];
+ p.left_tangent = input[i + 1];
+ p.right_tangent = input[i + 2];
+ }
+
+ mark_dirty();
+}
+
+void Curve::bake() {
+ _baked_cache.clear();
+
+ _baked_cache.resize(_bake_resolution);
+
+ for (int i = 1; i < _bake_resolution - 1; ++i) {
+ real_t x = i / static_cast<real_t>(_bake_resolution);
+ real_t y = interpolate(x);
+ _baked_cache[i] = y;
+ }
+
+ if (_points.size() != 0) {
+ _baked_cache[0] = _points[0].pos.y;
+ _baked_cache[_baked_cache.size() - 1] = _points[_points.size() - 1].pos.y;
+ }
+
+ _baked_cache_dirty = false;
+}
+
+void Curve::set_bake_resolution(int p_resolution) {
+ ERR_FAIL_COND(p_resolution < 1);
+ ERR_FAIL_COND(p_resolution > 1000);
+ _bake_resolution = p_resolution;
+ _baked_cache_dirty = true;
+}
+
+real_t Curve::interpolate_baked(real_t offset) {
+ if (_baked_cache_dirty) {
+ // Last-second bake if not done already
+ bake();
+ }
+
+ // Special cases if the cache is too small
+ if (_baked_cache.size() == 0) {
+ if (_points.size() == 0)
+ return 0;
+ return _points[0].pos.y;
+ } else if (_baked_cache.size() == 1) {
+ return _baked_cache[0];
+ }
+
+ // Get interpolation index
+ real_t fi = offset * _baked_cache.size();
+ int i = Math::floor(fi);
+ if (i < 0) {
+ i = 0;
+ fi = 0;
+ } else if (i >= _baked_cache.size()) {
+ i = _baked_cache.size() - 1;
+ fi = 0;
+ }
+
+ // Interpolate
+ if (i + 1 < _baked_cache.size()) {
+ real_t t = fi - i;
+ return Math::lerp(_baked_cache[i], _baked_cache[i + 1], t);
+ } else {
+ return _baked_cache[_baked_cache.size() - 1];
+ }
+}
+
+void Curve::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("add_point", "pos", "left_tangent", "right_tangent"), &Curve::add_point, DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("remove_point", "index"), &Curve::remove_point);
+ ClassDB::bind_method(D_METHOD("clear_points"), &Curve::clear_points);
+ ClassDB::bind_method(D_METHOD("get_point_pos", "index"), &Curve::get_point_pos);
+ ClassDB::bind_method(D_METHOD("set_point_value", "index, y"), &Curve::set_point_value);
+ ClassDB::bind_method(D_METHOD("set_point_offset", "index, offset"), &Curve::set_point_value);
+ ClassDB::bind_method(D_METHOD("interpolate", "offset"), &Curve::interpolate);
+ 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("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("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);
+ ClassDB::bind_method(D_METHOD("set_bake_resolution", "resolution"), &Curve::set_bake_resolution);
+ 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::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");
+}
+
int Curve2D::get_point_count() const {
return points.size();
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 17c0ac9f5e..63b9a07f07 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -82,6 +82,78 @@ public:
#endif
+// y(x) curve
+class Curve : public Resource {
+ GDCLASS(Curve, Resource)
+public:
+ static const int MIN_X = 0.f;
+ static const int MAX_X = 1.f;
+
+#ifdef TOOLS_ENABLED
+ bool _disable_set_data;
+#endif
+
+ struct Point {
+ Vector2 pos;
+ real_t left_tangent;
+ real_t right_tangent;
+
+ Point() {
+ left_tangent = 0;
+ right_tangent = 0;
+ }
+
+ Point(Vector2 p, real_t left = 0, real_t right = 0) {
+ pos = p;
+ left_tangent = left;
+ right_tangent = right;
+ }
+ };
+
+ Curve();
+
+ int get_point_count() const { return _points.size(); }
+
+ int add_point(Vector2 p_pos, real_t left_tangent = 0, real_t right_tangent = 0);
+ void remove_point(int p_index);
+ void clear_points();
+
+ int get_index(real_t offset) const;
+
+ void set_point_value(int p_index, real_t pos);
+ int set_point_offset(int p_index, float offset);
+ Vector2 get_point_pos(int p_index) const;
+
+ real_t interpolate(real_t offset) const;
+ real_t interpolate_local_nocheck(int index, real_t local_offset) const;
+
+ void clean_dupes();
+
+ void set_point_left_tangent(int i, real_t tangent);
+ void set_point_right_tangent(int i, real_t tangent);
+ real_t get_point_left_tangent(int i) const;
+ real_t get_point_right_tangent(int i) const;
+
+ Array get_data() const;
+ void set_data(Array input);
+
+ void bake();
+ int get_bake_resolution() const { return _bake_resolution; }
+ void set_bake_resolution(int p_interval);
+ real_t interpolate_baked(real_t offset);
+
+protected:
+ static void _bind_methods();
+
+private:
+ void mark_dirty();
+
+ Vector<Point> _points;
+ bool _baked_cache_dirty;
+ Vector<real_t> _baked_cache;
+ int _bake_resolution;
+};
+
class Curve2D : public Resource {
GDCLASS(Curve2D, Resource);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 2120b37497..7b393233f1 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -30,7 +30,9 @@
#include "texture.h"
#include "core/method_bind_ext.inc"
#include "core/os/os.h"
+#include "core_string_names.h"
#include "io/image_loader.h"
+
Size2 Texture::get_size() const {
return Size2(get_width(), get_height());
@@ -1376,254 +1378,126 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_width", "width"), &CurveTexture::set_width);
- ClassDB::bind_method(D_METHOD("set_points", "points"), &CurveTexture::set_points);
- ClassDB::bind_method(D_METHOD("get_points"), &CurveTexture::get_points);
+ ClassDB::bind_method(D_METHOD("set_curve", "curve:Curve"), &CurveTexture::set_curve);
+ ClassDB::bind_method(D_METHOD("get_curve:Curve"), &CurveTexture::get_curve);
+
+ 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::POOL_VECTOR2_ARRAY, "points"), "set_points", "get_points");
+ 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;
+ _max = p_max;
emit_changed();
}
float CurveTexture::get_max() const {
- return max;
+ return _max;
}
void CurveTexture::set_min(float p_min) {
- min = p_min;
+ _min = p_min;
emit_changed();
}
float CurveTexture::get_min() const {
- return min;
+ return _min;
}
void CurveTexture::set_width(int p_width) {
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
- width = p_width;
- if (points.size())
- set_points(points);
+ _width = p_width;
+ _update();
}
int CurveTexture::get_width() const {
- return width;
+ return _width;
}
-static void _plot_curve(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_c, const Vector2 &p_d, float *p_heights, bool *p_useds, int p_width, float p_min, float p_max) {
-
- float geometry[4][4];
- float tmp1[4][4];
- float tmp2[4][4];
- float deltas[4][4];
- double x, dx, dx2, dx3;
- double y, dy, dy2, dy3;
- double d, d2, d3;
- int lastx;
- int newx;
- float lasty;
- float newy;
- int ntimes;
- int i, j;
-
- int xmax = p_width;
-
- /* construct the geometry matrix from the segment */
- for (i = 0; i < 4; i++) {
- geometry[i][2] = 0;
- geometry[i][3] = 0;
- }
+void CurveTexture::ensure_default_setup() {
- geometry[0][0] = (p_a[0] * xmax);
- geometry[1][0] = (p_b[0] * xmax);
- geometry[2][0] = (p_c[0] * xmax);
- geometry[3][0] = (p_d[0] * xmax);
-
- geometry[0][1] = (p_a[1]);
- geometry[1][1] = (p_b[1]);
- geometry[2][1] = (p_c[1]);
- geometry[3][1] = (p_d[1]);
-
- /* subdivide the curve ntimes (1000) times */
- ntimes = 4 * xmax;
- /* ntimes can be adjusted to give a finer or coarser curve */
- d = 1.0 / ntimes;
- d2 = d * d;
- d3 = d * d * d;
-
- /* construct a temporary matrix for determining the forward differencing deltas */
- tmp2[0][0] = 0;
- tmp2[0][1] = 0;
- tmp2[0][2] = 0;
- tmp2[0][3] = 1;
- tmp2[1][0] = d3;
- tmp2[1][1] = d2;
- tmp2[1][2] = d;
- tmp2[1][3] = 0;
- tmp2[2][0] = 6 * d3;
- tmp2[2][1] = 2 * d2;
- tmp2[2][2] = 0;
- tmp2[2][3] = 0;
- tmp2[3][0] = 6 * d3;
- tmp2[3][1] = 0;
- tmp2[3][2] = 0;
- tmp2[3][3] = 0;
-
- /* compose the basis and geometry matrices */
-
- static const float CR_basis[4][4] = {
- { -0.5, 1.5, -1.5, 0.5 },
- { 1.0, -2.5, 2.0, -0.5 },
- { -0.5, 0.0, 0.5, 0.0 },
- { 0.0, 1.0, 0.0, 0.0 },
- };
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
- }
+ if (_curve.is_null()) {
+ Ref<Curve> curve = Ref<Curve>(memnew(Curve));
+ curve->add_point(Vector2(0, 1));
+ curve->add_point(Vector2(1, 1));
+ set_curve(curve);
}
- /* compose the above results to get the deltas matrix */
-
- for (i = 0; i < 4; i++) {
- for (j = 0; j < 4; j++) {
- deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
- }
+
+ if (get_min() == 0 && get_max() == 1) {
+ set_max(32);
}
+}
- /* extract the x deltas */
- x = deltas[0][0];
- dx = deltas[1][0];
- dx2 = deltas[2][0];
- dx3 = deltas[3][0];
-
- /* extract the y deltas */
- y = deltas[0][1];
- dy = deltas[1][1];
- dy2 = deltas[2][1];
- dy3 = deltas[3][1];
-
- lastx = CLAMP(x, 0, xmax);
- lasty = y;
-
- p_heights[lastx] = lasty;
- p_useds[lastx] = true;
-
- /* loop over the curve */
- for (i = 0; i < ntimes; i++) {
- /* increment the x values */
- x += dx;
- dx += dx2;
- dx2 += dx3;
-
- /* increment the y values */
- y += dy;
- dy += dy2;
- dy2 += dy3;
-
- newx = CLAMP((Math::round(x)), 0, xmax);
- newy = CLAMP(y, p_min, p_max);
-
- /* if this point is different than the last one...then draw it */
- if ((lastx != newx) || (lasty != newy)) {
- p_useds[newx] = true;
- p_heights[newx] = newy;
+void CurveTexture::set_curve(Ref<Curve> p_curve) {
+ if (_curve != p_curve) {
+ if (_curve.is_valid()) {
+ _curve->disconnect(CoreStringNames::get_singleton()->changed, this, "_update");
}
-
- lastx = newx;
- lasty = newy;
+ _curve = p_curve;
+ if (_curve.is_valid()) {
+ _curve->connect(CoreStringNames::get_singleton()->changed, this, "_update");
+ }
+ _update();
}
}
-void CurveTexture::set_points(const PoolVector<Vector2> &p_points) {
-
- points = p_points;
+void CurveTexture::_update() {
PoolVector<uint8_t> data;
- PoolVector<bool> used;
- data.resize(width * sizeof(float));
- used.resize(width);
+ data.resize(_width * sizeof(float));
+
+ // The array is locked in that scope
{
PoolVector<uint8_t>::Write wd8 = data.write();
float *wd = (float *)wd8.ptr();
- PoolVector<bool>::Write wu = used.write();
- int pc = p_points.size();
- PoolVector<Vector2>::Read pr = p_points.read();
- for (int i = 0; i < width; i++) {
- wd[i] = 0.0;
- wu[i] = false;
- }
-
- Vector2 prev = Vector2(0, 0);
- Vector2 prev2 = Vector2(0, 0);
-
- for (int i = -1; i < pc; i++) {
-
- Vector2 next;
- Vector2 next2;
- if (i + 1 >= pc) {
- next = Vector2(1, 0);
- } else {
- next = Vector2(pr[i + 1].x, pr[i + 1].y);
+ 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);
}
- if (i + 2 >= pc) {
- next2 = Vector2(1, 0);
- } else {
- next2 = Vector2(pr[i + 2].x, pr[i + 2].y);
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i] = 0;
}
-
- /*if (i==-1 && prev.offset==next.offset) {
- prev=next;
- continue;
- }*/
-
- _plot_curve(prev2, prev, next, next2, wd, wu.ptr(), width, min, max);
-
- prev2 = prev;
- prev = next;
}
}
- Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RF, data));
+ Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
- VS::get_singleton()->texture_allocate(texture, width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
- VS::get_singleton()->texture_set_data(texture, image);
+ VS::get_singleton()->texture_allocate(_texture, _width, 1, Image::FORMAT_RF, VS::TEXTURE_FLAG_FILTER);
+ VS::get_singleton()->texture_set_data(_texture, image);
emit_changed();
}
-PoolVector<Vector2> CurveTexture::get_points() const {
+Ref<Curve> CurveTexture::get_curve() const {
- return points;
+ return _curve;
}
RID CurveTexture::get_rid() const {
- return texture;
+ return _texture;
}
CurveTexture::CurveTexture() {
- max = 1;
- min = 0;
- width = 2048;
- texture = VS::get_singleton()->texture_create();
+ _max = 1;
+ _min = 0;
+ _width = 2048;
+ _texture = VS::get_singleton()->texture_create();
}
CurveTexture::~CurveTexture() {
- VS::get_singleton()->free(texture);
+ VS::get_singleton()->free(_texture);
}
//////////////////
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 2b82dbd21f..2c36cdef87 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -30,6 +30,7 @@
#ifndef TEXTURE_H
#define TEXTURE_H
+#include "curve.h"
#include "io/resource_loader.h"
#include "math_2d.h"
#include "resource.h"
@@ -389,20 +390,22 @@ public:
~CubeMap();
};
-VARIANT_ENUM_CAST(CubeMap::Flags);
-VARIANT_ENUM_CAST(CubeMap::Side);
-VARIANT_ENUM_CAST(CubeMap::Storage);
+VARIANT_ENUM_CAST(CubeMap::Flags)
+VARIANT_ENUM_CAST(CubeMap::Side)
+VARIANT_ENUM_CAST(CubeMap::Storage)
class CurveTexture : public Texture {
- GDCLASS(CurveTexture, Texture);
- RES_BASE_EXTENSION("curvetex");
+ GDCLASS(CurveTexture, Texture)
+ RES_BASE_EXTENSION("curvetex")
private:
- RID texture;
- PoolVector<Vector2> points;
- float min, max;
- int width;
+ RID _texture;
+ Ref<Curve> _curve;
+ float _min, _max;
+ int _width;
+
+ void _update();
protected:
static void _bind_methods();
@@ -417,8 +420,10 @@ public:
void set_width(int p_width);
int get_width() const;
- void set_points(const PoolVector<Vector2> &p_points);
- PoolVector<Vector2> get_points() const;
+ void ensure_default_setup();
+
+ void set_curve(Ref<Curve> p_curve);
+ Ref<Curve> get_curve() const;
virtual RID get_rid() const;