summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorreduz <reduzio@gmail.com>2021-07-01 15:25:35 -0300
committerreduz <reduzio@gmail.com>2021-07-03 12:11:01 -0300
commitd6893cb2e87796336a3c195a1df10057c21dfbca (patch)
treec6f25ad40a68e95014ff96bf5fc7b02aa582c613
parentad8a2b3d527f821d1a0b061811661d49d0920967 (diff)
Implement Curve3Texture
* This was required by users in some scenarios, such as animating individual axes over time with a single texture. * Examples: Shaders, Particles, etc. * CurveTexture now defaults to RGB, can be changed to Red if needed, this allows to freely exchange them.
-rw-r--r--doc/classes/Curve3Texture.xml23
-rw-r--r--doc/classes/CurveTexture.xml6
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/texture.cpp251
-rw-r--r--scene/resources/texture.h64
5 files changed, 328 insertions, 17 deletions
diff --git a/doc/classes/Curve3Texture.xml b/doc/classes/Curve3Texture.xml
new file mode 100644
index 0000000000..1b352dff0d
--- /dev/null
+++ b/doc/classes/Curve3Texture.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="Curve3Texture" inherits="Texture2D" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="curve_x" type="Curve" setter="set_curve_x" getter="get_curve_x">
+ </member>
+ <member name="curve_y" type="Curve" setter="set_curve_y" getter="get_curve_y">
+ </member>
+ <member name="curve_z" type="Curve" setter="set_curve_z" getter="get_curve_z">
+ </member>
+ <member name="width" type="int" setter="set_width" getter="get_width" default="2048">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml
index bc6b69d2d1..54065fe0f9 100644
--- a/doc/classes/CurveTexture.xml
+++ b/doc/classes/CurveTexture.xml
@@ -14,10 +14,16 @@
<member name="curve" type="Curve" setter="set_curve" getter="get_curve">
The [code]curve[/code] rendered onto the texture.
</member>
+ <member name="texture_mode" type="int" setter="set_texture_mode" getter="get_texture_mode" enum="CurveTexture.TextureMode" default="0">
+ </member>
<member name="width" type="int" setter="set_width" getter="get_width" default="2048">
The width of the texture.
</member>
</members>
<constants>
+ <constant name="TEXTURE_MODE_RGB" value="0" enum="TextureMode">
+ </constant>
+ <constant name="TEXTURE_MODE_RED" value="1" enum="TextureMode">
+ </constant>
</constants>
</class>
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index d069d5e963..85bd08529c 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -774,6 +774,7 @@ void register_scene_types() {
ClassDB::register_class<AtlasTexture>();
ClassDB::register_class<MeshTexture>();
ClassDB::register_class<CurveTexture>();
+ ClassDB::register_class<Curve3Texture>();
ClassDB::register_class<GradientTexture>();
ClassDB::register_class<ProxyTexture>();
ClassDB::register_class<AnimatedTexture>();
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 72031c3a69..b4d05fb545 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -1407,14 +1407,26 @@ void CurveTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve);
ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve);
+ ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode);
+ ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode);
+
ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update);
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
+
+ BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB);
+ BIND_ENUM_CONSTANT(TEXTURE_MODE_RED);
}
void CurveTexture::set_width(int p_width) {
ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+
+ if (_width == p_width) {
+ return;
+ }
+
_width = p_width;
_update();
}
@@ -1450,7 +1462,7 @@ void CurveTexture::set_curve(Ref<Curve> p_curve) {
void CurveTexture::_update() {
Vector<uint8_t> data;
- data.resize(_width * sizeof(float));
+ data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1));
// The array is locked in that scope
{
@@ -1461,24 +1473,42 @@ void CurveTexture::_update() {
Curve &curve = **_curve;
for (int i = 0; i < _width; ++i) {
float t = i / static_cast<float>(_width);
- wd[i] = curve.interpolate_baked(t);
+ if (texture_mode == TEXTURE_MODE_RGB) {
+ wd[i * 3 + 0] = curve.interpolate_baked(t);
+ wd[i * 3 + 1] = wd[i * 3 + 0];
+ wd[i * 3 + 2] = wd[i * 3 + 0];
+ } else {
+ wd[i] = curve.interpolate_baked(t);
+ }
}
} else {
for (int i = 0; i < _width; ++i) {
- wd[i] = 0;
+ if (texture_mode == TEXTURE_MODE_RGB) {
+ wd[i * 3 + 0] = 0;
+ wd[i * 3 + 1] = 0;
+ wd[i * 3 + 2] = 0;
+ } else {
+ wd[i] = 0;
+ }
}
}
}
- Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data));
+ Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data));
if (_texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(_texture, new_texture);
+ if (_current_texture_mode != texture_mode || _current_width != _width) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(_texture, new_texture);
+ } else {
+ RS::get_singleton()->texture_2d_update(_texture, image);
+ }
} else {
_texture = RS::get_singleton()->texture_2d_create(image);
}
+ _current_texture_mode = texture_mode;
+ _current_width = _width;
emit_changed();
}
@@ -1487,6 +1517,17 @@ Ref<Curve> CurveTexture::get_curve() const {
return _curve;
}
+void CurveTexture::set_texture_mode(TextureMode p_mode) {
+ if (texture_mode == p_mode) {
+ return;
+ }
+ texture_mode = p_mode;
+ _update();
+}
+CurveTexture::TextureMode CurveTexture::get_texture_mode() const {
+ return texture_mode;
+}
+
RID CurveTexture::get_rid() const {
if (!_texture.is_valid()) {
_texture = RS::get_singleton()->texture_2d_placeholder_create();
@@ -1504,6 +1545,204 @@ CurveTexture::~CurveTexture() {
//////////////////
+void Curve3Texture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_width", "width"), &Curve3Texture::set_width);
+
+ ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &Curve3Texture::set_curve_x);
+ ClassDB::bind_method(D_METHOD("get_curve_x"), &Curve3Texture::get_curve_x);
+
+ ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &Curve3Texture::set_curve_y);
+ ClassDB::bind_method(D_METHOD("get_curve_y"), &Curve3Texture::get_curve_y);
+
+ ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &Curve3Texture::set_curve_z);
+ ClassDB::bind_method(D_METHOD("get_curve_z"), &Curve3Texture::get_curve_z);
+
+ ClassDB::bind_method(D_METHOD("_update"), &Curve3Texture::_update);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z");
+}
+
+void Curve3Texture::set_width(int p_width) {
+ ERR_FAIL_COND(p_width < 32 || p_width > 4096);
+
+ if (_width == p_width) {
+ return;
+ }
+
+ _width = p_width;
+ _update();
+}
+
+int Curve3Texture::get_width() const {
+ return _width;
+}
+
+void Curve3Texture::ensure_default_setup(float p_min, float p_max) {
+ if (_curve_x.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_x(curve);
+ }
+
+ if (_curve_y.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_y(curve);
+ }
+
+ if (_curve_z.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_z(curve);
+ }
+}
+
+void Curve3Texture::set_curve_x(Ref<Curve> p_curve) {
+ if (_curve_x != p_curve) {
+ if (_curve_x.is_valid()) {
+ _curve_x->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update));
+ }
+ _curve_x = p_curve;
+ if (_curve_x.is_valid()) {
+ _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void Curve3Texture::set_curve_y(Ref<Curve> p_curve) {
+ if (_curve_y != p_curve) {
+ if (_curve_y.is_valid()) {
+ _curve_y->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update));
+ }
+ _curve_y = p_curve;
+ if (_curve_y.is_valid()) {
+ _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void Curve3Texture::set_curve_z(Ref<Curve> p_curve) {
+ if (_curve_z != p_curve) {
+ if (_curve_z.is_valid()) {
+ _curve_z->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update));
+ }
+ _curve_z = p_curve;
+ if (_curve_z.is_valid()) {
+ _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED);
+ }
+ _update();
+ }
+}
+
+void Curve3Texture::_update() {
+ Vector<uint8_t> data;
+ data.resize(_width * sizeof(float) * 3);
+
+ // The array is locked in that scope
+ {
+ uint8_t *wd8 = data.ptrw();
+ float *wd = (float *)wd8;
+
+ if (_curve_x.is_valid()) {
+ Curve &curve_x = **_curve_x;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 0] = curve_x.interpolate_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 0] = 0;
+ }
+ }
+
+ if (_curve_y.is_valid()) {
+ Curve &curve_y = **_curve_y;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 1] = curve_y.interpolate_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 1] = 0;
+ }
+ }
+
+ if (_curve_z.is_valid()) {
+ Curve &curve_z = **_curve_z;
+ for (int i = 0; i < _width; ++i) {
+ float t = i / static_cast<float>(_width);
+ wd[i * 3 + 2] = curve_z.interpolate_baked(t);
+ }
+
+ } else {
+ for (int i = 0; i < _width; ++i) {
+ wd[i * 3 + 2] = 0;
+ }
+ }
+ }
+
+ Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data));
+
+ if (_texture.is_valid()) {
+ if (_current_width != _width) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(_texture, new_texture);
+ } else {
+ RS::get_singleton()->texture_2d_update(_texture, image);
+ }
+ } else {
+ _texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ _current_width = _width;
+
+ emit_changed();
+}
+
+Ref<Curve> Curve3Texture::get_curve_x() const {
+ return _curve_x;
+}
+
+Ref<Curve> Curve3Texture::get_curve_y() const {
+ return _curve_y;
+}
+
+Ref<Curve> Curve3Texture::get_curve_z() const {
+ return _curve_z;
+}
+
+RID Curve3Texture::get_rid() const {
+ if (!_texture.is_valid()) {
+ _texture = RS::get_singleton()->texture_2d_placeholder_create();
+ }
+ return _texture;
+}
+
+Curve3Texture::Curve3Texture() {}
+
+Curve3Texture::~Curve3Texture() {
+ if (_texture.is_valid()) {
+ RS::get_singleton()->free(_texture);
+ }
+}
+
+//////////////////
+
GradientTexture::GradientTexture() {
_queue_update();
}
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 40193e3ff6..73390039cb 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -586,11 +586,19 @@ public:
class CurveTexture : public Texture2D {
GDCLASS(CurveTexture, Texture2D);
RES_BASE_EXTENSION("curvetex")
+public:
+ enum TextureMode {
+ TEXTURE_MODE_RGB,
+ TEXTURE_MODE_RED,
+ };
private:
mutable RID _texture;
Ref<Curve> _curve;
int _width = 2048;
+ int _current_width = 0;
+ TextureMode texture_mode = TEXTURE_MODE_RGB;
+ TextureMode _current_texture_mode = TEXTURE_MODE_RGB;
void _update();
@@ -601,6 +609,9 @@ public:
void set_width(int p_width);
int get_width() const override;
+ void set_texture_mode(TextureMode p_mode);
+ TextureMode get_texture_mode() const;
+
void ensure_default_setup(float p_min = 0, float p_max = 1);
void set_curve(Ref<Curve> p_curve);
@@ -614,18 +625,49 @@ public:
CurveTexture();
~CurveTexture();
};
-/*
- enum CubeMapSide {
- CUBEMAP_LEFT,
- CUBEMAP_RIGHT,
- CUBEMAP_BOTTOM,
- CUBEMAP_TOP,
- CUBEMAP_FRONT,
- CUBEMAP_BACK,
- };
-*/
-//VARIANT_ENUM_CAST( Texture::CubeMapSide );
+VARIANT_ENUM_CAST(CurveTexture::TextureMode)
+
+class Curve3Texture : public Texture2D {
+ GDCLASS(Curve3Texture, Texture2D);
+ RES_BASE_EXTENSION("curvetex")
+
+private:
+ mutable RID _texture;
+ Ref<Curve> _curve_x;
+ Ref<Curve> _curve_y;
+ Ref<Curve> _curve_z;
+ int _width = 2048;
+ int _current_width = 0;
+
+ void _update();
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_width(int p_width);
+ int get_width() const override;
+
+ void ensure_default_setup(float p_min = 0, float p_max = 1);
+
+ void set_curve_x(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_x() const;
+
+ void set_curve_y(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_y() const;
+
+ void set_curve_z(Ref<Curve> p_curve);
+ Ref<Curve> get_curve_z() const;
+
+ virtual RID get_rid() const override;
+
+ virtual int get_height() const override { return 1; }
+ virtual bool has_alpha() const override { return false; }
+
+ Curve3Texture();
+ ~Curve3Texture();
+};
class GradientTexture : public Texture2D {
GDCLASS(GradientTexture, Texture2D);