summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/collision_object_2d.cpp8
-rw-r--r--scene/2d/collision_object_2d.h4
-rw-r--r--scene/2d/cpu_particles_2d.cpp254
-rw-r--r--scene/2d/cpu_particles_2d.h22
-rw-r--r--scene/2d/gpu_particles_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.cpp8
-rw-r--r--scene/2d/physics_body_2d.h2
-rw-r--r--scene/2d/tile_map.cpp12
-rw-r--r--scene/2d/touch_screen_button.cpp8
-rw-r--r--scene/2d/touch_screen_button.h2
-rw-r--r--scene/3d/area_3d.cpp69
-rw-r--r--scene/3d/area_3d.h14
-rw-r--r--scene/3d/audio_stream_player_3d.cpp6
-rw-r--r--scene/3d/collision_object_3d.cpp8
-rw-r--r--scene/3d/collision_object_3d.h4
-rw-r--r--scene/3d/cpu_particles_3d.cpp260
-rw-r--r--scene/3d/cpu_particles_3d.h25
-rw-r--r--scene/3d/gpu_particles_3d.cpp2
-rw-r--r--scene/3d/physics_body_3d.cpp67
-rw-r--r--scene/3d/physics_body_3d.h2
-rw-r--r--scene/animation/animation_tree.cpp52
-rw-r--r--scene/animation/animation_tree.h8
-rw-r--r--scene/audio/audio_stream_player.cpp6
-rw-r--r--scene/gui/base_button.cpp18
-rw-r--r--scene/gui/base_button.h7
-rw-r--r--scene/gui/code_edit.cpp41
-rw-r--r--scene/gui/code_edit.h12
-rw-r--r--scene/gui/color_picker.cpp202
-rw-r--r--scene/gui/color_picker.h39
-rw-r--r--scene/gui/control.cpp103
-rw-r--r--scene/gui/control.h18
-rw-r--r--scene/gui/file_dialog.cpp4
-rw-r--r--scene/gui/file_dialog.h2
-rw-r--r--scene/gui/gradient_edit.cpp3
-rw-r--r--scene/gui/gradient_edit.h2
-rw-r--r--scene/gui/graph_edit.cpp115
-rw-r--r--scene/gui/graph_edit.h13
-rw-r--r--scene/gui/graph_node.cpp4
-rw-r--r--scene/gui/graph_node.h2
-rw-r--r--scene/gui/item_list.cpp42
-rw-r--r--scene/gui/item_list.h7
-rw-r--r--scene/gui/line_edit.cpp3
-rw-r--r--scene/gui/line_edit.h2
-rw-r--r--scene/gui/menu_button.cpp6
-rw-r--r--scene/gui/menu_button.h4
-rw-r--r--scene/gui/popup_menu.cpp6
-rw-r--r--scene/gui/popup_menu.h4
-rw-r--r--scene/gui/rich_text_effect.cpp29
-rw-r--r--scene/gui/rich_text_effect.h32
-rw-r--r--scene/gui/rich_text_label.cpp11
-rw-r--r--scene/gui/rich_text_label.h2
-rw-r--r--scene/gui/scroll_bar.cpp3
-rw-r--r--scene/gui/scroll_bar.h2
-rw-r--r--scene/gui/scroll_container.cpp3
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/shortcut.cpp76
-rw-r--r--scene/gui/shortcut.h54
-rw-r--r--scene/gui/slider.cpp3
-rw-r--r--scene/gui/slider.h2
-rw-r--r--scene/gui/spin_box.cpp4
-rw-r--r--scene/gui/spin_box.h2
-rw-r--r--scene/gui/split_container.cpp4
-rw-r--r--scene/gui/split_container.h2
-rw-r--r--scene/gui/subviewport_container.cpp10
-rw-r--r--scene/gui/subviewport_container.h4
-rw-r--r--scene/gui/tab_container.cpp3
-rw-r--r--scene/gui/tab_container.h2
-rw-r--r--scene/gui/tabs.cpp3
-rw-r--r--scene/gui/tabs.h2
-rw-r--r--scene/gui/text_edit.cpp56
-rw-r--r--scene/gui/text_edit.h20
-rw-r--r--scene/gui/tree.cpp4
-rw-r--r--scene/gui/tree.h3
-rw-r--r--scene/main/canvas_item.cpp6
-rw-r--r--scene/main/canvas_item.h1
-rw-r--r--scene/main/node.cpp95
-rw-r--r--scene/main/node.h21
-rw-r--r--scene/main/scene_tree.cpp23
-rw-r--r--scene/main/scene_tree.h8
-rw-r--r--scene/main/viewport.cpp59
-rw-r--r--scene/main/viewport.h6
-rw-r--r--scene/main/window.cpp6
-rw-r--r--scene/register_scene_types.cpp1
-rw-r--r--scene/resources/animation.cpp13
-rw-r--r--scene/resources/animation.h3
-rw-r--r--scene/resources/curve.cpp97
-rw-r--r--scene/resources/curve.h2
-rw-r--r--scene/resources/default_theme/default_theme.cpp50
-rw-r--r--scene/resources/particles_material.cpp344
-rw-r--r--scene/resources/particles_material.h62
-rw-r--r--scene/resources/primitive_meshes.cpp7
-rw-r--r--scene/resources/skeleton_modification_2d.cpp12
-rw-r--r--scene/resources/skeleton_modification_2d.h4
-rw-r--r--scene/resources/skeleton_modification_3d.cpp16
-rw-r--r--scene/resources/skeleton_modification_3d.h3
-rw-r--r--scene/resources/syntax_highlighter.cpp24
-rw-r--r--scene/resources/syntax_highlighter.h9
-rw-r--r--scene/resources/text_paragraph.cpp17
-rw-r--r--scene/resources/texture.cpp71
-rw-r--r--scene/resources/texture.h4
-rw-r--r--scene/resources/visual_shader.cpp109
-rw-r--r--scene/resources/visual_shader.h14
103 files changed, 1668 insertions, 1267 deletions
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index e0b994f27d..8a4d42fd1f 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -272,8 +272,12 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) {
}
if (p_stream.is_valid()) {
- stream = p_stream;
stream_playback = p_stream->instance_playback();
+ if (stream_playback.is_valid()) {
+ stream = p_stream;
+ } else {
+ stream.unref();
+ }
}
AudioServer::get_singleton()->unlock();
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 60f29ca163..5d3a538f60 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -481,10 +481,8 @@ bool CollisionObject2D::is_pickable() const {
return pickable;
}
-void CollisionObject2D::_input_event(Node *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_viewport, p_input_event, p_shape);
- }
+void CollisionObject2D::_input_event_call(Viewport *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape) {
+ GDVIRTUAL_CALL(_input_event, p_viewport, p_input_event, p_shape);
emit_signal(SceneStringNames::get_singleton()->input_event, p_viewport, p_input_event, p_shape);
}
@@ -597,7 +595,7 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject2D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner);
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "viewport"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
+ GDVIRTUAL_BIND(_input_event, "viewport", "event", "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 11e11d1382..19abacb201 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -32,6 +32,7 @@
#define COLLISION_OBJECT_2D_H
#include "scene/2d/node_2d.h"
+#include "scene/main/viewport.h"
#include "scene/resources/shape_2d.h"
#include "servers/physics_server_2d.h"
@@ -88,7 +89,7 @@ protected:
void _update_pickable();
friend class Viewport;
- void _input_event(Node *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape);
+ void _input_event_call(Viewport *p_viewport, const Ref<InputEvent> &p_input_event, int p_shape);
void _mouse_enter();
void _mouse_exit();
@@ -100,6 +101,7 @@ protected:
void set_body_mode(PhysicsServer2D::BodyMode p_mode);
+ GDVIRTUAL3(_input_event, Viewport *, Ref<InputEvent>, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 559bd2fd16..b836497627 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -248,7 +248,7 @@ TypedArray<String> CPUParticles2D::get_configuration_warnings() const {
CanvasItemMaterial *mat = Object::cast_to<CanvasItemMaterial>(get_material().ptr());
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
- if (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
+ if (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid()) {
warnings.push_back(TTR("CPUParticles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
@@ -292,28 +292,34 @@ real_t CPUParticles2D::get_spread() const {
return spread;
}
-void CPUParticles2D::set_param(Parameter p_param, real_t p_value) {
+void CPUParticles2D::set_param_min(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- parameters[p_param] = p_value;
+ parameters_min[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_max(p_param, p_value);
+ }
}
-real_t CPUParticles2D::get_param(Parameter p_param) const {
+real_t CPUParticles2D::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return parameters[p_param];
+ return parameters_min[p_param];
}
-void CPUParticles2D::set_param_randomness(Parameter p_param, real_t p_value) {
+void CPUParticles2D::set_param_max(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- randomness[p_param] = p_value;
+ parameters_max[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_min(p_param, p_value);
+ }
}
-real_t CPUParticles2D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles2D::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return parameters_max[p_param];
}
static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
@@ -460,6 +466,31 @@ Vector2 CPUParticles2D::get_gravity() const {
return gravity;
}
+void CPUParticles2D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
+ scale_curve_x = p_scale_curve;
+}
+
+void CPUParticles2D::set_scale_curve_y(Ref<Curve> p_scale_curve) {
+ scale_curve_y = p_scale_curve;
+}
+
+void CPUParticles2D::set_split_scale(bool p_split_scale) {
+ split_scale = p_split_scale;
+ notify_property_list_changed();
+}
+
+Ref<Curve> CPUParticles2D::get_scale_curve_x() const {
+ return scale_curve_x;
+}
+
+Ref<Curve> CPUParticles2D::get_scale_curve_y() const {
+ return scale_curve_y;
+}
+
+bool CPUParticles2D::get_split_scale() {
+ return split_scale;
+}
+
void CPUParticles2D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
property.usage = PROPERTY_USAGE_NONE;
@@ -484,6 +515,9 @@ void CPUParticles2D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) {
property.usage = PROPERTY_USAGE_NONE;
}
+ if (property.name.begins_with("scale_curve_") && !split_scale) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
}
static uint32_t idhash(uint32_t x) {
@@ -695,14 +729,14 @@ void CPUParticles2D::_particles_process(double p_delta) {
real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad));
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], Math::randf());
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
p.rotation = Math::deg2rad(base_angle);
p.custom[0] = 0.0; // unused
p.custom[1] = 0.0; // phase [0..1]
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1]
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand);
p.custom[3] = 0.0;
p.transform = Transform2D();
p.time = 0;
@@ -766,51 +800,51 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.custom[1] = p.time / lifetime;
tv = p.time / p.lifetime;
- real_t tex_linear_velocity = 0.0;
+ real_t tex_linear_velocity = 1.0;
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv);
}
- real_t tex_orbit_velocity = 0.0;
+ real_t tex_orbit_velocity = 1.0;
if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv);
}
- real_t tex_angular_velocity = 0.0;
+ real_t tex_angular_velocity = 1.0;
if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv);
}
- real_t tex_linear_accel = 0.0;
+ real_t tex_linear_accel = 1.0;
if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv);
}
- real_t tex_tangential_accel = 0.0;
+ real_t tex_tangential_accel = 1.0;
if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv);
}
- real_t tex_radial_accel = 0.0;
+ real_t tex_radial_accel = 1.0;
if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv);
}
- real_t tex_damping = 0.0;
+ real_t tex_damping = 1.0;
if (curve_parameters[PARAM_DAMPING].is_valid()) {
tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv);
}
- real_t tex_angle = 0.0;
+ real_t tex_angle = 1.0;
if (curve_parameters[PARAM_ANGLE].is_valid()) {
tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv);
}
- real_t tex_anim_speed = 0.0;
+ real_t tex_anim_speed = 1.0;
if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) {
tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv);
}
- real_t tex_anim_offset = 0.0;
+ real_t tex_anim_offset = 1.0;
if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) {
tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv);
}
@@ -819,18 +853,18 @@ void CPUParticles2D::_particles_process(double p_delta) {
Vector2 pos = p.transform[2];
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector2();
//apply radial acceleration
Vector2 org = emission_xform[2];
Vector2 diff = pos - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2();
+ force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector2();
//apply tangential acceleration;
Vector2 yx = Vector2(diff.y, diff.x);
- force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2();
+ force += yx.length() > 0.0 ? yx.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector2();
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
- real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
@@ -843,9 +877,9 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.velocity = p.velocity.normalized() * tex_linear_velocity;
}
- if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
+ if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
real_t v = p.velocity.length();
- real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector2();
@@ -853,18 +887,32 @@ void CPUParticles2D::_particles_process(double p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
+ base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
p.rotation = Math::deg2rad(base_angle); //angle
- real_t animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]);
- p.custom[2] = animation_phase;
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + p.custom[1] * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed));
}
//apply color
//apply hue rotation
- real_t tex_scale = 1.0;
- if (curve_parameters[PARAM_SCALE].is_valid()) {
- tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ Vector2 tex_scale = Vector2(1.0, 1.0);
+ if (split_scale) {
+ if (scale_curve_x.is_valid()) {
+ tex_scale.x = scale_curve_x->interpolate(tv);
+ } else {
+ tex_scale.x = 1.0;
+ }
+ if (scale_curve_y.is_valid()) {
+ tex_scale.y = scale_curve_y->interpolate(tv);
+ } else {
+ tex_scale.y = 1.0;
+ }
+ } else {
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ real_t tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ tex_scale.x = tmp_scale;
+ tex_scale.y = tmp_scale;
+ }
}
real_t tex_hue_variation = 0.0;
@@ -872,7 +920,7 @@ void CPUParticles2D::_particles_process(double p_delta) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
real_t hue_rot_c = Math::cos(hue_rot_angle);
real_t hue_rot_s = Math::sin(hue_rot_angle);
@@ -912,13 +960,15 @@ void CPUParticles2D::_particles_process(double p_delta) {
}
//scale by scale
- real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale < 0.000001) {
- base_scale = 0.000001;
+ Vector2 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand);
+ if (base_scale.x < 0.00001) {
+ base_scale.x = 0.00001;
}
-
- p.transform.elements[0] *= base_scale;
- p.transform.elements[1] *= base_scale;
+ if (base_scale.y < 0.00001) {
+ base_scale.y = 0.00001;
+ }
+ p.transform.elements[0] *= base_scale.x;
+ p.transform.elements[1] *= base_scale.y;
p.transform[2] += p.velocity * local_delta;
}
@@ -1130,18 +1180,24 @@ void CPUParticles2D::convert_from_particles(Node *p_particles) {
Vector2 rect_extents = Vector2(material->get_emission_box_extents().x, material->get_emission_box_extents().y);
set_emission_rect_extents(rect_extents);
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ if (scale3D.is_valid()) {
+ split_scale = true;
+ scale_curve_x = scale3D->get_curve_x();
+ scale_curve_y = scale3D->get_curve_y();
+ }
Vector2 gravity = Vector2(material->get_gravity().x, material->get_gravity().y);
set_gravity(gravity);
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
- set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
- set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+ set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
@@ -1224,11 +1280,11 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_spread", "degrees"), &CPUParticles2D::set_spread);
ClassDB::bind_method(D_METHOD("get_spread"), &CPUParticles2D::get_spread);
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles2D::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles2D::get_param);
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles2D::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &CPUParticles2D::get_param_min);
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles2D::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles2D::get_param_randomness);
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &CPUParticles2D::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &CPUParticles2D::get_param_max);
ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles2D::set_param_curve);
ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles2D::get_param_curve);
@@ -1263,6 +1319,15 @@ void CPUParticles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles2D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles2D::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_split_scale"), &CPUParticles2D::get_split_scale);
+ ClassDB::bind_method(D_METHOD("set_split_scale", "split_scale"), &CPUParticles2D::set_split_scale);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_x"), &CPUParticles2D::get_scale_curve_x);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_x", "scale_curve"), &CPUParticles2D::set_scale_curve_x);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_y"), &CPUParticles2D::get_scale_curve_y);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_y", "scale_curve"), &CPUParticles2D::set_scale_curve_y);
+
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles2D::convert_from_particles);
ADD_GROUP("Emission Shape", "emission_");
@@ -1280,54 +1345,58 @@ void CPUParticles2D::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_x", "get_scale_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_y", "get_scale_curve_y");
+
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
@@ -1366,22 +1435,31 @@ CPUParticles2D::CPUParticles2D() {
set_amount(8);
set_use_local_coordinates(true);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
- set_param(PARAM_ANGULAR_VELOCITY, 0);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
-
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
+ set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_min(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_min(PARAM_ORBIT_VELOCITY, 0);
+ set_param_min(PARAM_LINEAR_ACCEL, 0);
+ set_param_min(PARAM_RADIAL_ACCEL, 0);
+ set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_min(PARAM_DAMPING, 0);
+ set_param_min(PARAM_ANGLE, 0);
+ set_param_min(PARAM_SCALE, 1);
+ set_param_min(PARAM_HUE_VARIATION, 0);
+ set_param_min(PARAM_ANIM_SPEED, 0);
+ set_param_min(PARAM_ANIM_OFFSET, 0);
+
+ set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_max(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_max(PARAM_ORBIT_VELOCITY, 0);
+ set_param_max(PARAM_LINEAR_ACCEL, 0);
+ set_param_max(PARAM_RADIAL_ACCEL, 0);
+ set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_max(PARAM_DAMPING, 0);
+ set_param_max(PARAM_ANGLE, 0);
+ set_param_max(PARAM_SCALE, 1);
+ set_param_max(PARAM_HUE_VARIATION, 0);
+ set_param_max(PARAM_ANIM_SPEED, 0);
+ set_param_max(PARAM_ANIM_OFFSET, 0);
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
particle_flags[i] = false;
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 0f8950375f..4990d443e3 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -150,8 +150,8 @@ private:
Vector2 direction = Vector2(1, 0);
real_t spread = 45.0;
- real_t parameters[PARAM_MAX];
- real_t randomness[PARAM_MAX];
+ real_t parameters_min[PARAM_MAX];
+ real_t parameters_max[PARAM_MAX];
Ref<Curve> curve_parameters[PARAM_MAX];
Color color;
@@ -167,6 +167,10 @@ private:
Vector<Color> emission_colors;
int emission_point_count = 0;
+ Ref<Curve> scale_curve_x;
+ Ref<Curve> scale_curve_y;
+ bool split_scale = false;
+
Vector2 gravity = Vector2(0, 980);
void _update_internal();
@@ -236,11 +240,11 @@ public:
void set_spread(real_t p_spread);
real_t get_spread() const;
- void set_param(Parameter p_param, real_t p_value);
- real_t get_param(Parameter p_param) const;
+ void set_param_min(Parameter p_param, real_t p_value);
+ real_t get_param_min(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, real_t p_value);
- real_t get_param_randomness(Parameter p_param) const;
+ void set_param_max(Parameter p_param, real_t p_value);
+ real_t get_param_max(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -261,6 +265,9 @@ public:
void set_emission_normals(const Vector<Vector2> &p_normals);
void set_emission_colors(const Vector<Color> &p_colors);
void set_emission_point_count(int p_count);
+ void set_scale_curve_x(Ref<Curve> p_scale_curve);
+ void set_scale_curve_y(Ref<Curve> p_scale_curve);
+ void set_split_scale(bool p_split_scale);
EmissionShape get_emission_shape() const;
real_t get_emission_sphere_radius() const;
@@ -269,6 +276,9 @@ public:
Vector<Vector2> get_emission_normals() const;
Vector<Color> get_emission_colors() const;
int get_emission_point_count() const;
+ Ref<Curve> get_scale_curve_x() const;
+ Ref<Curve> get_scale_curve_y() const;
+ bool get_split_scale();
void set_gravity(const Vector2 &p_gravity);
Vector2 get_gravity() const;
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 47bf1bc77c..5bce705dd5 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -295,7 +295,7 @@ TypedArray<String> GPUParticles2D::get_configuration_warnings() const {
if (get_material().is_null() || (mat && !mat->get_particles_animation())) {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (process &&
- (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("Particles2D animation requires the usage of a CanvasItemMaterial with \"Particles Animation\" enabled."));
}
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 13ed4af04e..a9d4877cbb 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -529,9 +529,9 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
sleeping = state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- if (get_script_instance()) {
- get_script_instance()->call("_integrate_forces", state);
- }
+
+ GDVIRTUAL_CALL(_integrate_forces, state);
+
set_block_transform_notify(false); // want it back
if (contact_monitor) {
@@ -978,7 +978,7 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies);
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D")));
+ GDVIRTUAL_BIND(_integrate_forces, "state");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass");
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 302a2148be..a999317953 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -189,6 +189,8 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState2D *)
+
public:
void set_mode(Mode p_mode);
Mode get_mode() const;
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 12aa1afc45..13f1d258a8 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1051,9 +1051,13 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
Vector2 quadrant_pos = map_to_world(q.coords * get_effective_quadrant_size(q.layer));
+ LocalVector<int> body_shape_count;
+ body_shape_count.resize(q.bodies.size());
+
// Clear shapes.
for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
ps->body_clear_shapes(q.bodies[body_index]);
+ body_shape_count[body_index] = 0;
// Position the bodies.
Transform2D xform;
@@ -1078,6 +1082,8 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile));
for (int body_index = 0; body_index < q.bodies.size(); body_index++) {
+ int &body_shape_index = body_shape_count[body_index];
+
// Add the shapes again.
for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) {
bool one_way_collision = tile_data->is_collision_polygon_one_way(body_index, polygon_index);
@@ -1091,8 +1097,10 @@ void TileMap::_physics_update_dirty_quadrants(SelfList<TileMapQuadrant>::List &r
// Add decomposed convex shapes.
Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(body_index, polygon_index, shape_index);
ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform);
- ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get());
- ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin);
+ ps->body_set_shape_metadata(q.bodies[body_index], body_shape_index, E_cell->get());
+ ps->body_set_shape_as_one_way_collision(q.bodies[body_index], body_shape_index, one_way_collision, one_way_collision_margin);
+
+ ++body_shape_index;
}
}
}
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 00e4e1dc62..8bd7b696f2 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -185,7 +185,7 @@ String TouchScreenButton::get_action() const {
return action;
}
-void TouchScreenButton::_input(const Ref<InputEvent> &p_event) {
+void TouchScreenButton::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!get_tree()) {
@@ -288,7 +288,7 @@ void TouchScreenButton::_press(int p_finger_pressed) {
iea.instantiate();
iea->set_action(action);
iea->set_pressed(true);
- get_viewport()->input(iea, true);
+ get_viewport()->push_input(iea, true);
}
emit_signal(SNAME("pressed"));
@@ -305,7 +305,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
iea.instantiate();
iea->set_action(action);
iea->set_pressed(false);
- get_viewport()->input(iea, true);
+ get_viewport()->push_input(iea, true);
}
}
@@ -384,8 +384,6 @@ void TouchScreenButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_pressed"), &TouchScreenButton::is_pressed);
- ClassDB::bind_method(D_METHOD("_input"), &TouchScreenButton::_input);
-
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "pressed", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture_pressed", "get_texture_pressed");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "bitmask", PROPERTY_HINT_RESOURCE_TYPE, "BitMap"), "set_bitmask", "get_bitmask");
diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h
index 10820ad059..1c515149d4 100644
--- a/scene/2d/touch_screen_button.h
+++ b/scene/2d/touch_screen_button.h
@@ -61,7 +61,7 @@ private:
VisibilityMode visibility = VISIBILITY_ALWAYS;
- void _input(const Ref<InputEvent> &p_event);
+ virtual void input(const Ref<InputEvent> &p_event) override;
bool _is_point_inside(const Point2 &p_point);
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index 2e917c4a42..943586f43c 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -105,6 +105,61 @@ real_t Area3D::get_priority() const {
return priority;
}
+void Area3D::set_wind_force_magnitude(real_t p_wind_force_magnitude) {
+ wind_force_magnitude = p_wind_force_magnitude;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+real_t Area3D::get_wind_force_magnitude() const {
+ return wind_force_magnitude;
+}
+
+void Area3D::set_wind_attenuation_factor(real_t p_wind_force_attenuation_factor) {
+ wind_attenuation_factor = p_wind_force_attenuation_factor;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+real_t Area3D::get_wind_attenuation_factor() const {
+ return wind_attenuation_factor;
+}
+
+void Area3D::set_wind_source_path(const NodePath &p_wind_source_path) {
+ wind_source_path = p_wind_source_path;
+ if (is_inside_tree()) {
+ _initialize_wind();
+ }
+}
+
+const NodePath &Area3D::get_wind_source_path() const {
+ return wind_source_path;
+}
+
+void Area3D::_initialize_wind() {
+ real_t temp_magnitude = 0.0;
+ Vector3 wind_direction(0., 0., 0.);
+ Vector3 wind_source(0., 0., 0.);
+
+ // Overwrite with area-specified info if available
+ if (!wind_source_path.is_empty()) {
+ Node3D *p_wind_source = Object::cast_to<Node3D>(get_node(wind_source_path));
+ ERR_FAIL_NULL(p_wind_source);
+ Transform3D global_transform = p_wind_source->get_transform();
+ wind_direction = -global_transform.basis.get_axis(Vector3::AXIS_Z).normalized();
+ wind_source = global_transform.origin;
+ temp_magnitude = wind_force_magnitude;
+ }
+
+ // Set force, source and direction in the physics server.
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_ATTENUATION_FACTOR, wind_attenuation_factor);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_SOURCE, wind_source);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_DIRECTION, wind_direction);
+ PhysicsServer3D::get_singleton()->area_set_param(get_rid(), PhysicsServer3D::AREA_PARAM_WIND_FORCE_MAGNITUDE, temp_magnitude);
+}
+
void Area3D::_body_enter_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
@@ -264,6 +319,8 @@ void Area3D::_clear_monitoring() {
void Area3D::_notification(int p_what) {
if (p_what == NOTIFICATION_EXIT_TREE) {
_clear_monitoring();
+ } else if (p_what == NOTIFICATION_ENTER_TREE) {
+ _initialize_wind();
}
}
@@ -550,6 +607,15 @@ void Area3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &Area3D::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &Area3D::get_priority);
+ ClassDB::bind_method(D_METHOD("set_wind_force_magnitude", "wind_force_magnitude"), &Area3D::set_wind_force_magnitude);
+ ClassDB::bind_method(D_METHOD("get_wind_force_magnitude"), &Area3D::get_wind_force_magnitude);
+
+ ClassDB::bind_method(D_METHOD("set_wind_attenuation_factor", "wind_attenuation_factor"), &Area3D::set_wind_attenuation_factor);
+ ClassDB::bind_method(D_METHOD("get_wind_attenuation_factor"), &Area3D::get_wind_attenuation_factor);
+
+ ClassDB::bind_method(D_METHOD("set_wind_source_path", "wind_source_path"), &Area3D::set_wind_source_path);
+ ClassDB::bind_method(D_METHOD("get_wind_source_path"), &Area3D::get_wind_source_path);
+
ClassDB::bind_method(D_METHOD("set_monitorable", "enable"), &Area3D::set_monitorable);
ClassDB::bind_method(D_METHOD("is_monitorable"), &Area3D::is_monitorable);
@@ -605,6 +671,9 @@ void Area3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-32,32,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_force_magnitude", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater"), "set_wind_force_magnitude", "get_wind_force_magnitude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wind_attenuation_factor", PROPERTY_HINT_RANGE, "0.0,3.0,0.001,or_greater"), "set_wind_attenuation_factor", "get_wind_attenuation_factor");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "wind_source_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_wind_source_path", "get_wind_source_path");
ADD_GROUP("Audio Bus", "audio_bus_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_bus_override"), "set_audio_bus_override", "is_overriding_audio_bus");
diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h
index 5b8d612717..847d1c5966 100644
--- a/scene/3d/area_3d.h
+++ b/scene/3d/area_3d.h
@@ -55,6 +55,9 @@ private:
real_t angular_damp = 0.1;
real_t linear_damp = 0.1;
int priority = 0;
+ real_t wind_force_magnitude = 0.0;
+ real_t wind_attenuation_factor = 0.0;
+ NodePath wind_source_path;
bool monitoring = false;
bool monitorable = false;
bool locked = false;
@@ -134,6 +137,8 @@ private:
void _validate_property(PropertyInfo &property) const override;
+ void _initialize_wind();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -163,6 +168,15 @@ public:
void set_priority(real_t p_priority);
real_t get_priority() const;
+ void set_wind_force_magnitude(real_t p_wind_force_magnitude);
+ real_t get_wind_force_magnitude() const;
+
+ void set_wind_attenuation_factor(real_t p_wind_attenuation_factor);
+ real_t get_wind_attenuation_factor() const;
+
+ void set_wind_source_path(const NodePath &p_wind_source_path);
+ const NodePath &get_wind_source_path() const;
+
void set_monitoring(bool p_enable);
bool is_monitoring() const;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index d2424c9a3b..3b44580264 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -624,8 +624,12 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) {
}
if (p_stream.is_valid()) {
- stream = p_stream;
stream_playback = p_stream->instance_playback();
+ if (stream_playback.is_valid()) {
+ stream = p_stream;
+ } else {
+ stream.unref();
+ }
}
AudioServer::get_singleton()->unlock();
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 36d9bfba82..e2f953974a 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -254,10 +254,8 @@ void CollisionObject3D::_apply_enabled() {
}
}
-void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
- }
+void CollisionObject3D::_input_event_call(Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) {
+ GDVIRTUAL_CALL(_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
emit_signal(SceneStringNames::get_singleton()->input_event, p_camera, p_input_event, p_pos, p_normal, p_shape);
}
@@ -453,7 +451,7 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes);
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
- BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
+ GDVIRTUAL_BIND(_input_event, "camera", "event", "position", "normal", "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index c066960eb4..1c7e205888 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -31,6 +31,7 @@
#ifndef COLLISION_OBJECT_3D_H
#define COLLISION_OBJECT_3D_H
+#include "scene/3d/camera_3d.h"
#include "scene/3d/node_3d.h"
class CollisionObject3D : public Node3D {
@@ -101,7 +102,7 @@ protected:
void _on_transform_changed();
friend class Viewport;
- virtual void _input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
+ virtual void _input_event_call(Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape);
virtual void _mouse_enter();
virtual void _mouse_exit();
@@ -110,6 +111,7 @@ protected:
void set_only_update_transform_changes(bool p_enable);
bool is_only_update_transform_changes_enabled() const;
+ GDVIRTUAL5(_input_event, Camera3D *, Ref<InputEvent>, Vector3, Vector3, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp
index e2095940ff..48ef41e015 100644
--- a/scene/3d/cpu_particles_3d.cpp
+++ b/scene/3d/cpu_particles_3d.cpp
@@ -212,7 +212,7 @@ TypedArray<String> CPUParticles3D::get_configuration_warnings() const {
warnings.push_back(TTR("Nothing is visible because no mesh has been assigned."));
}
- if (!anim_material_found && (get_param(PARAM_ANIM_SPEED) != 0.0 || get_param(PARAM_ANIM_OFFSET) != 0.0 ||
+ if (!anim_material_found && (get_param_max(PARAM_ANIM_SPEED) != 0.0 || get_param_max(PARAM_ANIM_OFFSET) != 0.0 ||
get_param_curve(PARAM_ANIM_SPEED).is_valid() || get_param_curve(PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("CPUParticles3D animation requires the usage of a StandardMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
@@ -263,28 +263,33 @@ real_t CPUParticles3D::get_flatness() const {
return flatness;
}
-void CPUParticles3D::set_param(Parameter p_param, real_t p_value) {
+void CPUParticles3D::set_param_min(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- parameters[p_param] = p_value;
+ parameters_min[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_max(p_param, p_value);
+ }
}
-real_t CPUParticles3D::get_param(Parameter p_param) const {
+real_t CPUParticles3D::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return parameters[p_param];
+ return parameters_min[p_param];
}
-void CPUParticles3D::set_param_randomness(Parameter p_param, real_t p_value) {
+void CPUParticles3D::set_param_max(Parameter p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
-
- randomness[p_param] = p_value;
+ parameters_max[p_param] = p_value;
+ if (parameters_min[p_param] > parameters_max[p_param]) {
+ set_param_min(p_param, p_value);
+ }
}
-real_t CPUParticles3D::get_param_randomness(Parameter p_param) const {
+real_t CPUParticles3D::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return parameters_max[p_param];
}
static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) {
@@ -417,6 +422,23 @@ void CPUParticles3D::set_emission_ring_inner_radius(real_t p_radius) {
emission_ring_inner_radius = p_radius;
}
+void CPUParticles3D::set_scale_curve_x(Ref<Curve> p_scale_curve) {
+ scale_curve_x = p_scale_curve;
+}
+
+void CPUParticles3D::set_scale_curve_y(Ref<Curve> p_scale_curve) {
+ scale_curve_y = p_scale_curve;
+}
+
+void CPUParticles3D::set_scale_curve_z(Ref<Curve> p_scale_curve) {
+ scale_curve_z = p_scale_curve;
+}
+
+void CPUParticles3D::set_split_scale(bool p_split_scale) {
+ split_scale = p_split_scale;
+ notify_property_list_changed();
+}
+
real_t CPUParticles3D::get_emission_sphere_radius() const {
return emission_sphere_radius;
}
@@ -465,6 +487,22 @@ Vector3 CPUParticles3D::get_gravity() const {
return gravity;
}
+Ref<Curve> CPUParticles3D::get_scale_curve_x() const {
+ return scale_curve_x;
+}
+
+Ref<Curve> CPUParticles3D::get_scale_curve_y() const {
+ return scale_curve_y;
+}
+
+Ref<Curve> CPUParticles3D::get_scale_curve_z() const {
+ return scale_curve_z;
+}
+
+bool CPUParticles3D::get_split_scale() {
+ return split_scale;
+}
+
void CPUParticles3D::_validate_property(PropertyInfo &property) const {
if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) {
property.usage = PROPERTY_USAGE_NONE;
@@ -489,6 +527,10 @@ void CPUParticles3D::_validate_property(PropertyInfo &property) const {
if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
property.usage = PROPERTY_USAGE_NONE;
}
+
+ if (property.name.begins_with("scale_curve_") && !split_scale) {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
}
static uint32_t idhash(uint32_t x) {
@@ -707,7 +749,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread);
Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0);
- p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = rot * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], Math::randf());
} else {
//initiate velocity spread in 3D
real_t angle1_rad = Math::deg2rad((Math::randf() * (real_t)2.0 - (real_t)1.0) * spread);
@@ -731,13 +773,13 @@ void CPUParticles3D::_particles_process(double p_delta) {
binormal.normalize();
Vector3 normal = binormal.cross(direction_nrm);
spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;
- p.velocity = spread_direction * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]);
+ p.velocity = spread_direction * Math::lerp(parameters_min[PARAM_INITIAL_LINEAR_VELOCITY], parameters_max[PARAM_INITIAL_LINEAR_VELOCITY], float(Math::randf()));
}
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
+ real_t base_angle = tex_angle * Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
p.custom[0] = Math::deg2rad(base_angle); //angle
p.custom[1] = 0.0; //phase
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1)
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand); //animation offset (0-1)
p.transform = Transform3D();
p.time = 0;
p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness);
@@ -894,26 +936,25 @@ void CPUParticles3D::_particles_process(double p_delta) {
position.z = 0.0;
}
//apply linear acceleration
- force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector3();
+ force += p.velocity.length() > 0.0 ? p.velocity.normalized() * tex_linear_accel * Math::lerp(parameters_min[PARAM_LINEAR_ACCEL], parameters_max[PARAM_LINEAR_ACCEL], rand_from_seed(alt_seed)) : Vector3();
//apply radial acceleration
Vector3 org = emission_xform.origin;
Vector3 diff = position - org;
- force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector3();
- //apply tangential acceleration;
+ force += diff.length() > 0.0 ? diff.normalized() * (tex_radial_accel)*Math::lerp(parameters_min[PARAM_RADIAL_ACCEL], parameters_max[PARAM_RADIAL_ACCEL], rand_from_seed(alt_seed)) : Vector3();
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
Vector2 yx = Vector2(diff.y, diff.x);
Vector2 yx2 = (yx * Vector2(-1.0, 1.0)).normalized();
- force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ force += yx.length() > 0.0 ? Vector3(yx2.x, yx2.y, 0.0) * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
} else {
Vector3 crossDiff = diff.normalized().cross(gravity.normalized());
- force += crossDiff.length() > 0.0 ? crossDiff.normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector3();
+ force += crossDiff.length() > 0.0 ? crossDiff.normalized() * (tex_tangential_accel * Math::lerp(parameters_min[PARAM_TANGENTIAL_ACCEL], parameters_max[PARAM_TANGENTIAL_ACCEL], rand_from_seed(alt_seed))) : Vector3();
}
//apply attractor forces
p.velocity += force * local_delta;
//orbit velocity
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]);
+ real_t orbit_amount = tex_orbit_velocity * Math::lerp(parameters_min[PARAM_ORBIT_VELOCITY], parameters_max[PARAM_ORBIT_VELOCITY], rand_from_seed(alt_seed));
if (orbit_amount != 0.0) {
real_t ang = orbit_amount * local_delta * Math_TAU;
// Not sure why the ParticlesMaterial code uses a clockwise rotation matrix,
@@ -927,9 +968,10 @@ void CPUParticles3D::_particles_process(double p_delta) {
if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
p.velocity = p.velocity.normalized() * tex_linear_velocity;
}
- if (parameters[PARAM_DAMPING] + tex_damping > 0.0) {
+
+ if (parameters_max[PARAM_DAMPING] + tex_damping > 0.0) {
real_t v = p.velocity.length();
- real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]);
+ real_t damp = tex_damping * Math::lerp(parameters_min[PARAM_DAMPING], parameters_max[PARAM_DAMPING], rand_from_seed(alt_seed));
v -= damp * local_delta;
if (v < 0.0) {
p.velocity = Vector3();
@@ -937,17 +979,38 @@ void CPUParticles3D::_particles_process(double p_delta) {
p.velocity = p.velocity.normalized() * v;
}
}
- real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]);
- base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]);
+ real_t base_angle = (tex_angle)*Math::lerp(parameters_min[PARAM_ANGLE], parameters_max[PARAM_ANGLE], p.angle_rand);
+ base_angle += p.custom[1] * lifetime * tex_angular_velocity * Math::lerp(parameters_min[PARAM_ANGULAR_VELOCITY], parameters_max[PARAM_ANGULAR_VELOCITY], rand_from_seed(alt_seed));
p.custom[0] = Math::deg2rad(base_angle); //angle
- p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); //angle
+ p.custom[2] = tex_anim_offset * Math::lerp(parameters_min[PARAM_ANIM_OFFSET], parameters_max[PARAM_ANIM_OFFSET], p.anim_offset_rand) + p.custom[1] * tex_anim_speed * Math::lerp(parameters_min[PARAM_ANIM_SPEED], parameters_max[PARAM_ANIM_SPEED], rand_from_seed(alt_seed)); //angle
}
//apply color
//apply hue rotation
- real_t tex_scale = 1.0;
- if (curve_parameters[PARAM_SCALE].is_valid()) {
- tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ Vector3 tex_scale = Vector3(1.0, 1.0, 1.0);
+ if (split_scale) {
+ if (scale_curve_x.is_valid()) {
+ tex_scale.x = scale_curve_x->interpolate(tv);
+ } else {
+ tex_scale.x = 1.0;
+ }
+ if (scale_curve_y.is_valid()) {
+ tex_scale.y = scale_curve_y->interpolate(tv);
+ } else {
+ tex_scale.y = 1.0;
+ }
+ if (scale_curve_z.is_valid()) {
+ tex_scale.z = scale_curve_z->interpolate(tv);
+ } else {
+ tex_scale.z = 1.0;
+ }
+ } else {
+ if (curve_parameters[PARAM_SCALE].is_valid()) {
+ float tmp_scale = curve_parameters[PARAM_SCALE]->interpolate(tv);
+ tex_scale.x = tmp_scale;
+ tex_scale.y = tmp_scale;
+ tex_scale.z = tmp_scale;
+ }
}
real_t tex_hue_variation = 0.0;
@@ -955,7 +1018,7 @@ void CPUParticles3D::_particles_process(double p_delta) {
tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv);
}
- real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]);
+ real_t hue_rot_angle = (tex_hue_variation)*Math_TAU * Math::lerp(parameters_min[PARAM_HUE_VARIATION], parameters_max[PARAM_HUE_VARIATION], p.hue_rot_rand);
real_t hue_rot_c = Math::cos(hue_rot_angle);
real_t hue_rot_s = Math::sin(hue_rot_angle);
@@ -1025,13 +1088,21 @@ void CPUParticles3D::_particles_process(double p_delta) {
}
}
+ p.transform.basis = p.transform.basis.orthonormalized();
//scale by scale
- real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]);
- if (base_scale < CMP_EPSILON) {
- base_scale = CMP_EPSILON;
+
+ Vector3 base_scale = tex_scale * Math::lerp(parameters_min[PARAM_SCALE], parameters_max[PARAM_SCALE], p.scale_rand);
+ if (base_scale.x < CMP_EPSILON) {
+ base_scale.x = CMP_EPSILON;
+ }
+ if (base_scale.y < CMP_EPSILON) {
+ base_scale.y = CMP_EPSILON;
+ }
+ if (base_scale.z < CMP_EPSILON) {
+ base_scale.z = CMP_EPSILON;
}
- p.transform.basis.scale(Vector3(1, 1, 1) * base_scale);
+ p.transform.basis.scale(base_scale);
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
p.velocity.z = 0.0;
@@ -1267,18 +1338,25 @@ void CPUParticles3D::convert_from_particles(Node *p_particles) {
set_emission_shape(EmissionShape(material->get_emission_shape()));
set_emission_sphere_radius(material->get_emission_sphere_radius());
set_emission_box_extents(material->get_emission_box_extents());
+ Ref<CurveXYZTexture> scale3D = material->get_param_texture(ParticlesMaterial::PARAM_SCALE);
+ if (scale3D.is_valid()) {
+ split_scale = true;
+ scale_curve_x = scale3D->get_curve_x();
+ scale_curve_y = scale3D->get_curve_y();
+ scale_curve_z = scale3D->get_curve_z();
+ }
set_gravity(material->get_gravity());
set_lifetime_randomness(material->get_lifetime_randomness());
#define CONVERT_PARAM(m_param) \
- set_param(m_param, material->get_param(ParticlesMaterial::m_param)); \
+ set_param_min(m_param, material->get_param_min(ParticlesMaterial::m_param)); \
{ \
Ref<CurveTexture> ctex = material->get_param_texture(ParticlesMaterial::m_param); \
if (ctex.is_valid()) \
set_param_curve(m_param, ctex->get_curve()); \
} \
- set_param_randomness(m_param, material->get_param_randomness(ParticlesMaterial::m_param));
+ set_param_max(m_param, material->get_param_max(ParticlesMaterial::m_param));
CONVERT_PARAM(PARAM_INITIAL_LINEAR_VELOCITY);
CONVERT_PARAM(PARAM_ANGULAR_VELOCITY);
@@ -1364,11 +1442,11 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &CPUParticles3D::set_flatness);
ClassDB::bind_method(D_METHOD("get_flatness"), &CPUParticles3D::get_flatness);
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &CPUParticles3D::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &CPUParticles3D::get_param);
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &CPUParticles3D::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &CPUParticles3D::get_param_min);
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &CPUParticles3D::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &CPUParticles3D::get_param_randomness);
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &CPUParticles3D::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &CPUParticles3D::get_param_max);
ClassDB::bind_method(D_METHOD("set_param_curve", "param", "curve"), &CPUParticles3D::set_param_curve);
ClassDB::bind_method(D_METHOD("get_param_curve", "param"), &CPUParticles3D::get_param_curve);
@@ -1415,6 +1493,18 @@ void CPUParticles3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gravity"), &CPUParticles3D::get_gravity);
ClassDB::bind_method(D_METHOD("set_gravity", "accel_vec"), &CPUParticles3D::set_gravity);
+ ClassDB::bind_method(D_METHOD("get_split_scale"), &CPUParticles3D::get_split_scale);
+ ClassDB::bind_method(D_METHOD("set_split_scale", "split_scale"), &CPUParticles3D::set_split_scale);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_x"), &CPUParticles3D::get_scale_curve_x);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_x", "scale_curve"), &CPUParticles3D::set_scale_curve_x);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_y"), &CPUParticles3D::get_scale_curve_y);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_y", "scale_curve"), &CPUParticles3D::set_scale_curve_y);
+
+ ClassDB::bind_method(D_METHOD("get_scale_curve_z"), &CPUParticles3D::get_scale_curve_z);
+ ClassDB::bind_method(D_METHOD("set_scale_curve_z", "scale_curve"), &CPUParticles3D::set_scale_curve_z);
+
ClassDB::bind_method(D_METHOD("convert_from_particles", "particles"), &CPUParticles3D::convert_from_particles);
ADD_GROUP("Emission Shape", "emission_");
@@ -1439,54 +1529,58 @@ void CPUParticles3D::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_min", "get_param_min", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_amount_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_amount_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_SCALE);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "split_scale"), "set_split_scale", "get_split_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_x", "get_scale_curve_x");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_y", "get_scale_curve_y");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "scale_curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_scale_curve_z", "get_scale_curve_z");
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater,or_lesser"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANIM_OFFSET);
BIND_ENUM_CONSTANT(PARAM_INITIAL_LINEAR_VELOCITY);
@@ -1527,18 +1621,30 @@ CPUParticles3D::CPUParticles3D() {
set_emitting(true);
set_amount(8);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
- set_param(PARAM_ANGULAR_VELOCITY, 0);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
+ set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_min(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_min(PARAM_ORBIT_VELOCITY, 0);
+ set_param_min(PARAM_LINEAR_ACCEL, 0);
+ set_param_min(PARAM_RADIAL_ACCEL, 0);
+ set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_min(PARAM_DAMPING, 0);
+ set_param_min(PARAM_ANGLE, 0);
+ set_param_min(PARAM_SCALE, 1);
+ set_param_min(PARAM_HUE_VARIATION, 0);
+ set_param_min(PARAM_ANIM_SPEED, 0);
+ set_param_min(PARAM_ANIM_OFFSET, 0);
+ set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_max(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_max(PARAM_ORBIT_VELOCITY, 0);
+ set_param_max(PARAM_LINEAR_ACCEL, 0);
+ set_param_max(PARAM_RADIAL_ACCEL, 0);
+ set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_max(PARAM_DAMPING, 0);
+ set_param_max(PARAM_ANGLE, 0);
+ set_param_max(PARAM_SCALE, 1);
+ set_param_max(PARAM_HUE_VARIATION, 0);
+ set_param_max(PARAM_ANIM_SPEED, 0);
+ set_param_max(PARAM_ANIM_OFFSET, 0);
set_emission_shape(EMISSION_SHAPE_POINT);
set_emission_sphere_radius(1);
set_emission_box_extents(Vector3(1, 1, 1));
@@ -1549,10 +1655,6 @@ CPUParticles3D::CPUParticles3D() {
set_gravity(Vector3(0, -9.8, 0));
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
-
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
particle_flags[i] = false;
}
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 5b60322f05..160814ead4 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -154,8 +154,8 @@ private:
real_t spread = 45.0;
real_t flatness = 0.0;
- real_t parameters[PARAM_MAX];
- real_t randomness[PARAM_MAX] = {};
+ real_t parameters_min[PARAM_MAX];
+ real_t parameters_max[PARAM_MAX] = {};
Ref<Curve> curve_parameters[PARAM_MAX];
Color color = Color(1, 1, 1, 1);
@@ -175,6 +175,11 @@ private:
real_t emission_ring_radius;
real_t emission_ring_inner_radius;
+ Ref<Curve> scale_curve_x;
+ Ref<Curve> scale_curve_y;
+ Ref<Curve> scale_curve_z;
+ bool split_scale = false;
+
Vector3 gravity = Vector3(0, -9.8, 0);
void _update_internal();
@@ -246,11 +251,11 @@ public:
void set_flatness(real_t p_flatness);
real_t get_flatness() const;
- void set_param(Parameter p_param, real_t p_value);
- real_t get_param(Parameter p_param) const;
+ void set_param_min(Parameter p_param, real_t p_value);
+ real_t get_param_min(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, real_t p_value);
- real_t get_param_randomness(Parameter p_param) const;
+ void set_param_max(Parameter p_param, real_t p_value);
+ real_t get_param_max(Parameter p_param) const;
void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve);
Ref<Curve> get_param_curve(Parameter p_param) const;
@@ -275,6 +280,10 @@ public:
void set_emission_ring_height(real_t p_height);
void set_emission_ring_radius(real_t p_radius);
void set_emission_ring_inner_radius(real_t p_radius);
+ void set_scale_curve_x(Ref<Curve> p_scale_curve);
+ void set_scale_curve_y(Ref<Curve> p_scale_curve);
+ void set_scale_curve_z(Ref<Curve> p_scale_curve);
+ void set_split_scale(bool p_split_scale);
EmissionShape get_emission_shape() const;
real_t get_emission_sphere_radius() const;
@@ -287,6 +296,10 @@ public:
real_t get_emission_ring_height() const;
real_t get_emission_ring_radius() const;
real_t get_emission_ring_inner_radius() const;
+ Ref<Curve> get_scale_curve_x() const;
+ Ref<Curve> get_scale_curve_y() const;
+ Ref<Curve> get_scale_curve_z() const;
+ bool get_split_scale();
void set_gravity(const Vector3 &p_gravity);
Vector3 get_gravity() const;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index d56228df66..baf28ae102 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -312,7 +312,7 @@ TypedArray<String> GPUParticles3D::get_configuration_warnings() const {
} else {
const ParticlesMaterial *process = Object::cast_to<ParticlesMaterial>(process_material.ptr());
if (!anim_material_found && process &&
- (process->get_param(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
+ (process->get_param_max(ParticlesMaterial::PARAM_ANIM_SPEED) != 0.0 || process->get_param_max(ParticlesMaterial::PARAM_ANIM_OFFSET) != 0.0 ||
process->get_param_texture(ParticlesMaterial::PARAM_ANIM_SPEED).is_valid() || process->get_param_texture(ParticlesMaterial::PARAM_ANIM_OFFSET).is_valid())) {
warnings.push_back(TTR("Particles animation requires the usage of a BaseMaterial3D whose Billboard Mode is set to \"Particle Billboard\"."));
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 092efc55d7..d34331e1d8 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -599,9 +599,9 @@ void RigidBody3D::_direct_state_changed(Object *p_state) {
sleeping = state->is_sleeping();
emit_signal(SceneStringNames::get_singleton()->sleeping_state_changed);
}
- if (get_script_instance()) {
- get_script_instance()->call("_integrate_forces", state);
- }
+
+ GDVIRTUAL_CALL(_integrate_forces, state);
+
set_ignore_transform_notification(false);
_on_transform_changed();
@@ -1022,7 +1022,7 @@ void RigidBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies);
- BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D")));
+ GDVIRTUAL_BIND(_integrate_forces, "state");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass");
@@ -1080,8 +1080,6 @@ void RigidBody3D::_reload_physics_characteristics() {
#define FLOOR_ANGLE_THRESHOLD 0.01
bool CharacterBody3D::move_and_slide() {
- Vector3 body_velocity_normal = linear_velocity.normalized();
-
bool was_on_floor = on_floor;
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
@@ -1111,7 +1109,7 @@ bool CharacterBody3D::move_and_slide() {
floor_normal = Vector3();
floor_velocity = Vector3();
- if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) {
+ if (!current_floor_velocity.is_equal_approx(Vector3()) && on_floor_body.is_valid()) {
PhysicsServer3D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(on_floor_body);
@@ -1130,39 +1128,35 @@ bool CharacterBody3D::move_and_slide() {
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result;
- bool found_collision = false;
-
bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
- if (!collided) {
- motion = Vector3(); //clear because no collision happened and motion completed
- } else {
- found_collision = true;
-
+ if (collided) {
motion_results.push_back(result);
_set_collision_direction(result);
- if (on_floor && floor_stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
- Transform3D gt = get_global_transform();
- if (result.travel.length() > margin) {
- gt.origin -= result.travel.slide(up_direction);
- } else {
- gt.origin -= result.travel;
- }
- set_global_transform(gt);
- linear_velocity = Vector3();
- return true;
+ if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
+ Transform3D gt = get_global_transform();
+ if (result.travel.length() > margin) {
+ gt.origin -= result.travel.slide(up_direction);
+ } else {
+ gt.origin -= result.travel;
}
+ set_global_transform(gt);
+ linear_velocity = Vector3();
+ motion = Vector3();
+ break;
}
- if (sliding_enabled || !on_floor) {
- motion = result.remainder.slide(result.collision_normal);
- linear_velocity = linear_velocity.slide(result.collision_normal);
+ if (result.remainder.is_equal_approx(Vector3())) {
+ motion = Vector3();
+ break;
+ }
- for (int j = 0; j < 3; j++) {
- if (locked_axis & (1 << j)) {
- linear_velocity[j] = 0.0;
- }
+ if (sliding_enabled || !on_floor) {
+ Vector3 slide_motion = result.remainder.slide(result.collision_normal);
+ if (slide_motion.dot(linear_velocity) > 0.0) {
+ motion = slide_motion;
+ } else {
+ motion = Vector3();
}
} else {
motion = result.remainder;
@@ -1171,12 +1165,12 @@ bool CharacterBody3D::move_and_slide() {
sliding_enabled = true;
- if (!found_collision || motion == Vector3()) {
+ if (!collided || motion.is_equal_approx(Vector3())) {
break;
}
}
- if (was_on_floor && snap != Vector3()) {
+ if (was_on_floor && !on_floor && !snap.is_equal_approx(Vector3())) {
// Apply snap.
Transform3D gt = get_global_transform();
PhysicsServer3D::MotionResult result;
@@ -1213,6 +1207,11 @@ bool CharacterBody3D::move_and_slide() {
linear_velocity += current_floor_velocity;
}
+ // Reset the gravity accumulation when touching the ground.
+ if (on_floor && linear_velocity.dot(up_direction) <= 0) {
+ linear_velocity = linear_velocity.slide(up_direction);
+ }
+
return motion_results.size() > 0;
}
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 9c40f92f06..26b9a39047 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -132,6 +132,8 @@ public:
MODE_KINEMATIC,
};
+ GDVIRTUAL1(_integrate_forces, PhysicsDirectBodyState3D *)
+
protected:
bool can_sleep = true;
PhysicsDirectBodyState3D *state = nullptr;
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 543545b90f..88fb960164 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -36,8 +36,9 @@
#include "servers/audio/audio_stream.h"
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
- if (get_script_instance()) {
- Array parameters = get_script_instance()->call("_get_parameter_list");
+ Array parameters;
+
+ if (GDVIRTUAL_CALL(_get_parameter_list, parameters)) {
for (int i = 0; i < parameters.size(); i++) {
Dictionary d = parameters[i];
ERR_CONTINUE(d.is_empty());
@@ -47,8 +48,9 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
}
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_parameter_default_value", p_parameter);
+ Variant ret;
+ if (GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret)) {
+ return ret;
}
return Variant();
}
@@ -72,8 +74,8 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
}
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
- if (get_script_instance()) {
- Dictionary cn = get_script_instance()->call("_get_child_nodes");
+ Dictionary cn;
+ if (GDVIRTUAL_CALL(_get_child_nodes, cn)) {
List<Variant> keys;
cn.get_key_list(&keys);
for (const Variant &E : keys) {
@@ -298,8 +300,9 @@ String AnimationNode::get_input_name(int p_input) {
}
String AnimationNode::get_caption() const {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_caption");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_caption, ret)) {
+ return ret;
}
return "Node";
@@ -329,8 +332,9 @@ void AnimationNode::remove_input(int p_index) {
}
double AnimationNode::process(double p_time, bool p_seek) {
- if (get_script_instance()) {
- return get_script_instance()->call("_process", p_time, p_seek);
+ double ret;
+ if (GDVIRTUAL_CALL(_process, p_time, p_seek, ret)) {
+ return ret;
}
return 0;
@@ -357,8 +361,9 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
}
bool AnimationNode::has_filter() const {
- if (get_script_instance()) {
- return get_script_instance()->call("_has_filter");
+ bool ret;
+ if (GDVIRTUAL_CALL(_has_filter, ret)) {
+ return ret;
}
return false;
@@ -390,8 +395,9 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
}
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_child_by_name", p_name);
+ Ref<AnimationNode> ret;
+ if (GDVIRTUAL_CALL(_get_child_by_name, p_name, ret)) {
+ return ret;
}
return Ref<AnimationNode>();
}
@@ -422,17 +428,13 @@ void AnimationNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
- BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_child_nodes"));
- BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_parameter_list"));
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_get_child_by_name", PropertyInfo(Variant::STRING, "name")));
- {
- MethodInfo mi = MethodInfo(Variant::NIL, "_get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name"));
- mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(mi);
- }
- BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_caption"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_filter"));
+ GDVIRTUAL_BIND(_get_child_nodes);
+ GDVIRTUAL_BIND(_get_parameter_list);
+ GDVIRTUAL_BIND(_get_child_by_name, "name");
+ GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
+ GDVIRTUAL_BIND(_process, "time", "seek");
+ GDVIRTUAL_BIND(_get_caption);
+ GDVIRTUAL_BIND(_has_filter);
ADD_SIGNAL(MethodInfo("removed_from_graph"));
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 59bbc5b4da..1e0267682e 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -112,6 +112,14 @@ protected:
void _set_parent(Object *p_parent);
+ GDVIRTUAL0RC(Dictionary, _get_child_nodes)
+ GDVIRTUAL0RC(Array, _get_parameter_list)
+ GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
+ GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
+ GDVIRTUAL2RC(double, _process, double, bool)
+ GDVIRTUAL0RC(String, _get_caption)
+ GDVIRTUAL0RC(bool, _has_filter)
+
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 298d75b668..9383355292 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -202,8 +202,12 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) {
}
if (p_stream.is_valid()) {
- stream = p_stream;
stream_playback = p_stream->instance_playback();
+ if (stream_playback.is_valid()) {
+ stream = p_stream;
+ } else {
+ stream.unref();
+ }
}
AudioServer::get_singleton()->unlock();
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index d252a4507c..bef1011364 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -52,7 +52,7 @@ void BaseButton::_unpress_group() {
}
}
-void BaseButton::_gui_input(Ref<InputEvent> p_event) {
+void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (status.disabled) { // no interaction with disabled button
@@ -121,17 +121,13 @@ void BaseButton::_notification(int p_what) {
}
void BaseButton::_pressed() {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_pressed);
- }
+ GDVIRTUAL_CALL(_pressed);
pressed();
emit_signal(SNAME("pressed"));
}
void BaseButton::_toggled(bool p_pressed) {
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_toggled, p_pressed);
- }
+ GDVIRTUAL_CALL(_toggled, p_pressed);
toggled(p_pressed);
emit_signal(SNAME("toggled"), p_pressed);
}
@@ -342,7 +338,7 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
-void BaseButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+void BaseButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shorcut_context()) {
@@ -411,8 +407,6 @@ bool BaseButton::_is_focus_owner_in_shorcut_context() const {
}
void BaseButton::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &BaseButton::_gui_input);
- ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &BaseButton::_unhandled_key_input);
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &BaseButton::set_pressed);
ClassDB::bind_method(D_METHOD("is_pressed"), &BaseButton::is_pressed);
ClassDB::bind_method(D_METHOD("set_pressed_no_signal", "pressed"), &BaseButton::set_pressed_no_signal);
@@ -440,8 +434,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shortcut_context", "node"), &BaseButton::set_shortcut_context);
ClassDB::bind_method(D_METHOD("get_shortcut_context"), &BaseButton::get_shortcut_context);
- BIND_VMETHOD(MethodInfo("_pressed"));
- BIND_VMETHOD(MethodInfo("_toggled", PropertyInfo(Variant::BOOL, "button_pressed")));
+ GDVIRTUAL_BIND(_pressed);
+ GDVIRTUAL_BIND(_toggled, "button_pressed");
ADD_SIGNAL(MethodInfo("pressed"));
ADD_SIGNAL(MethodInfo("button_up"));
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index d86b35daf0..cd6e78464f 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -75,12 +75,15 @@ protected:
virtual void pressed();
virtual void toggled(bool p_pressed);
static void _bind_methods();
- virtual void _gui_input(Ref<InputEvent> p_event);
- virtual void _unhandled_key_input(Ref<InputEvent> p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
bool _is_focus_owner_in_shorcut_context() const;
+ GDVIRTUAL0(_pressed)
+ GDVIRTUAL1(_toggled, bool)
+
public:
enum DrawMode {
DRAW_NORMAL,
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 08dd7f28eb..27cac73aef 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -248,7 +248,7 @@ void CodeEdit::_notification(int p_what) {
}
}
-void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
+void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventMouseButton> mb = p_gui_input;
if (mb.is_valid()) {
@@ -354,7 +354,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventKey> k = p_gui_input;
bool update_code_completion = false;
if (!k.is_valid()) {
- TextEdit::_gui_input(p_gui_input);
+ TextEdit::gui_input(p_gui_input);
return;
}
@@ -450,7 +450,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (k->is_action("ui_text_backspace", true)) {
backspace();
- _filter_code_completion_candidates();
+ _filter_code_completion_candidates_impl();
accept_event();
return;
}
@@ -519,10 +519,10 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
set_code_hint("");
}
- TextEdit::_gui_input(p_gui_input);
+ TextEdit::gui_input(p_gui_input);
if (update_code_completion) {
- _filter_code_completion_candidates();
+ _filter_code_completion_candidates_impl();
}
}
@@ -557,7 +557,7 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
/* Text manipulation */
// Overridable actions
-void CodeEdit::_handle_unicode_input(const uint32_t p_unicode) {
+void CodeEdit::_handle_unicode_input_internal(const uint32_t p_unicode) {
bool had_selection = has_selection();
if (had_selection) {
begin_complex_operation();
@@ -609,7 +609,7 @@ void CodeEdit::_handle_unicode_input(const uint32_t p_unicode) {
}
}
-void CodeEdit::_backspace() {
+void CodeEdit::_backspace_internal() {
if (!is_editable()) {
return;
}
@@ -1739,9 +1739,7 @@ String CodeEdit::get_text_for_code_completion() const {
}
void CodeEdit::request_code_completion(bool p_force) {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_request_code_completion")) {
- si->call("_request_code_completion", p_force);
+ if (GDVIRTUAL_CALL(_request_code_completion, p_force)) {
return;
}
@@ -1798,7 +1796,7 @@ void CodeEdit::update_code_completion_options(bool p_forced) {
code_completion_forced = p_forced;
code_completion_option_sources = code_completion_option_submitted;
code_completion_option_submitted.clear();
- _filter_code_completion_candidates();
+ _filter_code_completion_candidates_impl();
}
TypedArray<Dictionary> CodeEdit::get_code_completion_options() const {
@@ -1855,11 +1853,10 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
return;
}
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_confirm_code_completion")) {
- si->call("_confirm_code_completion", p_replace);
+ if (GDVIRTUAL_CALL(_confirm_code_completion, p_replace)) {
return;
}
+
begin_complex_operation();
int caret_line = get_caret_line();
@@ -2179,9 +2176,10 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_code_comletion_prefixes"), &CodeEdit::get_code_completion_prefixes);
// Overridable
- BIND_VMETHOD(MethodInfo("_confirm_code_completion", PropertyInfo(Variant::BOOL, "replace")));
- BIND_VMETHOD(MethodInfo("_request_code_completion", PropertyInfo(Variant::BOOL, "force")));
- BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_filter_code_completion_candidates", PropertyInfo(Variant::ARRAY, "candidates")));
+
+ GDVIRTUAL_BIND(_confirm_code_completion, "replace")
+ GDVIRTUAL_BIND(_request_code_completion, "force")
+ GDVIRTUAL_BIND(_filter_code_completion_candidates, "candidates")
/* Line length guidelines */
ClassDB::bind_method(D_METHOD("set_line_length_guidelines", "guideline_columns"), &CodeEdit::set_line_length_guidelines);
@@ -2650,11 +2648,10 @@ TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const {
}
/* Code Completion */
-void CodeEdit::_filter_code_completion_candidates() {
- ScriptInstance *si = get_script_instance();
+void CodeEdit::_filter_code_completion_candidates_impl() {
int line_height = get_line_height();
- if (si && si->has_method("_filter_code_completion_candidates")) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_filter_code_completion_candidates)) {
code_completion_options.clear();
code_completion_base = "";
@@ -2674,7 +2671,9 @@ void CodeEdit::_filter_code_completion_candidates() {
i++;
}
- TypedArray<Dictionary> completion_options = si->call("_filter_code_completion_candidates", completion_options_sources);
+ Array completion_options;
+
+ GDVIRTUAL_CALL(_filter_code_completion_candidates, completion_options_sources, completion_options);
/* No options to complete, cancel. */
if (completion_options.size() == 0) {
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 76ac15f553..4fbb5194e6 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -219,7 +219,7 @@ private:
List<ScriptCodeCompletionOption> code_completion_option_sources;
String code_completion_base;
- void _filter_code_completion_candidates();
+ void _filter_code_completion_candidates_impl();
/* Line length guidelines */
TypedArray<int> line_length_guideline_columns;
@@ -248,7 +248,7 @@ private:
void _text_changed();
protected:
- void _gui_input(const Ref<InputEvent> &p_gui_input) override;
+ void gui_input(const Ref<InputEvent> &p_gui_input) override;
void _notification(int p_what);
static void _bind_methods();
@@ -256,8 +256,12 @@ protected:
/* Text manipulation */
// Overridable actions
- virtual void _handle_unicode_input(const uint32_t p_unicode) override;
- virtual void _backspace() override;
+ virtual void _handle_unicode_input_internal(const uint32_t p_unicode) override;
+ virtual void _backspace_internal() override;
+
+ GDVIRTUAL1(_confirm_code_completion, bool)
+ GDVIRTUAL1(_request_code_completion, bool)
+ GDVIRTUAL1RC(Array, _filter_code_completion_candidates, TypedArray<Dictionary>)
public:
/* General overrides */
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 261480bcdd..0dddb2b09a 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -46,13 +46,13 @@ void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
- bt_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
-
+ btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
+ _update_presets();
_update_controls();
} break;
case NOTIFICATION_ENTER_TREE: {
btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
- bt_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
+ btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
_update_controls();
_update_color();
@@ -69,7 +69,6 @@ void ColorPicker::_notification(int p_what) {
for (int i = 0; i < preset_cache.size(); i++) {
presets.push_back(preset_cache[i]);
}
- preset->update();
}
#endif
} break;
@@ -98,6 +97,8 @@ Ref<Shader> ColorPicker::circle_shader;
void ColorPicker::init_shaders() {
wheel_shader.instantiate();
wheel_shader->set_code(R"(
+// ColorPicker wheel shader.
+
shader_type canvas_item;
void fragment() {
@@ -120,6 +121,8 @@ void fragment() {
circle_shader.instantiate();
circle_shader->set_code(R"(
+// ColorPicker circle shader.
+
shader_type canvas_item;
uniform float v = 1.0;
@@ -372,22 +375,23 @@ void ColorPicker::_update_color(bool p_update_sliders) {
}
void ColorPicker::_update_presets() {
- return;
- //presets should be shown using buttons or something else, this method is not a good idea
-
- presets_per_row = 10;
- Size2 size = bt_add_preset->get_size();
- Size2 preset_size = Size2(MIN(size.width * presets.size(), presets_per_row * size.width), size.height * (Math::ceil((float)presets.size() / presets_per_row)));
- preset->set_custom_minimum_size(preset_size);
- preset_container->set_custom_minimum_size(preset_size);
- preset->draw_rect(Rect2(Point2(), preset_size), Color(1, 1, 1, 0));
-
- for (int i = 0; i < presets.size(); i++) {
- int x = (i % presets_per_row) * size.width;
- int y = (Math::floor((float)i / presets_per_row)) * size.height;
- preset->draw_rect(Rect2(Point2(x, y), size), presets[i]);
+ int preset_size = _get_preset_size();
+ // Only update the preset button size if it has changed.
+ if (preset_size != prev_preset_size) {
+ prev_preset_size = preset_size;
+ btn_add_preset->set_custom_minimum_size(Size2(preset_size, preset_size));
+ for (int i = 1; i < preset_container->get_child_count(); i++) {
+ ColorPresetButton *cpb = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
+ cpb->set_custom_minimum_size(Size2(preset_size, preset_size));
+ }
+ }
+ // Only load preset buttons when the only child is the add-preset button.
+ if (preset_container->get_child_count() == 1) {
+ for (int i = 0; i < preset_cache.size(); i++) {
+ _add_preset_button(preset_size, preset_cache[i]);
+ }
+ _notification(NOTIFICATION_VISIBILITY_CHANGED);
}
- _notification(NOTIFICATION_VISIBILITY_CHANGED);
}
void ColorPicker::_text_type_toggled() {
@@ -422,14 +426,37 @@ ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const {
return picker_type;
}
+inline int ColorPicker::_get_preset_size() {
+ return (int(get_minimum_size().width) - (preset_container->get_theme_constant(SNAME("hseparation")) * (preset_column_count - 1))) / preset_column_count;
+}
+
+void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
+ ColorPresetButton *btn_preset = memnew(ColorPresetButton(p_color));
+ btn_preset->set_preset_color(p_color);
+ btn_preset->set_custom_minimum_size(Size2(p_size, p_size));
+ btn_preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input), varray(p_color));
+ btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
+ preset_container->add_child(btn_preset);
+}
+
void ColorPicker::add_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.move_to_back(presets.find(p_color));
+
+ // Find button to move to the end.
+ for (int i = 1; i < preset_container->get_child_count(); i++) {
+ ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
+ if (current_btn && p_color == current_btn->get_preset_color()) {
+ preset_container->move_child(current_btn, preset_container->get_child_count() - 1);
+ break;
+ }
+ }
} else {
presets.push_back(p_color);
preset_cache.push_back(p_color);
+
+ _add_preset_button(_get_preset_size(), p_color);
}
- preset->update();
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
@@ -443,7 +470,15 @@ void ColorPicker::erase_preset(const Color &p_color) {
if (presets.find(p_color)) {
presets.erase(presets.find(p_color));
preset_cache.erase(preset_cache.find(p_color));
- preset->update();
+
+ // Find preset button to remove.
+ for (int i = 1; i < preset_container->get_child_count(); i++) {
+ ColorPresetButton *current_btn = Object::cast_to<ColorPresetButton>(preset_container->get_child(i));
+ if (current_btn && p_color == current_btn->get_preset_color()) {
+ current_btn->queue_delete();
+ break;
+ }
+ }
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
@@ -560,7 +595,7 @@ void ColorPicker::_sample_draw() {
const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
if (display_old_color && old_color.a < 1.0) {
- sample->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), rect_old, true);
+ sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_old, true);
}
sample->draw_rect(rect_old, old_color);
@@ -574,7 +609,7 @@ void ColorPicker::_sample_draw() {
}
if (color.a < 1.0) {
- sample->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), rect_new, true);
+ sample->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), rect_new, true);
}
sample->draw_rect(rect_new, color);
@@ -734,7 +769,7 @@ void ColorPicker::_slider_draw(int p_which) {
#endif
if (p_which == 3) {
- scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
+ scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -932,43 +967,19 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) {
}
}
-void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) {
+void ColorPicker::_preset_input(const Ref<InputEvent> &p_event, const Color &p_color) {
Ref<InputEventMouseButton> bev = p_event;
if (bev.is_valid()) {
- int index = 0;
if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) {
- for (int i = 0; i < presets.size(); i++) {
- int x = (i % presets_per_row) * bt_add_preset->get_size().x;
- int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y;
- if (bev->get_position().x > x && bev->get_position().x < x + preset->get_size().x && bev->get_position().y > y && bev->get_position().y < y + preset->get_size().y) {
- index = i;
- }
- }
- set_pick_color(presets[index]);
+ set_pick_color(p_color);
_update_color();
- emit_signal(SNAME("color_changed"), color);
+ emit_signal(SNAME("color_changed"), p_color);
} else if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_RIGHT && presets_enabled) {
- index = bev->get_position().x / (preset->get_size().x / presets.size());
- Color clicked_preset = presets[index];
- erase_preset(clicked_preset);
- emit_signal(SNAME("preset_removed"), clicked_preset);
- bt_add_preset->show();
+ erase_preset(p_color);
+ emit_signal(SNAME("preset_removed"), p_color);
}
}
-
- Ref<InputEventMouseMotion> mev = p_event;
-
- if (mev.is_valid()) {
- int index = mev->get_position().x * presets.size();
- if (preset->get_size().x != 0) {
- index /= preset->get_size().x;
- }
- if (index < 0 || index >= presets.size()) {
- return;
- }
- preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Set color\nRMB: Remove preset"), presets[index].to_html(presets[index].a < 1)));
- }
}
void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) {
@@ -1064,11 +1075,11 @@ void ColorPicker::_html_focus_exit() {
void ColorPicker::set_presets_enabled(bool p_enabled) {
presets_enabled = p_enabled;
if (!p_enabled) {
- bt_add_preset->set_disabled(true);
- bt_add_preset->set_focus_mode(FOCUS_NONE);
+ btn_add_preset->set_disabled(true);
+ btn_add_preset->set_focus_mode(FOCUS_NONE);
} else {
- bt_add_preset->set_disabled(false);
- bt_add_preset->set_focus_mode(FOCUS_ALL);
+ btn_add_preset->set_disabled(false);
+ btn_add_preset->set_focus_mode(FOCUS_ALL);
}
}
@@ -1080,7 +1091,6 @@ void ColorPicker::set_presets_visible(bool p_visible) {
presets_visible = p_visible;
preset_separator->set_visible(p_visible);
preset_container->set_visible(p_visible);
- preset_container2->set_visible(p_visible);
}
bool ColorPicker::are_presets_visible() const {
@@ -1266,17 +1276,13 @@ ColorPicker::ColorPicker() :
add_child(preset_separator);
preset_container->set_h_size_flags(SIZE_EXPAND_FILL);
+ preset_container->set_columns(preset_column_count);
add_child(preset_container);
- preset_container->add_child(preset);
- preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input));
- preset->connect("draw", callable_mp(this, &ColorPicker::_update_presets));
-
- preset_container2->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(preset_container2);
- preset_container2->add_child(bt_add_preset);
- bt_add_preset->set_tooltip(RTR("Add current color as a preset."));
- bt_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
+ btn_add_preset->set_icon_align(Button::ALIGN_CENTER);
+ btn_add_preset->set_tooltip(RTR("Add current color as a preset."));
+ btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
+ preset_container->add_child(btn_add_preset);
}
/////////////////
@@ -1303,6 +1309,7 @@ void ColorPickerButton::pressed() {
_update_picker();
popup->set_as_minsize();
+ picker->_update_presets();
Rect2i usable_rect = popup->get_usable_parent_rect();
//let's try different positions to see which one we can use
@@ -1428,3 +1435,64 @@ void ColorPickerButton::_bind_methods() {
ColorPickerButton::ColorPickerButton() {
set_toggle_mode(true);
}
+
+/////////////////
+
+void ColorPresetButton::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ const Rect2 r = Rect2(Point2(0, 0), get_size());
+ Ref<StyleBox> sb_raw = get_theme_stylebox(SNAME("preset_fg"), SNAME("ColorPresetButton"))->duplicate();
+ Ref<StyleBoxFlat> sb_flat = sb_raw;
+ Ref<StyleBoxTexture> sb_texture = sb_raw;
+
+ if (sb_flat.is_valid()) {
+ if (preset_color.a < 1) {
+ // Draw a background pattern when the color is transparent.
+ sb_flat->set_bg_color(Color(1, 1, 1));
+ sb_flat->draw(get_canvas_item(), r);
+
+ Rect2 bg_texture_rect = r.grow_side(SIDE_LEFT, -sb_flat->get_margin(SIDE_LEFT));
+ bg_texture_rect = bg_texture_rect.grow_side(SIDE_RIGHT, -sb_flat->get_margin(SIDE_RIGHT));
+ bg_texture_rect = bg_texture_rect.grow_side(SIDE_TOP, -sb_flat->get_margin(SIDE_TOP));
+ bg_texture_rect = bg_texture_rect.grow_side(SIDE_BOTTOM, -sb_flat->get_margin(SIDE_BOTTOM));
+
+ draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPresetButton")), bg_texture_rect, true);
+ sb_flat->set_bg_color(preset_color);
+ }
+ sb_flat->set_bg_color(preset_color);
+ sb_flat->draw(get_canvas_item(), r);
+ } else if (sb_texture.is_valid()) {
+ if (preset_color.a < 1) {
+ // Draw a background pattern when the color is transparent.
+ bool use_tile_texture = (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE) || (sb_texture->get_h_axis_stretch_mode() == StyleBoxTexture::AxisStretchMode::AXIS_STRETCH_MODE_TILE_FIT);
+ draw_texture_rect(get_theme_icon(SNAME("preset_bg"), SNAME("ColorPresetButton")), r, use_tile_texture);
+ }
+ sb_texture->set_modulate(preset_color);
+ sb_texture->draw(get_canvas_item(), r);
+ } else {
+ WARN_PRINT("Unsupported StyleBox used for ColorPresetButton. Use StyleBoxFlat or StyleBoxTexture instead.");
+ }
+ if (preset_color.r > 1 || preset_color.g > 1 || preset_color.b > 1) {
+ // Draw an indicator to denote that the color is "overbright" and can't be displayed accurately in the preview
+ draw_texture(Control::get_theme_icon(SNAME("overbright_indicator"), SNAME("ColorPresetButton")), Vector2(0, 0));
+ }
+
+ } break;
+ }
+}
+
+void ColorPresetButton::set_preset_color(const Color &p_color) {
+ preset_color = p_color;
+}
+
+Color ColorPresetButton::get_preset_color() const {
+ return preset_color;
+}
+
+ColorPresetButton::ColorPresetButton(Color p_color) {
+ preset_color = p_color;
+}
+
+ColorPresetButton::~ColorPresetButton() {
+}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 60da3957aa..67ca007eb5 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -35,6 +35,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
+#include "scene/gui/grid_container.h"
#include "scene/gui/label.h"
#include "scene/gui/line_edit.h"
#include "scene/gui/popup.h"
@@ -43,6 +44,22 @@
#include "scene/gui/spin_box.h"
#include "scene/gui/texture_rect.h"
+class ColorPresetButton : public BaseButton {
+ GDCLASS(ColorPresetButton, BaseButton);
+
+ Color preset_color;
+
+protected:
+ void _notification(int);
+
+public:
+ void set_preset_color(const Color &p_color);
+ Color get_preset_color() const;
+
+ ColorPresetButton(Color p_color);
+ ~ColorPresetButton();
+};
+
class ColorPicker : public BoxContainer {
GDCLASS(ColorPicker, BoxContainer);
@@ -69,12 +86,9 @@ private:
Control *wheel = memnew(Control);
Control *wheel_uv = memnew(Control);
TextureRect *sample = memnew(TextureRect);
- TextureRect *preset = memnew(TextureRect);
- HBoxContainer *preset_container = memnew(HBoxContainer);
- HBoxContainer *preset_container2 = memnew(HBoxContainer);
+ GridContainer *preset_container = memnew(GridContainer);
HSeparator *preset_separator = memnew(HSeparator);
- Button *bt_add_preset = memnew(Button);
- List<Color> presets;
+ Button *btn_add_preset = memnew(Button);
Button *btn_pick = memnew(Button);
CheckButton *btn_hsv = memnew(CheckButton);
CheckButton *btn_raw = memnew(CheckButton);
@@ -83,14 +97,19 @@ private:
Label *labels[4];
Button *text_type = memnew(Button);
LineEdit *c_text = memnew(LineEdit);
+
bool edit_alpha = true;
Size2i ms;
bool text_is_constructor = false;
- int presets_per_row = 0;
PickerShapeType picker_type = SHAPE_HSV_WHEEL;
+ const int preset_column_count = 9;
+ int prev_preset_size = 0;
+ List<Color> presets;
+
Color color;
Color old_color;
+
bool display_old_color = false;
bool raw_mode_enabled = false;
bool hsv_mode_enabled = false;
@@ -100,6 +119,7 @@ private:
bool spinning = false;
bool presets_enabled = true;
bool presets_visible = true;
+
float h = 0.0;
float s = 0.0;
float v = 0.0;
@@ -109,7 +129,6 @@ private:
void _value_changed(double);
void _update_controls();
void _update_color(bool p_update_sliders = true);
- void _update_presets();
void _update_text_value();
void _text_type_toggled();
void _sample_input(const Ref<InputEvent> &p_event);
@@ -119,7 +138,7 @@ private:
void _uv_input(const Ref<InputEvent> &p_event, Control *c);
void _w_input(const Ref<InputEvent> &p_event);
- void _preset_input(const Ref<InputEvent> &p_event);
+ void _preset_input(const Ref<InputEvent> &p_event, const Color &p_color);
void _screen_input(const Ref<InputEvent> &p_event);
void _add_preset_pressed();
void _screen_pick_pressed();
@@ -127,6 +146,9 @@ private:
void _focus_exit();
void _html_focus_exit();
+ inline int _get_preset_size();
+ void _add_preset_button(int p_size, const Color &p_color);
+
protected:
void _notification(int);
static void _bind_methods();
@@ -152,6 +174,7 @@ public:
void add_preset(const Color &p_color);
void erase_preset(const Color &p_color);
PackedColorArray get_presets() const;
+ void _update_presets();
void set_hsv_mode(bool p_enabled);
bool is_hsv_mode() const;
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index f114e06c75..4ac6a58d36 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -730,14 +730,9 @@ Variant Control::get_drag_data(const Point2 &p_point) {
}
}
- if (get_script_instance()) {
- Variant v = p_point;
- const Variant *p = &v;
- Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_get_drag_data, &p, 1, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- return ret;
- }
+ Variant dd;
+ if (GDVIRTUAL_CALL(_get_drag_data, p_point, dd)) {
+ return dd;
}
return Variant();
@@ -752,16 +747,10 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const
}
}
- if (get_script_instance()) {
- Variant v = p_point;
- const Variant *p[2] = { &v, &p_data };
- Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_can_drop_data, p, 2, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- return ret;
- }
+ bool ret;
+ if (GDVIRTUAL_CALL(_can_drop_data, p_point, p_data, ret)) {
+ return ret;
}
-
return false;
}
@@ -775,15 +764,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) {
}
}
- if (get_script_instance()) {
- Variant v = p_point;
- const Variant *p[2] = { &v, &p_data };
- Callable::CallError ce;
- Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_drop_data, p, 2, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- return;
- }
- }
+ GDVIRTUAL_CALL(_drop_data, p_point, p_data);
}
void Control::force_drag(const Variant &p_data, Control *p_control) {
@@ -799,16 +780,26 @@ void Control::set_drag_preview(Control *p_control) {
get_viewport()->_gui_set_drag_preview(this, p_control);
}
+void Control::_call_gui_input(const Ref<InputEvent> &p_event) {
+ emit_signal(SceneStringNames::get_singleton()->gui_input, p_event); //signal should be first, so it's possible to override an event (and then accept it)
+ if (!is_inside_tree() || get_viewport()->is_input_handled()) {
+ return; //input was handled, abort
+ }
+ GDVIRTUAL_CALL(_gui_input, p_event);
+ if (!is_inside_tree() || get_viewport()->is_input_handled()) {
+ return; //input was handled, abort
+ }
+ gui_input(p_event);
+}
+void Control::gui_input(const Ref<InputEvent> &p_event) {
+}
+
Size2 Control::get_minimum_size() const {
- ScriptInstance *si = const_cast<Control *>(this)->get_script_instance();
- if (si) {
- Callable::CallError ce;
- Variant s = si->call(SceneStringNames::get_singleton()->_get_minimum_size, nullptr, 0, ce);
- if (ce.error == Callable::CallError::CALL_OK) {
- return s;
- }
+ Vector2 ms;
+ if (GDVIRTUAL_CALL(_get_minimum_size, ms)) {
+ return ms;
}
- return Size2();
+ return Vector2();
}
template <class T>
@@ -2123,8 +2114,9 @@ String Control::get_tooltip(const Point2 &p_pos) const {
}
Control *Control::make_custom_tooltip(const String &p_text) const {
- if (get_script_instance()) {
- return const_cast<Control *>(this)->call("_make_custom_tooltip", p_text);
+ Object *ret = nullptr;
+ if (GDVIRTUAL_CALL(_make_custom_tooltip, p_text, ret)) {
+ return Object::cast_to<Control>(ret);
}
return nullptr;
}
@@ -2499,14 +2491,11 @@ Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_theme_ty
}
} break;
case STRUCTURED_TEXT_CUSTOM: {
- if (get_script_instance()) {
- Variant data = get_script_instance()->call(SceneStringNames::get_singleton()->_structured_text_parser, p_args, p_text);
- if (data.get_type() == Variant::ARRAY) {
- Array _data = data;
- for (int i = 0; i < _data.size(); i++) {
- if (_data[i].get_type() == Variant::VECTOR2I) {
- ret.push_back(Vector2i(_data[i]));
- }
+ Array r;
+ if (GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, r)) {
+ for (int i = 0; i < r.size(); i++) {
+ if (r[i].get_type() == Variant::VECTOR2I) {
+ ret.push_back(Vector2i(r[i]));
}
}
}
@@ -2823,21 +2812,6 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_translate", "enable"), &Control::set_auto_translate);
ClassDB::bind_method(D_METHOD("is_auto_translating"), &Control::is_auto_translating);
- BIND_VMETHOD(MethodInfo("_structured_text_parser", PropertyInfo(Variant::ARRAY, "args"), PropertyInfo(Variant::STRING, "text")));
-
- BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size"));
-
- MethodInfo get_drag_data = MethodInfo("_get_drag_data", PropertyInfo(Variant::VECTOR2, "position"));
- get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(get_drag_data);
-
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
- BIND_VMETHOD(MethodInfo("_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data")));
- BIND_VMETHOD(MethodInfo(
- PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"),
- "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text")));
-
ADD_GROUP("Anchor", "anchor_");
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP);
@@ -2994,5 +2968,14 @@ void Control::_bind_methods() {
ADD_SIGNAL(MethodInfo("minimum_size_changed"));
ADD_SIGNAL(MethodInfo("theme_changed"));
- GDVIRTUAL_BIND(_has_point);
+ GDVIRTUAL_BIND(_has_point, "position");
+ GDVIRTUAL_BIND(_structured_text_parser, "args", "text");
+ GDVIRTUAL_BIND(_get_minimum_size);
+
+ GDVIRTUAL_BIND(_get_drag_data, "at_position");
+ GDVIRTUAL_BIND(_can_drop_data, "at_position", "data");
+ GDVIRTUAL_BIND(_drop_data, "at_position", "data");
+ GDVIRTUAL_BIND(_make_custom_tooltip, "for_text");
+
+ GDVIRTUAL_BIND(_gui_input, "event");
}
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a871a8e9fb..0faa617f8d 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -31,10 +31,10 @@
#ifndef CONTROL_H
#define CONTROL_H
+#include "core/input/shortcut.h"
#include "core/math/transform_2d.h"
#include "core/object/gdvirtual.gen.inc"
#include "core/templates/rid.h"
-#include "scene/gui/shortcut.h"
#include "scene/main/canvas_item.h"
#include "scene/main/node.h"
#include "scene/main/timer.h"
@@ -263,6 +263,8 @@ private:
friend class Viewport;
+ void _call_gui_input(const Ref<InputEvent> &p_event);
+
void _update_minimum_size_cache();
friend class Window;
static void _propagate_theme_changed(Node *p_at, Control *p_owner, Window *p_owner_window, bool p_assign = true);
@@ -272,7 +274,6 @@ private:
static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types);
_FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const;
- GDVIRTUAL1RC(bool, _has_point, Vector2)
protected:
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
@@ -291,6 +292,17 @@ protected:
//bind helpers
+ GDVIRTUAL1RC(bool, _has_point, Vector2)
+ GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL0RC(Vector2, _get_minimum_size)
+
+ GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
+ GDVIRTUAL2RC(bool, _can_drop_data, Vector2, Variant)
+ GDVIRTUAL2(_drop_data, Vector2, Variant)
+ GDVIRTUAL1RC(Object *, _make_custom_tooltip, String)
+
+ GDVIRTUAL1(_gui_input, Ref<InputEvent>)
+
public:
enum {
/* NOTIFICATION_DRAW=30,
@@ -333,6 +345,8 @@ public:
virtual Size2 _edit_get_minimum_size() const override;
#endif
+ virtual void gui_input(const Ref<InputEvent> &p_event);
+
void accept_event();
virtual Size2 get_minimum_size() const;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 2e4204e171..2512b24623 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -95,7 +95,7 @@ void FileDialog::_notification(int p_what) {
}
}
-void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) {
+void FileDialog::unhandled_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@@ -854,8 +854,6 @@ void FileDialog::_update_drives() {
bool FileDialog::default_show_hidden_files = false;
void FileDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input);
-
ClassDB::bind_method(D_METHOD("_cancel_pressed"), &FileDialog::_cancel_pressed);
ClassDB::bind_method(D_METHOD("clear_filters"), &FileDialog::clear_filters);
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 7fbafc4bb4..b5190bdab1 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -132,7 +132,7 @@ private:
void _update_drives();
- void _unhandled_input(const Ref<InputEvent> &p_event);
+ virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
bool _is_open_should_be_disabled();
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 635f3c51b9..bbab3008e2 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -88,7 +88,7 @@ void GradientEdit::_show_color_picker() {
GradientEdit::~GradientEdit() {
}
-void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
+void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@@ -458,6 +458,5 @@ Vector<Gradient::Point> &GradientEdit::get_points() {
}
void GradientEdit::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &GradientEdit::_gui_input);
ADD_SIGNAL(MethodInfo("ramp_changed"));
}
diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h
index b0ee2c4abb..a173631963 100644
--- a/scene/gui/gradient_edit.h
+++ b/scene/gui/gradient_edit.h
@@ -52,7 +52,7 @@ class GradientEdit : public Control {
void _show_color_picker();
protected:
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index fcecbb5fca..0281bc7efb 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -51,10 +51,6 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
ge = p_edit;
}
-void GraphEditMinimap::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEditMinimap::_gui_input);
-}
-
GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
ge = p_edit;
@@ -148,7 +144,7 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position)
return graph_position;
}
-void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) {
+void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
if (!ge->is_minimap_enabled()) {
@@ -805,68 +801,36 @@ bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos, c
return true;
}
-template <class Vector2>
-static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) {
- /* Formula from Wikipedia article on Bezier curves. */
- real_t omt = (1.0 - t);
- real_t omt2 = omt * omt;
- real_t omt3 = omt2 * omt;
- real_t t2 = t * t;
- real_t t3 = t2 * t;
-
- return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
-}
-
-void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const {
- float mp = p_begin + (p_end - p_begin) * 0.5;
- Vector2 beg = _bezier_interp(p_begin, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 mid = _bezier_interp(mp, p_a, p_a + p_out, p_b + p_in, p_b);
- Vector2 end = _bezier_interp(p_end, p_a, p_a + p_out, p_b + p_in, p_b);
-
- Vector2 na = (mid - beg).normalized();
- Vector2 nb = (end - mid).normalized();
- float dp = Math::rad2deg(Math::acos(na.dot(nb)));
-
- if (p_depth >= p_min_depth && (dp < p_tol || p_depth >= p_max_depth)) {
- points.push_back((beg + end) * 0.5);
- colors.push_back(p_color.lerp(p_to_color, mp));
- lines++;
- } else {
- _bake_segment2d(points, colors, p_begin, mp, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines);
- _bake_segment2d(points, colors, mp, p_end, p_a, p_out, p_b, p_in, p_depth + 1, p_min_depth, p_max_depth, p_tol, p_color, p_to_color, lines);
+PackedVector2Array GraphEdit::get_connection_line(const Vector2 &p_from, const Vector2 &p_to) {
+ Vector<Vector2> ret;
+ if (GDVIRTUAL_CALL(_get_connection_line, p_from, p_to, ret)) {
+ return ret;
}
-}
-void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio) {
- //cubic bezier code
- float diff = p_to.x - p_from.x;
- float cp_offset;
- int cp_len = get_theme_constant(SNAME("bezier_len_pos")) * p_bezier_ratio;
- int cp_neg_len = get_theme_constant(SNAME("bezier_len_neg")) * p_bezier_ratio;
-
- if (diff > 0) {
- cp_offset = MIN(cp_len, diff * 0.5);
- } else {
- cp_offset = MAX(MIN(cp_len - diff, cp_neg_len), -diff * 0.5);
- }
-
- Vector2 c1 = Vector2(cp_offset * zoom, 0);
- Vector2 c2 = Vector2(-cp_offset * zoom, 0);
-
- int lines = 0;
+ Curve2D curve;
+ Vector<Color> colors;
+ curve.add_point(p_from);
+ curve.set_point_out(0, Vector2(60, 0));
+ curve.add_point(p_to);
+ curve.set_point_in(1, Vector2(-60, 0));
+ return curve.tessellate();
+}
- Vector<Point2> points;
+void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom) {
+ Vector<Vector2> points = get_connection_line(p_from / p_zoom, p_to / p_zoom);
+ Vector<Vector2> scaled_points;
Vector<Color> colors;
- points.push_back(p_from);
- colors.push_back(p_color);
- _bake_segment2d(points, colors, 0, 1, p_from, c1, p_to, c2, 0, 3, 9, 3, p_color, p_to_color, lines);
- points.push_back(p_to);
- colors.push_back(p_to_color);
+ float length = (p_from / p_zoom).distance_to(p_to / p_zoom);
+ for (int i = 0; i < points.size(); i++) {
+ float d = (p_from / p_zoom).distance_to(points[i]) / length;
+ colors.push_back(p_color.lerp(p_to_color, d));
+ scaled_points.push_back(points[i] * p_zoom);
+ }
#ifdef TOOLS_ENABLED
- p_where->draw_polyline_colors(points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
+ p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
#else
- p_where->draw_polyline_colors(points, colors, p_width, lines_antialiased);
+ p_where->draw_polyline_colors(scaled_points, colors, p_width, lines_antialiased);
#endif
}
@@ -913,7 +877,7 @@ void GraphEdit::_connections_layer_draw() {
color = color.lerp(activity_color, E->get().activity);
tocolor = tocolor.lerp(activity_color, E->get().activity);
}
- _draw_cos_line(connections_layer, frompos, topos, color, tocolor, lines_thickness);
+ _draw_connection_line(connections_layer, frompos, topos, color, tocolor, lines_thickness, zoom);
}
while (to_erase.size()) {
@@ -952,7 +916,7 @@ void GraphEdit::_top_layer_draw() {
if (!connecting_out) {
SWAP(pos, topos);
}
- _draw_cos_line(top_layer, pos, topos, col, col, lines_thickness);
+ _draw_connection_line(top_layer, pos, topos, col, col, lines_thickness, zoom);
}
if (box_selecting) {
@@ -1056,7 +1020,7 @@ void GraphEdit::_minimap_draw() {
from_color = from_color.lerp(activity_color, E.activity);
to_color = to_color.lerp(activity_color, E.activity);
}
- _draw_cos_line(minimap, from_position, to_position, from_color, to_color, 1.0, 0.5);
+ _draw_connection_line(minimap, from_position, to_position, from_color, to_color, 0.1, minimap->_convert_from_graph_position(Vector2(zoom, zoom)).length());
}
// Draw the "camera" viewport.
@@ -1080,7 +1044,7 @@ void GraphEdit::set_selected(Node *p_child) {
}
}
-void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) {
+void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventMouseMotion> mm = p_ev;
@@ -2048,7 +2012,6 @@ void GraphEdit::arrange_nodes() {
if (gn->is_selected()) {
selected_nodes.insert(gn->get_name());
- origin = origin < gn->get_position_offset() ? origin : gn->get_position_offset();
Set<StringName> s;
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
GraphNode *p_from = Object::cast_to<GraphNode>(node_names[E->get().from]);
@@ -2072,6 +2035,11 @@ void GraphEdit::arrange_nodes() {
}
}
+ if (!selected_nodes.size()) {
+ arranging_graph = false;
+ return;
+ }
+
HashMap<int, Vector<StringName>> layers = _layering(selected_nodes, upper_neighbours);
_crossing_minimisation(layers, upper_neighbours);
@@ -2098,16 +2066,16 @@ void GraphEdit::arrange_nodes() {
for (const Set<StringName>::Element *E = block_heads.front(); E; E = E->next()) {
_place_block(E->get(), gap_v, layers, root, align, node_names, inner_shift, sink, shift, new_positions);
}
+ origin.y = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().y - (new_positions[layers[0][0]].y + (float)inner_shift[layers[0][0]]);
+ origin.x = Object::cast_to<GraphNode>(node_names[layers[0][0]])->get_position_offset().x;
for (const Set<StringName>::Element *E = block_heads.front(); E; E = E->next()) {
StringName u = E->get();
- StringName prev = u;
float start_from = origin.y + new_positions[E->get()].y;
do {
Vector2 cal_pos;
cal_pos.y = start_from + (real_t)inner_shift[u];
new_positions.set(u, cal_pos);
- prev = u;
u = align[u];
} while (u != E->get());
}
@@ -2130,10 +2098,11 @@ void GraphEdit::arrange_nodes() {
if (current_node_size == largest_node_size) {
cal_pos.x = start_from;
} else {
- float current_node_start_pos;
- if (current_node_size >= largest_node_size / 2) {
- current_node_start_pos = start_from;
- } else {
+ float current_node_start_pos = start_from;
+ if (current_node_size < largest_node_size / 2) {
+ if (!(i || j)) {
+ start_from -= (largest_node_size - current_node_size);
+ }
current_node_start_pos = start_from + largest_node_size - current_node_size;
}
cal_pos.x = current_node_start_pos;
@@ -2179,6 +2148,7 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type);
ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type);
ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type);
+ ClassDB::bind_method(D_METHOD("get_connection_line", "from", "to"), &GraphEdit::get_connection_line);
ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom);
@@ -2218,7 +2188,6 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_right_disconnects", "enable"), &GraphEdit::set_right_disconnects);
ClassDB::bind_method(D_METHOD("is_right_disconnects_enabled"), &GraphEdit::is_right_disconnects_enabled);
- ClassDB::bind_method(D_METHOD("_gui_input"), &GraphEdit::_gui_input);
ClassDB::bind_method(D_METHOD("_update_scroll_offset"), &GraphEdit::_update_scroll_offset);
ClassDB::bind_method(D_METHOD("get_zoom_hbox"), &GraphEdit::get_zoom_hbox);
@@ -2227,6 +2196,8 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected);
+ GDVIRTUAL_BIND(_get_connection_line, "from", "to")
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs");
ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 9fd7cbef22..44e50aa3c2 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -62,8 +62,6 @@ class GraphEditMinimap : public Control {
GraphEdit *ge;
protected:
- static void _bind_methods();
-
public:
GraphEditMinimap(GraphEdit *p_edit);
@@ -88,7 +86,7 @@ private:
Vector2 _convert_from_graph_position(const Vector2 &p_position);
Vector2 _convert_to_graph_position(const Vector2 &p_position);
- void _gui_input(const Ref<InputEvent> &p_ev);
+ virtual void gui_input(const Ref<InputEvent> &p_ev) override;
void _adjust_graph_scroll(const Vector2 &p_offset);
};
@@ -169,9 +167,8 @@ private:
float lines_thickness = 2.0f;
bool lines_antialiased = true;
- void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const;
-
- void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0);
+ PackedVector2Array get_connection_line(const Vector2 &p_from, const Vector2 &p_to);
+ void _draw_connection_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_zoom);
void _graph_node_raised(Node *p_gn);
void _graph_node_moved(Node *p_gn);
@@ -179,7 +176,7 @@ private:
void _update_scroll();
void _scroll_moved(double);
- void _gui_input(const Ref<InputEvent> &p_ev);
+ virtual void gui_input(const Ref<InputEvent> &p_ev) override;
Control *connections_layer;
GraphEditFilter *top_layer;
@@ -256,6 +253,8 @@ protected:
virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);
+ GDVIRTUAL2RC(Vector<Vector2>, _get_connection_line, Vector2, Vector2)
+
public:
Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index e85cefcb7b..08c8c60d7a 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -863,7 +863,7 @@ Color GraphNode::get_connection_output_color(int p_idx) {
return conn_output_cache[p_idx].color;
}
-void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) {
+void GraphNode::gui_input(const Ref<InputEvent> &p_ev) {
ERR_FAIL_COND(p_ev.is_null());
Ref<InputEventMouseButton> mb = p_ev;
@@ -946,8 +946,6 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_language", "language"), &GraphNode::set_language);
ClassDB::bind_method(D_METHOD("get_language"), &GraphNode::get_language);
- ClassDB::bind_method(D_METHOD("_gui_input"), &GraphNode::_gui_input);
-
ClassDB::bind_method(D_METHOD("set_slot", "idx", "enable_left", "type_left", "color_left", "enable_right", "type_right", "color_right", "custom_left", "custom_right"), &GraphNode::set_slot, DEFVAL(Ref<Texture2D>()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("clear_slot", "idx"), &GraphNode::clear_slot);
ClassDB::bind_method(D_METHOD("clear_all_slots"), &GraphNode::clear_all_slots);
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index c70f616b47..c7c7006bfc 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -99,7 +99,7 @@ private:
Overlay overlay = OVERLAY_DISABLED;
protected:
- void _gui_input(const Ref<InputEvent> &p_ev);
+ virtual void gui_input(const Ref<InputEvent> &p_ev) override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 258d65112a..8297de9f30 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -48,6 +48,8 @@ void ItemList::_shape(int p_idx) {
} else {
item.text_buf->set_flags(TextServer::BREAK_NONE);
}
+ item.text_buf->set_text_overrun_behavior(text_overrun_behavior);
+ item.text_buf->set_max_lines_visible(max_text_lines);
}
int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bool p_selectable) {
@@ -453,6 +455,7 @@ void ItemList::set_max_text_lines(int p_lines) {
for (int i = 0; i < items.size(); i++) {
if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
items.write[i].text_buf->set_flags(TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::BREAK_GRAPHEME_BOUND);
+ items.write[i].text_buf->set_max_lines_visible(p_lines);
} else {
items.write[i].text_buf->set_flags(TextServer::BREAK_NONE);
}
@@ -534,7 +537,7 @@ Size2 ItemList::Item::get_icon_size() const {
return size_result;
}
-void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
+void ItemList::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
double prev_scroll = scroll_bar->get_value();
@@ -930,8 +933,14 @@ void ItemList::_notification(int p_what) {
}
if (items[i].text != "") {
+ int max_width = -1;
+ if (fixed_column_width) {
+ max_width = fixed_column_width;
+ } else if (same_column_width) {
+ max_width = items[i].rect_cache.size.x;
+ }
+ items.write[i].text_buf->set_width(max_width);
Size2 s = items[i].text_buf->get_size();
- //s.width=MIN(s.width,fixed_column_width);
if (icon_mode == ICON_MODE_TOP) {
minsize.x = MAX(minsize.x, s.width);
@@ -1139,11 +1148,8 @@ void ItemList::_notification(int p_what) {
if (icon_mode == ICON_MODE_TOP) {
pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2);
- pos.y += MIN(
- Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2),
- items[i].rect_cache.size.height - items[i].min_rect_cache.size.height);
- text_ofs.y = icon_size.height + icon_margin;
- text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height;
+ pos.y += icon_margin;
+ text_ofs.y = icon_size.height + icon_margin * 2;
} else {
pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2);
text_ofs.x = icon_size.width + icon_margin;
@@ -1210,7 +1216,6 @@ void ItemList::_notification(int p_what) {
text_ofs.x = size.width - text_ofs.x - max_len;
}
- items.write[i].text_buf->set_width(max_len);
items.write[i].text_buf->set_align(HALIGN_CENTER);
if (outline_size > 0 && font_outline_color.a > 0) {
@@ -1488,6 +1493,21 @@ bool ItemList::has_auto_height() const {
return auto_height;
}
+void ItemList::set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior) {
+ if (text_overrun_behavior != p_behavior) {
+ text_overrun_behavior = p_behavior;
+ for (int i = 0; i < items.size(); i++) {
+ items.write[i].text_buf->set_text_overrun_behavior(p_behavior);
+ }
+ shape_changed = true;
+ update();
+ }
+}
+
+TextParagraph::OverrunBehavior ItemList::get_text_overrun_behavior() const {
+ return text_overrun_behavior;
+}
+
void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_item", "text", "icon", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("add_icon_item", "icon", "selectable"), &ItemList::add_icon_item, DEFVAL(true));
@@ -1594,11 +1614,12 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ItemList::get_v_scroll);
- ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input);
-
ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items);
+ ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &ItemList::set_text_overrun_behavior);
+ ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &ItemList::get_text_overrun_behavior);
+
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
@@ -1606,6 +1627,7 @@ void ItemList::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_text_lines", PROPERTY_HINT_RANGE, "1,10,1,or_greater"), "set_max_text_lines", "get_max_text_lines");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_GROUP("Columns", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_columns", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), "set_max_columns", "get_max_columns");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 86a0174a20..148fa7ba9f 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -95,6 +95,7 @@ private:
SelectMode select_mode = SELECT_SINGLE;
IconMode icon_mode = ICON_MODE_LEFT;
VScrollBar *scroll_bar;
+ TextParagraph::OverrunBehavior text_overrun_behavior = TextParagraph::OVERRUN_NO_TRIMMING;
uint64_t search_time_msec = 0;
String search_string;
@@ -122,7 +123,6 @@ private:
void _set_items(const Array &p_items);
void _scroll_changed(double);
- void _gui_input(const Ref<InputEvent> &p_event);
void _shape(int p_idx);
protected:
@@ -130,6 +130,8 @@ protected:
static void _bind_methods();
public:
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
int add_item(const String &p_item, const Ref<Texture2D> &p_texture = Ref<Texture2D>(), bool p_selectable = true);
int add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable = true);
@@ -182,6 +184,9 @@ public:
void set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_color);
Color get_item_custom_fg_color(int p_idx) const;
+ void set_text_overrun_behavior(TextParagraph::OverrunBehavior p_behavior);
+ TextParagraph::OverrunBehavior get_text_overrun_behavior() const;
+
void select(int p_idx, bool p_single = true);
void deselect(int p_idx);
void deselect_all();
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 11e08b231e..5e9c2d891f 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -216,7 +216,7 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
}
-void LineEdit::_gui_input(Ref<InputEvent> p_event) {
+void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseButton> b = p_event;
@@ -2084,7 +2084,6 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align);
ClassDB::bind_method(D_METHOD("get_align"), &LineEdit::get_align);
- ClassDB::bind_method(D_METHOD("_gui_input"), &LineEdit::_gui_input);
ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear);
ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all);
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 0e9c032e88..e364a79c83 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -202,7 +202,7 @@ private:
protected:
void _notification(int p_what);
static void _bind_methods();
- void _gui_input(Ref<InputEvent> p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index dc6c7fec28..e312aaed57 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -33,7 +33,7 @@
#include "core/os/keyboard.h"
#include "scene/main/window.h"
-void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+void MenuButton::unhandled_key_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!_is_focus_owner_in_shorcut_context()) {
@@ -100,8 +100,8 @@ void MenuButton::pressed() {
popup->popup();
}
-void MenuButton::_gui_input(Ref<InputEvent> p_event) {
- BaseButton::_gui_input(p_event);
+void MenuButton::gui_input(const Ref<InputEvent> &p_event) {
+ BaseButton::gui_input(p_event);
}
PopupMenu *MenuButton::get_popup() const {
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index cc2ca117c4..730495b65d 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -47,14 +47,14 @@ class MenuButton : public Button {
Array _get_items() const;
void _set_items(const Array &p_items);
- void _gui_input(Ref<InputEvent> p_event) override;
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _popup_visibility_changed(bool p_visible);
protected:
void _notification(int p_what);
static void _bind_methods();
- virtual void _unhandled_key_input(Ref<InputEvent> p_event) override;
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
public:
virtual void pressed() override;
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index aff367e398..f75d6755a8 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -251,7 +251,7 @@ void PopupMenu::_submenu_timeout() {
submenu_over = -1;
}
-void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
+void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (p_event->is_action("ui_down") && p_event->is_pressed()) {
@@ -1581,8 +1581,6 @@ void PopupMenu::take_mouse_focus() {
}
void PopupMenu::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &PopupMenu::_gui_input);
-
ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0));
@@ -1708,7 +1706,7 @@ PopupMenu::PopupMenu() {
scroll_container->add_child(control);
control->connect("draw", callable_mp(this, &PopupMenu::_draw_items));
- connect("window_input", callable_mp(this, &PopupMenu::_gui_input));
+ connect("window_input", callable_mp(this, &PopupMenu::gui_input));
submenu_timer = memnew(Timer);
submenu_timer->set_wait_time(0.3);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index aedc5d0155..5c427e43bc 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -31,10 +31,10 @@
#ifndef POPUP_MENU_H
#define POPUP_MENU_H
+#include "core/input/shortcut.h"
#include "scene/gui/margin_container.h"
#include "scene/gui/popup.h"
#include "scene/gui/scroll_container.h"
-#include "scene/gui/shortcut.h"
#include "scene/resources/text_line.h"
class PopupMenu : public Popup {
@@ -107,7 +107,7 @@ class PopupMenu : public Popup {
void _shape_item(int p_item);
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event);
void _activate_submenu(int p_over);
void _submenu_timeout();
diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp
index 39718a269a..236d106af8 100644
--- a/scene/gui/rich_text_effect.cpp
+++ b/scene/gui/rich_text_effect.cpp
@@ -32,8 +32,15 @@
#include "core/object/script_language.h"
-void RichTextEffect::_bind_methods() {
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_process_custom_fx", PropertyInfo(Variant::OBJECT, "char_fx", PROPERTY_HINT_RESOURCE_TYPE, "CharFXTransform")));
+CharFXTransform::CharFXTransform() {
+}
+
+CharFXTransform::~CharFXTransform() {
+ environment.clear();
+}
+
+void RichTextEffect::_bind_methods(){
+ GDVIRTUAL_BIND(_process_custom_fx, "char_fx")
}
Variant RichTextEffect::get_bbcode() const {
@@ -49,15 +56,10 @@ Variant RichTextEffect::get_bbcode() const {
bool RichTextEffect::_process_effect_impl(Ref<CharFXTransform> p_cfx) {
bool return_value = false;
- if (get_script_instance()) {
- Variant v = get_script_instance()->call("_process_custom_fx", p_cfx);
- if (v.get_type() != Variant::BOOL) {
- return_value = false;
- } else {
- return_value = (bool)v;
- }
+ if (GDVIRTUAL_CALL(_process_custom_fx, p_cfx, return_value)) {
+ return return_value;
}
- return return_value;
+ return false;
}
RichTextEffect::RichTextEffect() {
@@ -101,10 +103,3 @@ void CharFXTransform::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
}
-
-CharFXTransform::CharFXTransform() {
-}
-
-CharFXTransform::~CharFXTransform() {
- environment.clear();
-}
diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h
index 67323e7f93..e674b2f62f 100644
--- a/scene/gui/rich_text_effect.h
+++ b/scene/gui/rich_text_effect.h
@@ -32,20 +32,8 @@
#define RICH_TEXT_EFFECT_H
#include "core/io/resource.h"
-
-class RichTextEffect : public Resource {
- GDCLASS(RichTextEffect, Resource);
- OBJ_SAVE_TYPE(RichTextEffect);
-
-protected:
- static void _bind_methods();
-
-public:
- Variant get_bbcode() const;
- bool _process_effect_impl(Ref<class CharFXTransform> p_cfx);
-
- RichTextEffect();
-};
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
class CharFXTransform : public RefCounted {
GDCLASS(CharFXTransform, RefCounted);
@@ -89,4 +77,20 @@ public:
void set_environment(Dictionary p_environment) { environment = p_environment; }
};
+class RichTextEffect : public Resource {
+ GDCLASS(RichTextEffect, Resource);
+ OBJ_SAVE_TYPE(RichTextEffect);
+
+protected:
+ static void _bind_methods();
+
+ GDVIRTUAL1RC(bool, _process_custom_fx, Ref<CharFXTransform>)
+
+public:
+ Variant get_bbcode() const;
+ bool _process_effect_impl(Ref<class CharFXTransform> p_cfx);
+
+ RichTextEffect();
+};
+
#endif // RICH_TEXT_EFFECT_H
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 75c2da7ef9..21a87d4e76 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1451,7 +1451,7 @@ void RichTextLabel::_notification(int p_what) {
Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const {
if (!underline_meta) {
- return CURSOR_ARROW;
+ return get_default_cursor_shape();
}
if (selection.click_item) {
@@ -1459,11 +1459,11 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
}
if (main->first_invalid_line < main->lines.size()) {
- return CURSOR_ARROW; //invalid
+ return get_default_cursor_shape(); //invalid
}
if (main->first_resized_line < main->lines.size()) {
- return CURSOR_ARROW; //invalid
+ return get_default_cursor_shape(); //invalid
}
Item *item = nullptr;
@@ -1474,10 +1474,10 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const
return CURSOR_POINTING_HAND;
}
- return CURSOR_ARROW;
+ return get_default_cursor_shape();
}
-void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
+void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseButton> b = p_event;
@@ -3993,7 +3993,6 @@ void RichTextLabel::_validate_property(PropertyInfo &property) const {
}
void RichTextLabel::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &RichTextLabel::_gui_input);
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 28dfe74b08..ae04a7e684 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -443,7 +443,7 @@ private:
void _update_fx(ItemFrame *p_frame, double p_delta_time);
void _scroll_changed(double);
- void _gui_input(Ref<InputEvent> p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
Item *_get_next_item(Item *p_item, bool p_free = false) const;
Item *_get_prev_item(Item *p_item, bool p_free = false) const;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index ce04a0204b..08bcb0bdda 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -41,7 +41,7 @@ void ScrollBar::set_can_focus_by_default(bool p_can_focus) {
focus_by_default = p_can_focus;
}
-void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
+void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseMotion> m = p_event;
@@ -597,7 +597,6 @@ bool ScrollBar::is_smooth_scroll_enabled() const {
}
void ScrollBar::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollBar::_gui_input);
ClassDB::bind_method(D_METHOD("set_custom_step", "step"), &ScrollBar::set_custom_step);
ClassDB::bind_method(D_METHOD("get_custom_step"), &ScrollBar::get_custom_step);
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 24b3b33e82..fbc035397f 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -86,7 +86,7 @@ class ScrollBar : public Range {
void _drag_node_exit();
void _drag_node_input(const Ref<InputEvent> &p_input);
- void _gui_input(Ref<InputEvent> p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
protected:
void _notification(int p_what);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index eb5fc924da..b5daa8b3f1 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -83,7 +83,7 @@ void ScrollContainer::_cancel_drag() {
}
}
-void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
+void ScrollContainer::gui_input(const Ref<InputEvent> &p_gui_input) {
ERR_FAIL_COND(p_gui_input.is_null());
double prev_v_scroll = v_scroll->get_value();
@@ -568,7 +568,6 @@ VScrollBar *ScrollContainer::get_v_scrollbar() {
}
void ScrollContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollContainer::_gui_input);
ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 4733fdabca..9f4ec558dc 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -68,7 +68,7 @@ class ScrollContainer : public Container {
protected:
Size2 get_minimum_size() const override;
- void _gui_input(const Ref<InputEvent> &p_gui_input);
+ virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
void _gui_focus_changed(Control *p_control);
void _update_dimensions();
void _notification(int p_what);
diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp
deleted file mode 100644
index d0cb08724e..0000000000
--- a/scene/gui/shortcut.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*************************************************************************/
-/* shortcut.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "shortcut.h"
-#include "core/os/keyboard.h"
-
-void Shortcut::set_event(const Ref<InputEvent> &p_event) {
- ERR_FAIL_COND_MSG(Object::cast_to<InputEventShortcut>(*p_event), "Cannot set a shortcut event to an instance of InputEventShortcut.");
- event = p_event;
- emit_changed();
-}
-
-Ref<InputEvent> Shortcut::get_event() const {
- return event;
-}
-
-bool Shortcut::matches_event(const Ref<InputEvent> &p_event) const {
- Ref<InputEventShortcut> ies = p_event;
- if (ies.is_valid()) {
- if (ies->get_shortcut().ptr() == this) {
- return true;
- }
- }
- return event.is_valid() && event->is_match(p_event, true);
-}
-
-String Shortcut::get_as_text() const {
- if (event.is_valid()) {
- return event->as_text();
- } else {
- return "None";
- }
-}
-
-bool Shortcut::has_valid_event() const {
- return event.is_valid();
-}
-
-void Shortcut::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_event", "event"), &Shortcut::set_event);
- ClassDB::bind_method(D_METHOD("get_event"), &Shortcut::get_event);
-
- ClassDB::bind_method(D_METHOD("has_valid_event"), &Shortcut::has_valid_event);
-
- ClassDB::bind_method(D_METHOD("matches_event", "event"), &Shortcut::matches_event);
- ClassDB::bind_method(D_METHOD("get_as_text"), &Shortcut::get_as_text);
-
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), "set_event", "get_event");
-}
diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h
deleted file mode 100644
index 249dd1971f..0000000000
--- a/scene/gui/shortcut.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*************************************************************************/
-/* shortcut.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#ifndef SHORTCUT_H
-#define SHORTCUT_H
-
-#include "core/input/input_event.h"
-#include "core/io/resource.h"
-
-class Shortcut : public Resource {
- GDCLASS(Shortcut, Resource);
-
- Ref<InputEvent> event;
-
-protected:
- static void _bind_methods();
-
-public:
- void set_event(const Ref<InputEvent> &p_shortcut);
- Ref<InputEvent> get_event() const;
- bool matches_event(const Ref<InputEvent> &p_event) const;
- bool has_valid_event() const;
-
- String get_as_text() const;
-};
-
-#endif // SHORTCUT_H
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 61b5325175..352f87954e 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -45,7 +45,7 @@ Size2 Slider::get_minimum_size() const {
}
}
-void Slider::_gui_input(Ref<InputEvent> p_event) {
+void Slider::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!editable) {
@@ -253,7 +253,6 @@ bool Slider::is_scrollable() const {
}
void Slider::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &Slider::_gui_input);
ClassDB::bind_method(D_METHOD("set_ticks", "count"), &Slider::set_ticks);
ClassDB::bind_method(D_METHOD("get_ticks"), &Slider::get_ticks);
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 65a4036cd1..46fa08bbf0 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -50,7 +50,7 @@ class Slider : public Range {
bool scrollable = true;
protected:
- void _gui_input(Ref<InputEvent> p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
static void _bind_methods();
bool ticks_on_borders = false;
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 3f0368a4e2..65a3eb3adf 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -99,7 +99,7 @@ void SpinBox::_release_mouse() {
}
}
-void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
+void SpinBox::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (!is_editable()) {
@@ -258,7 +258,7 @@ void SpinBox::apply() {
void SpinBox::_bind_methods() {
//ClassDB::bind_method(D_METHOD("_value_changed"),&SpinBox::_value_changed);
- ClassDB::bind_method(D_METHOD("_gui_input"), &SpinBox::_gui_input);
+
ClassDB::bind_method(D_METHOD("set_align", "align"), &SpinBox::set_align);
ClassDB::bind_method(D_METHOD("get_align"), &SpinBox::get_align);
ClassDB::bind_method(D_METHOD("set_suffix", "suffix"), &SpinBox::set_suffix);
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index fb10379296..9ec3885f1f 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -65,7 +65,7 @@ class SpinBox : public Range {
inline void _adjust_width_for_icon(const Ref<Texture2D> &icon);
protected:
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 3114e5b7c0..4736a1ad37 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -206,7 +206,7 @@ void SplitContainer::_notification(int p_what) {
}
}
-void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
+void SplitContainer::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility != DRAGGER_VISIBLE) {
@@ -337,8 +337,6 @@ bool SplitContainer::is_collapsed() const {
}
void SplitContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &SplitContainer::_gui_input);
-
ClassDB::bind_method(D_METHOD("set_split_offset", "offset"), &SplitContainer::set_split_offset);
ClassDB::bind_method(D_METHOD("get_split_offset"), &SplitContainer::get_split_offset);
ClassDB::bind_method(D_METHOD("clamp_split_offset"), &SplitContainer::clamp_split_offset);
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 6cb94d6ecf..47fd30a122 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -60,7 +60,7 @@ private:
void _resort();
protected:
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp
index bfc7e29f9c..53ea32e1b7 100644
--- a/scene/gui/subviewport_container.cpp
+++ b/scene/gui/subviewport_container.cpp
@@ -139,7 +139,7 @@ void SubViewportContainer::_notification(int p_what) {
}
}
-void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
+void SubViewportContainer::input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (Engine::get_singleton()->is_editor_hint()) {
@@ -162,11 +162,11 @@ void SubViewportContainer::_input(const Ref<InputEvent> &p_event) {
continue;
}
- c->input(ev);
+ c->push_input(ev);
}
}
-void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
+void SubViewportContainer::unhandled_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
if (Engine::get_singleton()->is_editor_hint()) {
@@ -189,13 +189,11 @@ void SubViewportContainer::_unhandled_input(const Ref<InputEvent> &p_event) {
continue;
}
- c->unhandled_input(ev);
+ c->push_unhandled_input(ev);
}
}
void SubViewportContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_unhandled_input", "event"), &SubViewportContainer::_unhandled_input);
- ClassDB::bind_method(D_METHOD("_input", "event"), &SubViewportContainer::_input);
ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &SubViewportContainer::set_stretch);
ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &SubViewportContainer::is_stretch_enabled);
diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h
index 77cf4c16b3..7853f1590e 100644
--- a/scene/gui/subviewport_container.h
+++ b/scene/gui/subviewport_container.h
@@ -47,8 +47,8 @@ public:
void set_stretch(bool p_enable);
bool is_stretch_enabled() const;
- void _input(const Ref<InputEvent> &p_event);
- void _unhandled_input(const Ref<InputEvent> &p_event);
+ virtual void input(const Ref<InputEvent> &p_event) override;
+ virtual void unhandled_input(const Ref<InputEvent> &p_event) override;
void set_stretch_shrink(int p_shrink);
int get_stretch_shrink() const;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 53a2fe4d93..5884d2a854 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -71,7 +71,7 @@ int TabContainer::_get_top_margin() const {
return tab_height + content_height;
}
-void TabContainer::_gui_input(const Ref<InputEvent> &p_event) {
+void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseButton> mb = p_event;
@@ -1193,7 +1193,6 @@ bool TabContainer::get_use_hidden_tabs_for_min_size() const {
}
void TabContainer::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input);
ClassDB::bind_method(D_METHOD("get_tab_count"), &TabContainer::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &TabContainer::set_current_tab);
ClassDB::bind_method(D_METHOD("get_current_tab"), &TabContainer::get_current_tab);
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 35f18eff8e..fe96df25e8 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -76,7 +76,7 @@ private:
protected:
void _child_renamed_callback();
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 103860ad78..3ca2d1c1e9 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -90,7 +90,7 @@ Size2 Tabs::get_minimum_size() const {
return ms;
}
-void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
+void Tabs::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseMotion> mm = p_event;
@@ -1107,7 +1107,6 @@ bool Tabs::get_select_with_rmb() const {
}
void Tabs::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover);
ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab);
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 61c9a5d96a..b044453803 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -112,7 +112,7 @@ private:
void _shape(int p_tab);
protected:
- void _gui_input(const Ref<InputEvent> &p_event);
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 87f06445ac..61dfec6abe 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1305,7 +1305,7 @@ void TextEdit::_notification(int p_what) {
}
}
-void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
+void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
ERR_FAIL_COND(p_gui_input.is_null());
double prev_v_scroll = v_scroll->get_value();
@@ -2150,7 +2150,6 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
next_column = column;
} else {
// Delete one character
- next_column = caret.column < curline_len ? (caret.column + 1) : 0;
if (caret_mid_grapheme_enabled) {
next_column = caret.column < curline_len ? (caret.column + 1) : 0;
} else {
@@ -2768,48 +2767,38 @@ Point2i TextEdit::get_next_visible_line_index_offset_from(int p_line_from, int p
// Overridable actions
void TextEdit::handle_unicode_input(const uint32_t p_unicode) {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_handle_unicode_input")) {
- si->call("_handle_unicode_input", p_unicode);
+ if (GDVIRTUAL_CALL(_handle_unicode_input, p_unicode)) {
return;
}
- _handle_unicode_input(p_unicode);
+ _handle_unicode_input_internal(p_unicode);
}
void TextEdit::backspace() {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_backspace")) {
- si->call("_backspace");
+ if (GDVIRTUAL_CALL(_backspace)) {
return;
}
- _backspace();
+ _backspace_internal();
}
void TextEdit::cut() {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_cut")) {
- si->call("_cut");
+ if (GDVIRTUAL_CALL(_cut)) {
return;
}
- _cut();
+ _cut_internal();
}
void TextEdit::copy() {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_copy")) {
- si->call("_copy");
+ if (GDVIRTUAL_CALL(_copy)) {
return;
}
- _copy();
+ _copy_internal();
}
void TextEdit::paste() {
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_paste")) {
- si->call("_paste");
+ if (GDVIRTUAL_CALL(_paste)) {
return;
}
- _paste();
+ _paste_internal();
}
// Context menu.
@@ -4377,7 +4366,7 @@ bool TextEdit::is_drawing_spaces() const {
void TextEdit::_bind_methods() {
/*Internal. */
- ClassDB::bind_method(D_METHOD("_gui_input"), &TextEdit::_gui_input);
+
ClassDB::bind_method(D_METHOD("_text_changed_emit"), &TextEdit::_text_changed_emit);
/* Text */
@@ -4452,12 +4441,11 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste);
- BIND_VMETHOD(MethodInfo("_handle_unicode_input", PropertyInfo(Variant::INT, "unicode")))
- BIND_VMETHOD(MethodInfo("_backspace"));
-
- BIND_VMETHOD(MethodInfo("_cut"));
- BIND_VMETHOD(MethodInfo("_copy"));
- BIND_VMETHOD(MethodInfo("_paste"));
+ GDVIRTUAL_BIND(_handle_unicode_input, "unicode_char")
+ GDVIRTUAL_BIND(_backspace)
+ GDVIRTUAL_BIND(_cut)
+ GDVIRTUAL_BIND(_copy)
+ GDVIRTUAL_BIND(_paste)
// Context Menu
BIND_ENUM_CONSTANT(MENU_CUT);
@@ -4884,7 +4872,7 @@ void TextEdit::_set_symbol_lookup_word(const String &p_symbol) {
/* Text manipulation */
// Overridable actions
-void TextEdit::_handle_unicode_input(const uint32_t p_unicode) {
+void TextEdit::_handle_unicode_input_internal(const uint32_t p_unicode) {
if (!editable) {
return;
}
@@ -4915,7 +4903,7 @@ void TextEdit::_handle_unicode_input(const uint32_t p_unicode) {
}
}
-void TextEdit::_backspace() {
+void TextEdit::_backspace_internal() {
if (!editable) {
return;
}
@@ -4946,7 +4934,7 @@ void TextEdit::_backspace() {
set_caret_column(prev_column);
}
-void TextEdit::_cut() {
+void TextEdit::_cut_internal() {
if (!editable) {
return;
}
@@ -4976,7 +4964,7 @@ void TextEdit::_cut() {
cut_copy_line = clipboard;
}
-void TextEdit::_copy() {
+void TextEdit::_copy_internal() {
if (has_selection()) {
DisplayServer::get_singleton()->clipboard_set(get_selected_text());
cut_copy_line = "";
@@ -4991,7 +4979,7 @@ void TextEdit::_copy() {
}
}
-void TextEdit::_paste() {
+void TextEdit::_paste_internal() {
if (!editable) {
return;
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 69468978ab..ced03e19d0 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -528,7 +528,7 @@ private:
protected:
void _notification(int p_what);
- virtual void _gui_input(const Ref<InputEvent> &p_gui_input);
+ virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
static void _bind_methods();
@@ -562,12 +562,18 @@ protected:
/* Text manipulation */
// Overridable actions
- virtual void _handle_unicode_input(const uint32_t p_unicode);
- virtual void _backspace();
-
- virtual void _cut();
- virtual void _copy();
- virtual void _paste();
+ virtual void _handle_unicode_input_internal(const uint32_t p_unicode);
+ virtual void _backspace_internal();
+
+ virtual void _cut_internal();
+ virtual void _copy_internal();
+ virtual void _paste_internal();
+
+ GDVIRTUAL1(_handle_unicode_input, int)
+ GDVIRTUAL0(_backspace)
+ GDVIRTUAL0(_cut)
+ GDVIRTUAL0(_copy)
+ GDVIRTUAL0(_paste)
public:
/* General overrides. */
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index d9892b53fc..5f07f5216a 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2768,7 +2768,7 @@ void Tree::_go_down() {
accept_event();
}
-void Tree::_gui_input(Ref<InputEvent> p_event) {
+void Tree::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventKey> k = p_event;
@@ -4650,8 +4650,6 @@ bool Tree::get_allow_reselect() const {
}
void Tree::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_gui_input"), &Tree::_gui_input);
-
ClassDB::bind_method(D_METHOD("clear"), &Tree::clear);
ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1));
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index c207737cc0..cce8b527db 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -462,7 +462,6 @@ private:
void popup_select(int p_option);
- void _gui_input(Ref<InputEvent> p_event);
void _notification(int p_what);
void item_edited(int p_column, TreeItem *p_item, bool p_lmb = true);
@@ -626,6 +625,8 @@ protected:
}
public:
+ virtual void gui_input(const Ref<InputEvent> &p_event) override;
+
virtual String get_tooltip(const Point2 &p_pos) const override;
TreeItem *get_item_at_position(const Point2 &p_pos) const;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index f2415eaf71..f329332725 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -151,9 +151,7 @@ void CanvasItem::_update_callback() {
current_item_drawn = this;
notification(NOTIFICATION_DRAW);
emit_signal(SceneStringNames::get_singleton()->draw);
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_draw);
- }
+ GDVIRTUAL_CALL(_draw);
current_item_drawn = nullptr;
drawing = false;
}
@@ -934,7 +932,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_clip_children", "enable"), &CanvasItem::set_clip_children);
ClassDB::bind_method(D_METHOD("is_clipping_children"), &CanvasItem::is_clipping_children);
- BIND_VMETHOD(MethodInfo("_draw"));
+ GDVIRTUAL_BIND(_draw);
ADD_GROUP("Visibility", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index dc7ad2bf5d..a591cab485 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -142,6 +142,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ GDVIRTUAL0(_draw)
public:
enum {
NOTIFICATION_TRANSFORM_CHANGED = SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 155af30a6d..9fce00be60 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -54,16 +54,11 @@ int Node::orphan_node_count = 0;
void Node::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_PROCESS: {
- if (get_script_instance()) {
- Variant time = get_process_delta_time();
- get_script_instance()->call(SceneStringNames::get_singleton()->_process, time);
- }
+ GDVIRTUAL_CALL(_process, get_process_delta_time());
+
} break;
case NOTIFICATION_PHYSICS_PROCESS: {
- if (get_script_instance()) {
- Variant time = get_physics_process_delta_time();
- get_script_instance()->call(SceneStringNames::get_singleton()->_physics_process, time);
- }
+ GDVIRTUAL_CALL(_physics_process, get_process_delta_time());
} break;
case NOTIFICATION_ENTER_TREE: {
@@ -128,27 +123,26 @@ void Node::_notification(int p_notification) {
} break;
case NOTIFICATION_READY: {
if (get_script_instance()) {
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_input)) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_input)) {
set_process_input(true);
}
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_input)) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_unhandled_input)) {
set_process_unhandled_input(true);
}
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_unhandled_key_input)) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_unhandled_key_input)) {
set_process_unhandled_key_input(true);
}
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_process)) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_process)) {
set_process(true);
}
-
- if (get_script_instance()->has_method(SceneStringNames::get_singleton()->_physics_process)) {
+ if (GDVIRTUAL_IS_OVERRIDEN(_physics_process)) {
set_physics_process(true);
}
- get_script_instance()->call(SceneStringNames::get_singleton()->_ready);
+ GDVIRTUAL_CALL(_ready);
}
if (data.filename.length()) {
ERR_FAIL_COND(!is_inside_tree());
@@ -221,9 +215,7 @@ void Node::_propagate_enter_tree() {
notification(NOTIFICATION_ENTER_TREE);
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_enter_tree);
- }
+ GDVIRTUAL_CALL(_enter_tree);
emit_signal(SceneStringNames::get_singleton()->tree_entered);
@@ -269,9 +261,8 @@ void Node::_propagate_exit_tree() {
data.blocked--;
- if (get_script_instance()) {
- get_script_instance()->call(SceneStringNames::get_singleton()->_exit_tree);
- }
+ GDVIRTUAL_CALL(_exit_tree);
+
emit_signal(SceneStringNames::get_singleton()->tree_exiting);
notification(NOTIFICATION_EXIT_TREE, true);
@@ -2496,9 +2487,14 @@ void Node::clear_internal_tree_resource_paths() {
}
TypedArray<String> Node::get_configuration_warnings() const {
- if (get_script_instance() && get_script_instance()->get_script().is_valid() &&
- get_script_instance()->get_script()->is_tool() && get_script_instance()->has_method("_get_configuration_warnings")) {
- return get_script_instance()->call("_get_configuration_warnings");
+ Vector<String> warnings;
+ if (GDVIRTUAL_CALL(_get_configuration_warnings, warnings)) {
+ TypedArray<String> ret;
+ ret.resize(warnings.size());
+ for (int i = 0; i < warnings.size(); i++) {
+ ret[i] = warnings[i];
+ }
+ return ret;
}
return Array();
}
@@ -2544,6 +2540,37 @@ void Node::request_ready() {
data.ready_first = true;
}
+void Node::_call_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ input(p_event);
+}
+void Node::_call_unhandled_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_unhandled_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ unhandled_input(p_event);
+}
+void Node::_call_unhandled_key_input(const Ref<InputEvent> &p_event) {
+ GDVIRTUAL_CALL(_unhandled_key_input, p_event);
+ if (!is_inside_tree() || !get_viewport() || get_viewport()->is_input_handled()) {
+ return;
+ }
+ unhandled_key_input(p_event);
+}
+
+void Node::input(const Ref<InputEvent> &p_event) {
+}
+
+void Node::unhandled_input(const Ref<InputEvent> &p_event) {
+}
+
+void Node::unhandled_key_input(const Ref<InputEvent> &p_key_event) {
+}
+
void Node::_bind_methods() {
GLOBAL_DEF("editor/node_naming/name_num_separator", 0);
ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_num_separator", PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash"));
@@ -2625,6 +2652,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder);
ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder);
+ ClassDB::bind_method(D_METHOD("set_editable_instance", "node", "is_editable"), &Node::set_editable_instance);
+ ClassDB::bind_method(D_METHOD("is_editable_instance", "node"), &Node::is_editable_instance);
ClassDB::bind_method(D_METHOD("get_viewport"), &Node::get_viewport);
@@ -2737,15 +2766,15 @@ void Node::_bind_methods() {
ADD_GROUP("Editor Description", "editor_");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "set_editor_description", "get_editor_description");
- BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_enter_tree"));
- BIND_VMETHOD(MethodInfo("_exit_tree"));
- BIND_VMETHOD(MethodInfo("_ready"));
- BIND_VMETHOD(MethodInfo("_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_unhandled_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent")));
- BIND_VMETHOD(MethodInfo("_unhandled_key_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEventKey")));
- BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::ARRAY, "", PROPERTY_HINT_ARRAY_TYPE, "String"), "_get_configuration_warnings"));
+ GDVIRTUAL_BIND(_process, "delta");
+ GDVIRTUAL_BIND(_physics_process, "delta");
+ GDVIRTUAL_BIND(_enter_tree);
+ GDVIRTUAL_BIND(_exit_tree);
+ GDVIRTUAL_BIND(_ready);
+ GDVIRTUAL_BIND(_get_configuration_warnings);
+ GDVIRTUAL_BIND(_input, "event");
+ GDVIRTUAL_BIND(_unhandled_input, "event");
+ GDVIRTUAL_BIND(_unhandled_key_input, "event");
}
String Node::_get_name_num_separator() {
diff --git a/scene/main/node.h b/scene/main/node.h
index 6616524866..a07accba2f 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -208,6 +208,27 @@ protected:
void _set_owner_nocheck(Node *p_owner);
void _set_name_nocheck(const StringName &p_name);
+ //call from SceneTree
+ void _call_input(const Ref<InputEvent> &p_event);
+ void _call_unhandled_input(const Ref<InputEvent> &p_event);
+ void _call_unhandled_key_input(const Ref<InputEvent> &p_event);
+
+protected:
+ virtual void input(const Ref<InputEvent> &p_event);
+ virtual void unhandled_input(const Ref<InputEvent> &p_event);
+ virtual void unhandled_key_input(const Ref<InputEvent> &p_key_event);
+
+ GDVIRTUAL1(_process, double)
+ GDVIRTUAL1(_physics_process, double)
+ GDVIRTUAL0(_enter_tree)
+ GDVIRTUAL0(_exit_tree)
+ GDVIRTUAL0(_ready)
+ GDVIRTUAL0RC(Vector<String>, _get_configuration_warnings)
+
+ GDVIRTUAL1(_input, Ref<InputEvent>)
+ GDVIRTUAL1(_unhandled_input, Ref<InputEvent>)
+ GDVIRTUAL1(_unhandled_key_input, Ref<InputEvent>)
+
public:
enum {
// you can make your own, but don't use the same numbers as other notifications in other nodes
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 5b707498a7..8260d0dff5 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -867,7 +867,7 @@ void SceneMainLoop::_update_listener_2d() {
*/
-void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
+void SceneTree::_call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport) {
Map<StringName, Group>::Element *E = group_map.find(p_group);
if (!E) {
return;
@@ -886,9 +886,6 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
int node_count = nodes_copy.size();
Node **nodes = nodes_copy.ptrw();
- Variant arg = p_input;
- const Variant *v[1] = { &arg };
-
call_lock++;
for (int i = node_count - 1; i >= 0; i--) {
@@ -905,14 +902,16 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p
continue;
}
- Callable::CallError err;
- // Call both script and native method.
- if (n->get_script_instance()) {
- n->get_script_instance()->call(p_method, (const Variant **)v, 1, err);
- }
- MethodBind *method = ClassDB::get_method(n->get_class_name(), p_method);
- if (method) {
- method->call(n, (const Variant **)v, 1, err);
+ switch (p_call_type) {
+ case CALL_INPUT_TYPE_INPUT:
+ n->_call_input(p_input);
+ break;
+ case CALL_INPUT_TYPE_UNHANDLED_INPUT:
+ n->_call_unhandled_input(p_input);
+ break;
+ case CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT:
+ n->_call_unhandled_key_input(p_input);
+ break;
}
}
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index cfb95bd6b5..b1b94ae910 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -204,8 +204,14 @@ private:
void _main_window_close();
void _main_window_go_back();
+ enum CallInputType {
+ CALL_INPUT_TYPE_INPUT,
+ CALL_INPUT_TYPE_UNHANDLED_INPUT,
+ CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT,
+ };
+
//used by viewport
- void _call_input_pause(const StringName &p_group, const StringName &p_method, const Ref<InputEvent> &p_input, Viewport *p_viewport);
+ void _call_input_pause(const StringName &p_group, CallInputType p_call_type, const Ref<InputEvent> &p_input, Viewport *p_viewport);
protected:
void _notification(int p_notification);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 78fa0985a9..ea2323c651 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
+#include "core/object/message_queue.h"
#include "core/string/translation.h"
#include "core/templates/pair.h"
#include "scene/2d/camera_2d.h"
@@ -662,7 +663,7 @@ void Viewport::_process_picking() {
}
if (send_event) {
- co->_input_event(this, ev, res[i].shape);
+ co->_input_event_call(this, ev, res[i].shape);
}
}
}
@@ -1234,27 +1235,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Control *control = Object::cast_to<Control>(ci);
if (control) {
if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
- control->emit_signal(SceneStringNames::get_singleton()->gui_input, ev); //signal should be first, so it's possible to override an event (and then accept it)
- }
- if (gui.key_event_accepted) {
- break;
- }
- if (!control->is_inside_tree()) {
- break;
- }
-
- if (control->data.mouse_filter != Control::MOUSE_FILTER_IGNORE) {
- // Call both script and native methods.
- Callable::CallError error;
- Variant event = ev;
- const Variant *args[1] = { &event };
- if (control->get_script_instance()) {
- control->get_script_instance()->call(SceneStringNames::get_singleton()->_gui_input, args, 1, error);
- }
- MethodBind *method = ClassDB::get_method(control->get_class_name(), SceneStringNames::get_singleton()->_gui_input);
- if (method) {
- method->call(control, args, 1, error);
- }
+ control->_call_gui_input(ev);
}
if (!control->is_inside_tree() || control->is_set_as_top_level()) {
@@ -1982,10 +1963,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.key_focus) {
gui.key_event_accepted = false;
if (gui.key_focus->can_process()) {
- gui.key_focus->call(SceneStringNames::get_singleton()->_gui_input, p_event);
- if (gui.key_focus) { //maybe lost it
- gui.key_focus->emit_signal(SceneStringNames::get_singleton()->gui_input, p_event);
- }
+ gui.key_focus->_call_gui_input(p_event);
}
if (gui.key_event_accepted) {
@@ -2205,7 +2183,7 @@ void Viewport::_drop_mouse_focus() {
mb->set_global_position(c->get_local_mouse_position());
mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(false);
- c->call(SceneStringNames::get_singleton()->_gui_input, mb);
+ c->_call_gui_input(mb);
}
}
}
@@ -2317,7 +2295,7 @@ void Viewport::_post_gui_grab_click_focus() {
mb->set_position(click);
mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(false);
- gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb);
+ gui.mouse_focus->_call_gui_input(mb);
}
}
@@ -2335,7 +2313,7 @@ void Viewport::_post_gui_grab_click_focus() {
mb->set_position(click);
mb->set_button_index(MouseButton(i + 1));
mb->set_pressed(true);
- gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
+ MessageQueue::get_singleton()->push_callable(callable_mp(gui.mouse_focus, &Control::_call_gui_input), mb);
}
}
}
@@ -2343,9 +2321,9 @@ void Viewport::_post_gui_grab_click_focus() {
///////////////////////////////
-void Viewport::input_text(const String &p_text) {
+void Viewport::push_text_input(const String &p_text) {
if (gui.subwindow_focused) {
- gui.subwindow_focused->input_text(p_text);
+ gui.subwindow_focused->push_text_input(p_text);
return;
}
@@ -2665,7 +2643,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
return true;
}
-void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+void Viewport::push_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(!is_inside_tree());
if (disable_input) {
@@ -2695,7 +2673,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
}
if (!is_input_handled()) {
- get_tree()->_call_input_pause(input_group, "_input", ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
+ get_tree()->_call_input_pause(input_group, SceneTree::CALL_INPUT_TYPE_INPUT, ev, this); //not a bug, must happen before GUI, order is _input -> gui input -> _unhandled input
}
if (!is_input_handled()) {
@@ -2703,10 +2681,9 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) {
}
event_count++;
- //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",ev); //special one for GUI, as controls use their own process check
}
-void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
+void Viewport::push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords) {
ERR_FAIL_COND(p_event.is_null());
ERR_FAIL_COND(!is_inside_tree());
local_input_handled = false;
@@ -2727,11 +2704,11 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor
}
// Unhandled Input
- get_tree()->_call_input_pause(unhandled_input_group, "_unhandled_input", ev, this);
+ get_tree()->_call_input_pause(unhandled_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_INPUT, ev, this);
// Unhandled key Input - used for performance reasons - This is called a lot less than _unhandled_input since it ignores MouseMotion, etc
if (!is_input_handled() && (Object::cast_to<InputEventKey>(*ev) != nullptr || Object::cast_to<InputEventShortcut>(*ev) != nullptr)) {
- get_tree()->_call_input_pause(unhandled_key_input_group, "_unhandled_key_input", ev, this);
+ get_tree()->_call_input_pause(unhandled_key_input_group, SceneTree::CALL_INPUT_TYPE_UNHANDLED_KEY_INPUT, ev, this);
}
if (physics_object_picking && !is_input_handled()) {
@@ -3159,7 +3136,7 @@ void Viewport::_collision_object_3d_input_event(CollisionObject3D *p_object, Cam
return; //discarded
}
}
- p_object->_input_event(camera_3d, p_input_event, p_pos, p_normal, p_shape);
+ p_object->_input_event_call(camera_3d, p_input_event, p_pos, p_normal, p_shape);
physics_last_object_transform = object_transform;
physics_last_camera_transform = camera_transform;
physics_last_id = id;
@@ -3515,9 +3492,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_object_picking"), &Viewport::get_physics_object_picking);
ClassDB::bind_method(D_METHOD("get_viewport_rid"), &Viewport::get_viewport_rid);
- ClassDB::bind_method(D_METHOD("input_text", "text"), &Viewport::input_text);
- ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("push_text_input", "text"), &Viewport::push_text_input);
+ ClassDB::bind_method(D_METHOD("push_input", "event", "in_local_coords"), &Viewport::push_input, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("push_unhandled_input", "event", "in_local_coords"), &Viewport::push_unhandled_input, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_camera_2d"), &Viewport::get_camera_2d);
ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d);
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 9c51f404d7..b24de77e6b 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -508,9 +508,9 @@ public:
Vector2 get_camera_coords(const Vector2 &p_viewport_coords) const;
Vector2 get_camera_rect_size() const;
- void input_text(const String &p_text);
- void input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
- void unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void push_text_input(const String &p_text);
+ void push_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
+ void push_unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coords = false);
void set_disable_input(bool p_disable);
bool is_input_disabled() const;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 73eec73d75..b9c0ae5a4a 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -916,14 +916,14 @@ void Window::_window_input(const Ref<InputEvent> &p_ev) {
emit_signal(SceneStringNames::get_singleton()->window_input, p_ev);
- input(p_ev);
+ push_input(p_ev);
if (!is_input_handled()) {
- unhandled_input(p_ev);
+ push_unhandled_input(p_ev);
}
}
void Window::_window_input_text(const String &p_text) {
- input_text(p_text);
+ push_text_input(p_text);
}
void Window::_window_drop_files(const Vector<String> &p_files) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 6f8091c03f..2cea3c2337 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -320,7 +320,6 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- GDREGISTER_CLASS(Shortcut);
GDREGISTER_CLASS(Control);
GDREGISTER_CLASS(Button);
GDREGISTER_CLASS(Label);
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index e6a74e7685..b4eec2530b 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -29,9 +29,9 @@
/*************************************************************************/
#include "animation.h"
-#include "scene/scene_string_names.h"
#include "core/math/geometry_3d.h"
+#include "scene/scene_string_names.h"
bool Animation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
@@ -79,15 +79,16 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]);
Vector<real_t> values = p_value;
int vcount = values.size();
- ERR_FAIL_COND_V(vcount % 12, false); // should be multiple of 12
+ ERR_FAIL_COND_V(vcount % TRANSFORM_TRACK_SIZE, false);
const real_t *r = values.ptr();
- tt->transforms.resize(vcount / 12);
+ int64_t count = vcount / TRANSFORM_TRACK_SIZE;
+ tt->transforms.resize(count);
- for (int i = 0; i < (vcount / 12); i++) {
+ for (int i = 0; i < count; i++) {
TKey<TransformKey> &tk = tt->transforms.write[i];
- const real_t *ofs = &r[i * 12];
+ const real_t *ofs = &r[i * TRANSFORM_TRACK_SIZE];
tk.time = ofs[0];
tk.transition = ofs[1];
@@ -354,7 +355,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
if (track_get_type(track) == TYPE_TRANSFORM3D) {
Vector<real_t> keys;
int kk = track_get_key_count(track);
- keys.resize(kk * sizeof(Transform3D));
+ keys.resize(kk * TRANSFORM_TRACK_SIZE);
real_t *w = keys.ptrw();
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 6227f6967f..9a410bd566 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -92,6 +92,9 @@ private:
Vector3 scale;
};
+ // Not necessarily the same size as Transform3D. The amount of numbers in Animation::Key and TransformKey.
+ const int32_t TRANSFORM_TRACK_SIZE = 12;
+
/* TRANSFORM TRACK */
struct TransformTrack : public Track {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 3b666640f8..a364a27e80 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -662,19 +662,27 @@ void Curve2D::_bake() const {
if (points.size() == 0) {
baked_point_cache.resize(0);
+ baked_dist_cache.resize(0);
return;
}
if (points.size() == 1) {
baked_point_cache.resize(1);
baked_point_cache.set(0, points[0].pos);
+
+ baked_dist_cache.resize(1);
+ baked_dist_cache.set(0, 0.0);
return;
}
Vector2 pos = points[0].pos;
+ float dist = 0.0;
+
List<Vector2> pointlist;
+ List<float> distlist;
pointlist.push_back(pos); //start always from origin
+ distlist.push_back(0.0);
for (int i = 0; i < points.size() - 1; i++) {
float step = 0.1; // at least 10 substeps ought to be enough?
@@ -712,7 +720,10 @@ void Curve2D::_bake() const {
pos = npp;
p = mid;
+ dist += d;
+
pointlist.push_back(pos);
+ distlist.push_back(dist);
} else {
p = np;
}
@@ -722,16 +733,20 @@ void Curve2D::_bake() const {
Vector2 lastpos = points[points.size() - 1].pos;
float rem = pos.distance_to(lastpos);
- baked_max_ofs = (pointlist.size() - 1) * bake_interval + rem;
+ dist += rem;
+ baked_max_ofs = dist;
pointlist.push_back(lastpos);
+ distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
+ baked_dist_cache.resize(distlist.size());
+
Vector2 *w = baked_point_cache.ptrw();
- int idx = 0;
+ float *wd = baked_dist_cache.ptrw();
- for (const Vector2 &E : pointlist) {
- w[idx] = E;
- idx++;
+ for (int i = 0; i < pointlist.size(); i++) {
+ w[i] = pointlist[i];
+ wd[i] = distlist[i];
}
}
@@ -766,19 +781,26 @@ Vector2 Curve2D::interpolate_baked(float p_offset, bool p_cubic) const {
return r[bpc - 1];
}
- int idx = Math::floor((double)p_offset / (double)bake_interval);
- float frac = Math::fmod(p_offset, (float)bake_interval);
-
- if (idx >= bpc - 1) {
- return r[bpc - 1];
- } else if (idx == bpc - 2) {
- if (frac > 0) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ int start = 0, end = bpc, idx = (end + start) / 2;
+ // binary search to find baked points
+ while (start < idx) {
+ float offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
}
- } else {
- frac /= bake_interval;
+ idx = (end + start) / 2;
}
+ float offset_begin = baked_dist_cache[idx];
+ float offset_end = baked_dist_cache[idx + 1];
+
+ float idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector2(), "failed to find baked segment");
+
+ float frac = (p_offset - offset_begin) / idx_interval;
+
if (p_cubic) {
Vector2 pre = idx > 0 ? r[idx - 1] : r[idx];
Vector2 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
@@ -1145,6 +1167,7 @@ void Curve3D::_bake() const {
baked_point_cache.resize(0);
baked_tilt_cache.resize(0);
baked_up_vector_cache.resize(0);
+ baked_dist_cache.resize(0);
return;
}
@@ -1153,6 +1176,8 @@ void Curve3D::_bake() const {
baked_point_cache.set(0, points[0].pos);
baked_tilt_cache.resize(1);
baked_tilt_cache.set(0, points[0].tilt);
+ baked_dist_cache.resize(1);
+ baked_dist_cache.set(0, 0.0);
if (up_vector_enabled) {
baked_up_vector_cache.resize(1);
@@ -1165,8 +1190,12 @@ void Curve3D::_bake() const {
}
Vector3 pos = points[0].pos;
+ float dist = 0.0;
List<Plane> pointlist;
+ List<float> distlist;
+
pointlist.push_back(Plane(pos, points[0].tilt));
+ distlist.push_back(0.0);
for (int i = 0; i < points.size() - 1; i++) {
float step = 0.1; // at least 10 substeps ought to be enough?
@@ -1207,7 +1236,10 @@ void Curve3D::_bake() const {
Plane post;
post.normal = pos;
post.d = Math::lerp(points[i].tilt, points[i + 1].tilt, mid);
+ dist += d;
+
pointlist.push_back(post);
+ distlist.push_back(dist);
} else {
p = np;
}
@@ -1218,8 +1250,10 @@ void Curve3D::_bake() const {
float lastilt = points[points.size() - 1].tilt;
float rem = pos.distance_to(lastpos);
- baked_max_ofs = (pointlist.size() - 1) * bake_interval + rem;
+ dist += rem;
+ baked_max_ofs = dist;
pointlist.push_back(Plane(lastpos, lastilt));
+ distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
Vector3 *w = baked_point_cache.ptrw();
@@ -1231,6 +1265,9 @@ void Curve3D::_bake() const {
baked_up_vector_cache.resize(up_vector_enabled ? pointlist.size() : 0);
Vector3 *up_write = baked_up_vector_cache.ptrw();
+ baked_dist_cache.resize(pointlist.size());
+ float *wd = baked_dist_cache.ptrw();
+
Vector3 sideways;
Vector3 up;
Vector3 forward;
@@ -1242,6 +1279,7 @@ void Curve3D::_bake() const {
for (const Plane &E : pointlist) {
w[idx] = E.normal;
wt[idx] = E.d;
+ wd[idx] = distlist[idx];
if (!up_vector_enabled) {
idx++;
@@ -1308,19 +1346,26 @@ Vector3 Curve3D::interpolate_baked(float p_offset, bool p_cubic) const {
return r[bpc - 1];
}
- int idx = Math::floor((double)p_offset / (double)bake_interval);
- float frac = Math::fmod(p_offset, bake_interval);
-
- if (idx >= bpc - 1) {
- return r[bpc - 1];
- } else if (idx == bpc - 2) {
- if (frac > 0) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ int start = 0, end = bpc, idx = (end + start) / 2;
+ // binary search to find baked points
+ while (start < idx) {
+ float offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
}
- } else {
- frac /= bake_interval;
+ idx = (end + start) / 2;
}
+ float offset_begin = baked_dist_cache[idx];
+ float offset_end = baked_dist_cache[idx + 1];
+
+ float idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(), "failed to find baked segment");
+
+ float frac = (p_offset - offset_begin) / idx_interval;
+
if (p_cubic) {
Vector3 pre = idx > 0 ? r[idx - 1] : r[idx];
Vector3 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index c25d307608..5808fd6508 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -161,6 +161,7 @@ class Curve2D : public Resource {
mutable bool baked_cache_dirty = false;
mutable PackedVector2Array baked_point_cache;
+ mutable PackedFloat32Array baked_dist_cache;
mutable float baked_max_ofs = 0.0;
void _bake() const;
@@ -224,6 +225,7 @@ class Curve3D : public Resource {
mutable PackedVector3Array baked_point_cache;
mutable Vector<real_t> baked_tilt_cache;
mutable PackedVector3Array baked_up_vector_cache;
+ mutable PackedFloat32Array baked_dist_cache;
mutable float baked_max_ofs = 0.0;
void _bake() const;
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 4e139adabb..dd7b348498 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -212,26 +212,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_constant("outline_size", "LinkButton", 0);
theme->set_constant("underline_spacing", "LinkButton", 2 * scale);
- // ColorPickerButton
-
- theme->set_stylebox("normal", "ColorPickerButton", sb_button_normal);
- theme->set_stylebox("pressed", "ColorPickerButton", sb_button_pressed);
- theme->set_stylebox("hover", "ColorPickerButton", sb_button_hover);
- theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled);
- theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus);
-
- theme->set_font("font", "ColorPickerButton", Ref<Font>());
- theme->set_font_size("font_size", "ColorPickerButton", -1);
-
- theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1));
- theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1));
- theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1));
- theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3));
- theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1));
-
- theme->set_constant("hseparation", "ColorPickerButton", 2 * scale);
- theme->set_constant("outline_size", "ColorPickerButton", 0);
-
// OptionButton
Ref<StyleBox> sb_optbutton_focus = sb_expand(make_stylebox(button_focus_png, 4, 4, 4, 4, 6, 2, 6, 2), 2, 2, 2, 2);
@@ -859,7 +839,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("add_preset", "ColorPicker", make_icon(icon_add_png));
theme->set_icon("color_hue", "ColorPicker", make_icon(color_picker_hue_png));
theme->set_icon("color_sample", "ColorPicker", make_icon(color_picker_sample_png));
- theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png));
+ theme->set_icon("sample_bg", "ColorPicker", make_icon(mini_checkerboard_png));
theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png));
theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png));
theme->set_icon("picker_cursor", "ColorPicker", make_icon(picker_cursor_png));
@@ -867,6 +847,34 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// ColorPickerButton
theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png));
+ theme->set_stylebox("normal", "ColorPickerButton", sb_button_normal);
+ theme->set_stylebox("pressed", "ColorPickerButton", sb_button_pressed);
+ theme->set_stylebox("hover", "ColorPickerButton", sb_button_hover);
+ theme->set_stylebox("disabled", "ColorPickerButton", sb_button_disabled);
+ theme->set_stylebox("focus", "ColorPickerButton", sb_button_focus);
+
+ theme->set_font("font", "ColorPickerButton", Ref<Font>());
+ theme->set_font_size("font_size", "ColorPickerButton", -1);
+
+ theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1));
+ theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1));
+ theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1));
+ theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3));
+ theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1));
+
+ theme->set_constant("hseparation", "ColorPickerButton", 2 * scale);
+ theme->set_constant("outline_size", "ColorPickerButton", 0);
+
+ // ColorPresetButton
+
+ Ref<StyleBoxFlat> preset_sb = make_flat_stylebox(Color(1, 1, 1), 2, 2, 2, 2);
+ preset_sb->set_corner_radius_all(2);
+ preset_sb->set_corner_detail(2);
+ preset_sb->set_anti_aliased(false);
+
+ theme->set_stylebox("preset_fg", "ColorPresetButton", preset_sb);
+ theme->set_icon("preset_bg", "ColorPresetButton", make_icon(mini_checkerboard_png));
+ theme->set_icon("overbright_indicator", "ColorPresetButton", make_icon(overbright_indicator_png));
// TooltipPanel
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index 34f4142a14..0495a9e92c 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -45,31 +45,31 @@ void ParticlesMaterial::init_shaders() {
shader_names->direction = "direction";
shader_names->spread = "spread";
shader_names->flatness = "flatness";
- shader_names->initial_linear_velocity = "initial_linear_velocity";
- shader_names->initial_angle = "initial_angle";
- shader_names->angular_velocity = "angular_velocity";
- shader_names->orbit_velocity = "orbit_velocity";
- shader_names->linear_accel = "linear_accel";
- shader_names->radial_accel = "radial_accel";
- shader_names->tangent_accel = "tangent_accel";
- shader_names->damping = "damping";
- shader_names->scale = "scale";
- shader_names->hue_variation = "hue_variation";
- shader_names->anim_speed = "anim_speed";
- shader_names->anim_offset = "anim_offset";
-
- shader_names->initial_linear_velocity_random = "initial_linear_velocity_random";
- shader_names->initial_angle_random = "initial_angle_random";
- shader_names->angular_velocity_random = "angular_velocity_random";
- shader_names->orbit_velocity_random = "orbit_velocity_random";
- shader_names->linear_accel_random = "linear_accel_random";
- shader_names->radial_accel_random = "radial_accel_random";
- shader_names->tangent_accel_random = "tangent_accel_random";
- shader_names->damping_random = "damping_random";
- shader_names->scale_random = "scale_random";
- shader_names->hue_variation_random = "hue_variation_random";
- shader_names->anim_speed_random = "anim_speed_random";
- shader_names->anim_offset_random = "anim_offset_random";
+ shader_names->initial_linear_velocity_min = "initial_linear_velocity_min";
+ shader_names->initial_angle_min = "initial_angle_min";
+ shader_names->angular_velocity_min = "angular_velocity_min";
+ shader_names->orbit_velocity_min = "orbit_velocity_min";
+ shader_names->linear_accel_min = "linear_accel_min";
+ shader_names->radial_accel_min = "radial_accel_min";
+ shader_names->tangent_accel_min = "tangent_accel_min";
+ shader_names->damping_min = "damping_min";
+ shader_names->scale_min = "scale_min";
+ shader_names->hue_variation_min = "hue_variation_min";
+ shader_names->anim_speed_min = "anim_speed_min";
+ shader_names->anim_offset_min = "anim_offset_min";
+
+ shader_names->initial_linear_velocity_max = "initial_linear_velocity_max";
+ shader_names->initial_angle_max = "initial_angle_max";
+ shader_names->angular_velocity_max = "angular_velocity_max";
+ shader_names->orbit_velocity_max = "orbit_velocity_max";
+ shader_names->linear_accel_max = "linear_accel_max";
+ shader_names->radial_accel_max = "radial_accel_max";
+ shader_names->tangent_accel_max = "tangent_accel_max";
+ shader_names->damping_max = "damping_max";
+ shader_names->scale_max = "scale_max";
+ shader_names->hue_variation_max = "hue_variation_max";
+ shader_names->anim_speed_max = "anim_speed_max";
+ shader_names->anim_offset_max = "anim_offset_max";
shader_names->angle_texture = "angle_texture";
shader_names->angular_velocity_texture = "angular_velocity_texture";
@@ -155,31 +155,31 @@ void ParticlesMaterial::_update_shader() {
code += "uniform vec3 direction;\n";
code += "uniform float spread;\n";
code += "uniform float flatness;\n";
- code += "uniform float initial_linear_velocity;\n";
- code += "uniform float initial_angle;\n";
- code += "uniform float angular_velocity;\n";
- code += "uniform float orbit_velocity;\n";
- code += "uniform float linear_accel;\n";
- code += "uniform float radial_accel;\n";
- code += "uniform float tangent_accel;\n";
- code += "uniform float damping;\n";
- code += "uniform float scale;\n";
- code += "uniform float hue_variation;\n";
- code += "uniform float anim_speed;\n";
- code += "uniform float anim_offset;\n";
-
- code += "uniform float initial_linear_velocity_random;\n";
- code += "uniform float initial_angle_random;\n";
- code += "uniform float angular_velocity_random;\n";
- code += "uniform float orbit_velocity_random;\n";
- code += "uniform float linear_accel_random;\n";
- code += "uniform float radial_accel_random;\n";
- code += "uniform float tangent_accel_random;\n";
- code += "uniform float damping_random;\n";
- code += "uniform float scale_random;\n";
- code += "uniform float hue_variation_random;\n";
- code += "uniform float anim_speed_random;\n";
- code += "uniform float anim_offset_random;\n";
+ code += "uniform float initial_linear_velocity_min;\n";
+ code += "uniform float initial_angle_min;\n";
+ code += "uniform float angular_velocity_min;\n";
+ code += "uniform float orbit_velocity_min;\n";
+ code += "uniform float linear_accel_min;\n";
+ code += "uniform float radial_accel_min;\n";
+ code += "uniform float tangent_accel_min;\n";
+ code += "uniform float damping_min;\n";
+ code += "uniform float scale_min;\n";
+ code += "uniform float hue_variation_min;\n";
+ code += "uniform float anim_speed_min;\n";
+ code += "uniform float anim_offset_min;\n";
+
+ code += "uniform float initial_linear_velocity_max;\n";
+ code += "uniform float initial_angle_max;\n";
+ code += "uniform float angular_velocity_max;\n";
+ code += "uniform float orbit_velocity_max;\n";
+ code += "uniform float linear_accel_max;\n";
+ code += "uniform float radial_accel_max;\n";
+ code += "uniform float tangent_accel_max;\n";
+ code += "uniform float damping_max;\n";
+ code += "uniform float scale_max;\n";
+ code += "uniform float hue_variation_max;\n";
+ code += "uniform float anim_speed_max;\n";
+ code += "uniform float anim_offset_max;\n";
code += "uniform float lifetime_randomness;\n";
switch (emission_shape) {
@@ -329,7 +329,7 @@ void ParticlesMaterial::_update_shader() {
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 1.0;\n";
}
code += " float spread_rad = spread * degree_to_rad;\n";
@@ -339,7 +339,7 @@ void ParticlesMaterial::_update_shader() {
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(0.0, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 1.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
@@ -347,7 +347,7 @@ void ParticlesMaterial::_update_shader() {
code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed) * spread_rad;\n";
code += " angle1_rad += direction.x != 0.0 ? atan(direction.y, direction.x) : sign(direction.y) * (pi / 2.0);\n";
code += " vec3 rot = vec3(cos(angle1_rad), sin(angle1_rad), 0.0);\n";
- code += " VELOCITY = rot * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " VELOCITY = rot * mix(initial_linear_velocity_min,initial_linear_velocity_max, rand_from_seed(alt_seed));\n";
code += " }\n";
} else {
@@ -369,16 +369,16 @@ void ParticlesMaterial::_update_shader() {
code += " binormal = normalize(binormal);\n";
code += " vec3 normal = cross(binormal, direction_nrm);\n";
code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n";
- code += " VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " VELOCITY = spread_direction * mix(initial_linear_velocity_min, initial_linear_velocity_max,rand_from_seed(alt_seed));\n";
code += " }\n";
}
code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
+ code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, angle_rand);\n";
code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
code += " CUSTOM.y = 0.0;\n"; // phase
code += " CUSTOM.w = (1.0 - lifetime_randomness * rand_from_seed(alt_seed));\n";
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random);\n"; // animation offset (0-1)
+ code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, anim_offset_rand);\n"; // animation offset (0-1)
code += " if (RESTART_POSITION) {\n";
@@ -471,63 +471,63 @@ void ParticlesMaterial::_update_shader() {
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_velocity = 0.0;\n";
+ code += " float tex_linear_velocity = 1.0;\n";
}
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) {
code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_orbit_velocity = 0.0;\n";
+ code += " float tex_orbit_velocity = 1.0;\n";
}
}
if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) {
code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angular_velocity = 0.0;\n";
+ code += " float tex_angular_velocity = 1.0;\n";
}
if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) {
code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_linear_accel = 0.0;\n";
+ code += " float tex_linear_accel = 1.0;\n";
}
if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) {
code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_radial_accel = 0.0;\n";
+ code += " float tex_radial_accel = 1.0;\n";
}
if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) {
code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_tangent_accel = 0.0;\n";
+ code += " float tex_tangent_accel = 1.0;\n";
}
if (tex_parameters[PARAM_DAMPING].is_valid()) {
code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_damping = 0.0;\n";
+ code += " float tex_damping = 1.0;\n";
}
if (tex_parameters[PARAM_ANGLE].is_valid()) {
code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_angle = 0.0;\n";
+ code += " float tex_angle = 1.0;\n";
}
if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) {
code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_speed = 0.0;\n";
+ code += " float tex_anim_speed = 1.0;\n";
}
if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) {
code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_anim_offset = 0.0;\n";
+ code += " float tex_anim_offset = 1.0;\n";
}
code += " vec3 force = gravity;\n";
@@ -536,18 +536,19 @@ void ParticlesMaterial::_update_shader() {
code += " pos.z = 0.0;\n";
}
code += " // apply linear acceleration\n";
- code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * (linear_accel + tex_linear_accel) * mix(1.0, rand_from_seed(alt_seed), linear_accel_random) : vec3(0.0);\n";
+ code += " force += length(VELOCITY) > 0.0 ? normalize(VELOCITY) * tex_linear_accel * mix(linear_accel_min, linear_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n";
code += " // apply radial acceleration\n";
code += " vec3 org = EMISSION_TRANSFORM[3].xyz;\n";
code += " vec3 diff = pos - org;\n";
- code += " force += length(diff) > 0.0 ? normalize(diff) * (radial_accel + tex_radial_accel) * mix(1.0, rand_from_seed(alt_seed), radial_accel_random) : vec3(0.0);\n";
+ code += " force += length(diff) > 0.0 ? normalize(diff) * tex_radial_accel * mix(radial_accel_min, radial_accel_max, rand_from_seed(alt_seed)) : vec3(0.0);\n";
code += " // apply tangential acceleration;\n";
+ code += " float tangent_accel_val = tex_tangent_accel * mix(tangent_accel_min, tangent_accel_max, rand_from_seed(alt_seed))\n;";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " force += length(diff.yx) > 0.0 ? vec3(normalize(diff.yx * vec2(-1.0, 1.0)), 0.0) * tangent_accel_val : vec3(0.0);\n";
} else {
code += " vec3 crossDiff = cross(normalize(diff), normalize(gravity));\n";
- code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * ((tangent_accel + tex_tangent_accel) * mix(1.0, rand_from_seed(alt_seed), tangent_accel_random)) : vec3(0.0);\n";
+ code += " force += length(crossDiff) > 0.0 ? normalize(crossDiff) * tangent_accel_val : vec3(0.0);\n";
}
if (attractor_interaction_enabled) {
code += " force += ATTRACTOR_FORCE;\n\n";
@@ -557,7 +558,7 @@ void ParticlesMaterial::_update_shader() {
code += " VELOCITY += force * DELTA;\n";
code += " // orbit velocity\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
- code += " float orbit_amount = (orbit_velocity + tex_orbit_velocity) * mix(1.0, rand_from_seed(alt_seed), orbit_velocity_random);\n";
+ code += " float orbit_amount = tex_orbit_velocity * mix(orbit_velocity_min, orbit_velocity_max, rand_from_seed(alt_seed));\n";
code += " if (orbit_amount != 0.0) {\n";
code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
code += " mat2 rot = mat2(vec2(cos(ang), -sin(ang)), vec2(sin(ang), cos(ang)));\n";
@@ -569,9 +570,10 @@ void ParticlesMaterial::_update_shader() {
if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) {
code += " VELOCITY = normalize(VELOCITY) * tex_linear_velocity;\n";
}
- code += " if (damping + tex_damping > 0.0) {\n";
+ code += " float dmp = mix(damping_min, damping_max, rand_from_seed(alt_seed));\n";
+ code += " if (dmp * tex_damping > 0.0) {\n";
code += " float v = length(VELOCITY);\n";
- code += " float damp = (damping + tex_damping) * mix(1.0, rand_from_seed(alt_seed), damping_random);\n";
+ code += " float damp = tex_damping * dmp;\n";
code += " v -= damp * DELTA;\n";
code += " if (v < 0.0) {\n";
code += " VELOCITY = vec3(0.0);\n";
@@ -579,26 +581,26 @@ void ParticlesMaterial::_update_shader() {
code += " VELOCITY = normalize(VELOCITY) * v;\n";
code += " }\n";
code += " }\n";
- code += " float base_angle = (initial_angle + tex_angle) * mix(1.0, angle_rand, initial_angle_random);\n";
- code += " base_angle += CUSTOM.y * LIFETIME * (angular_velocity + tex_angular_velocity) * mix(1.0, rand_from_seed(alt_seed) * 2.0 - 1.0, angular_velocity_random);\n";
+ code += " float base_angle = (tex_angle) * mix(initial_angle_min, initial_angle_max, rand_from_seed(alt_seed));\n";
+ code += " base_angle += CUSTOM.y * LIFETIME * (tex_angular_velocity) * mix(angular_velocity_min,angular_velocity_max, rand_from_seed(alt_seed));\n";
code += " CUSTOM.x = base_angle * degree_to_rad;\n"; // angle
- code += " CUSTOM.z = (anim_offset + tex_anim_offset) * mix(1.0, anim_offset_rand, anim_offset_random) + CUSTOM.y * (anim_speed + tex_anim_speed) * mix(1.0, rand_from_seed(alt_seed), anim_speed_random);\n"; // angle
+ code += " CUSTOM.z = (tex_anim_offset) * mix(anim_offset_min, anim_offset_max, rand_from_seed(alt_seed)) + CUSTOM.y * tex_anim_speed * mix(anim_speed_min, anim_speed_max, rand_from_seed(alt_seed));\n"; // angle
// apply color
// apply hue rotation
if (tex_parameters[PARAM_SCALE].is_valid()) {
- code += " float tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).r;\n";
+ code += " vec3 tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).rgb;\n";
} else {
- code += " float tex_scale = 1.0;\n";
+ code += " vec3 tex_scale = vec3(1.0);\n";
}
if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) {
code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(tv, 0.0), 0.0).r;\n";
} else {
- code += " float tex_hue_variation = 0.0;\n";
+ code += " float tex_hue_variation = 1.0;\n";
}
- code += " float hue_rot_angle = (hue_variation + tex_hue_variation) * pi * 2.0 * mix(1.0, hue_rot_rand * 2.0 - 1.0, hue_variation_random);\n";
+ code += " float hue_rot_angle = (tex_hue_variation) * pi * 2.0 * mix(hue_variation_min, hue_variation_max, rand_from_seed(alt_seed));\n";
code += " float hue_rot_c = cos(hue_rot_angle);\n";
code += " float hue_rot_s = sin(hue_rot_angle);\n";
code += " mat4 hue_rot_mat = mat4(vec4(0.299, 0.587, 0.114, 0.0),\n";
@@ -660,18 +662,18 @@ void ParticlesMaterial::_update_shader() {
}
// turn particle by rotation in Y
if (particle_flags[PARTICLE_FLAG_ROTATE_Y]) {
+ code += " vec4 origin = TRANSFORM[3];\n";
code += " TRANSFORM = mat4(vec4(cos(CUSTOM.x), 0.0, -sin(CUSTOM.x), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(sin(CUSTOM.x), 0.0, cos(CUSTOM.x), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
+ code += " TRANSFORM[3] = origin;\n";
}
}
//scale by scale
- code += " float base_scale = tex_scale * mix(scale, 1.0, scale_random * scale_rand);\n";
- code += " if (base_scale < 0.000001) {\n";
- code += " base_scale = 0.000001;\n";
- code += " }\n";
+ code += " float base_scale = mix(scale_min, scale_max, scale_rand);\n";
+ code += " base_scale = sign(base_scale) * max(abs(base_scale), 0.001);\n";
- code += " TRANSFORM[0].xyz *= base_scale;\n";
- code += " TRANSFORM[1].xyz *= base_scale;\n";
- code += " TRANSFORM[2].xyz *= base_scale;\n";
+ code += " TRANSFORM[0].xyz *= base_scale * sign(tex_scale.r) * max(abs(tex_scale.r), 0.001);\n";
+ code += " TRANSFORM[1].xyz *= base_scale * sign(tex_scale.g) * max(abs(tex_scale.g), 0.001);\n";
+ code += " TRANSFORM[2].xyz *= base_scale * sign(tex_scale.b) * max(abs(tex_scale.b), 0.001);\n";
if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) {
code += " VELOCITY.z = 0.0;\n";
code += " TRANSFORM[3].z = 0.0;\n";
@@ -777,110 +779,116 @@ float ParticlesMaterial::get_flatness() const {
return flatness;
}
-void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
+void ParticlesMaterial::set_param_min(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- parameters[p_param] = p_value;
+ params_min[p_param] = p_value;
+ if (params_min[p_param] > params_max[p_param]) {
+ set_param_max(p_param, p_value);
+ }
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_min, p_value);
} break;
case PARAM_ANGULAR_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_min, p_value);
} break;
case PARAM_ORBIT_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_min, p_value);
} break;
case PARAM_LINEAR_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_min, p_value);
} break;
case PARAM_RADIAL_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_min, p_value);
} break;
case PARAM_TANGENTIAL_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_min, p_value);
} break;
case PARAM_DAMPING: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_min, p_value);
} break;
case PARAM_ANGLE: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_min, p_value);
} break;
case PARAM_SCALE: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_min, p_value);
} break;
case PARAM_HUE_VARIATION: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_min, p_value);
} break;
case PARAM_ANIM_SPEED: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_min, p_value);
} break;
case PARAM_ANIM_OFFSET: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_min, p_value);
} break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param(Parameter p_param) const {
+float ParticlesMaterial::get_param_min(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return parameters[p_param];
+ return params_min[p_param];
}
-void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
+void ParticlesMaterial::set_param_max(Parameter p_param, float p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
- randomness[p_param] = p_value;
+ params_max[p_param] = p_value;
+ if (params_min[p_param] > params_max[p_param]) {
+ set_param_min(p_param, p_value);
+ }
switch (p_param) {
case PARAM_INITIAL_LINEAR_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_linear_velocity_max, p_value);
} break;
case PARAM_ANGULAR_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_max, p_value);
} break;
case PARAM_ORBIT_VELOCITY: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_max, p_value);
} break;
case PARAM_LINEAR_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_max, p_value);
} break;
case PARAM_RADIAL_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_max, p_value);
} break;
case PARAM_TANGENTIAL_ACCEL: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_max, p_value);
} break;
case PARAM_DAMPING: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_max, p_value);
} break;
case PARAM_ANGLE: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->initial_angle_max, p_value);
} break;
case PARAM_SCALE: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_max, p_value);
} break;
case PARAM_HUE_VARIATION: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_max, p_value);
} break;
case PARAM_ANIM_SPEED: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_max, p_value);
} break;
case PARAM_ANIM_OFFSET: {
- RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
+ RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_max, p_value);
} break;
case PARAM_MAX:
break; // Can't happen, but silences warning
}
}
-float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
+float ParticlesMaterial::get_param_max(Parameter p_param) const {
ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0);
- return randomness[p_param];
+ return params_max[p_param];
}
static void _adjust_curve_range(const Ref<Texture2D> &p_texture, float p_min, float p_max) {
@@ -1259,11 +1267,11 @@ void ParticlesMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_flatness", "amount"), &ParticlesMaterial::set_flatness);
ClassDB::bind_method(D_METHOD("get_flatness"), &ParticlesMaterial::get_flatness);
- ClassDB::bind_method(D_METHOD("set_param", "param", "value"), &ParticlesMaterial::set_param);
- ClassDB::bind_method(D_METHOD("get_param", "param"), &ParticlesMaterial::get_param);
+ ClassDB::bind_method(D_METHOD("set_param_min", "param", "value"), &ParticlesMaterial::set_param_min);
+ ClassDB::bind_method(D_METHOD("get_param_min", "param"), &ParticlesMaterial::get_param_min);
- ClassDB::bind_method(D_METHOD("set_param_randomness", "param", "randomness"), &ParticlesMaterial::set_param_randomness);
- ClassDB::bind_method(D_METHOD("get_param_randomness", "param"), &ParticlesMaterial::get_param_randomness);
+ ClassDB::bind_method(D_METHOD("set_param_max", "param", "value"), &ParticlesMaterial::set_param_max);
+ ClassDB::bind_method(D_METHOD("get_param_max", "param"), &ParticlesMaterial::get_param_max);
ClassDB::bind_method(D_METHOD("set_param_texture", "param", "texture"), &ParticlesMaterial::set_param_texture);
ClassDB::bind_method(D_METHOD("get_param_texture", "param"), &ParticlesMaterial::get_param_texture);
@@ -1369,54 +1377,54 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "initial_velocity_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_min", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANGULAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angular_velocity_max", PROPERTY_HINT_RANGE, "-720,720,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_min", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "orbit_velocity_max", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "linear_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "radial_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_min", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "tangential_accel_max", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param", "get_param", PARAM_DAMPING);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_min", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_max", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_min", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_min", "get_param_min", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_max", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param_max", "get_param_max", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
- ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_min", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_min", "get_param_min", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "scale_max", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param_max", "get_param_max", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture,CurveXYZTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
ADD_GROUP("Color", "");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "GradientTexture"), "set_color_ramp", "get_color_ramp");
ADD_GROUP("Hue Variation", "hue_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param", "get_param", PARAM_HUE_VARIATION);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_min", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_min", "get_param_min", PARAM_HUE_VARIATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "hue_variation_max", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_param_max", "get_param_max", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_speed_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
- ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_min", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_min", "get_param_min", PARAM_ANIM_OFFSET);
+ ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anim_offset_max", PROPERTY_HINT_RANGE, "0,16,0.01,or_lesser,or_greater"), "set_param_max", "get_param_max", PARAM_ANIM_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_offset_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_OFFSET);
ADD_GROUP("Sub Emitter", "sub_emitter_");
@@ -1472,18 +1480,30 @@ ParticlesMaterial::ParticlesMaterial() :
set_direction(Vector3(1, 0, 0));
set_spread(45);
set_flatness(0);
- set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0);
- set_param(PARAM_ANGULAR_VELOCITY, 0);
- set_param(PARAM_ORBIT_VELOCITY, 0);
- set_param(PARAM_LINEAR_ACCEL, 0);
- set_param(PARAM_RADIAL_ACCEL, 0);
- set_param(PARAM_TANGENTIAL_ACCEL, 0);
- set_param(PARAM_DAMPING, 0);
- set_param(PARAM_ANGLE, 0);
- set_param(PARAM_SCALE, 1);
- set_param(PARAM_HUE_VARIATION, 0);
- set_param(PARAM_ANIM_SPEED, 0);
- set_param(PARAM_ANIM_OFFSET, 0);
+ set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_min(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_min(PARAM_ORBIT_VELOCITY, 0);
+ set_param_min(PARAM_LINEAR_ACCEL, 0);
+ set_param_min(PARAM_RADIAL_ACCEL, 0);
+ set_param_min(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_min(PARAM_DAMPING, 0);
+ set_param_min(PARAM_ANGLE, 0);
+ set_param_min(PARAM_SCALE, 1);
+ set_param_min(PARAM_HUE_VARIATION, 0);
+ set_param_min(PARAM_ANIM_SPEED, 0);
+ set_param_min(PARAM_ANIM_OFFSET, 0);
+ set_param_max(PARAM_INITIAL_LINEAR_VELOCITY, 0);
+ set_param_max(PARAM_ANGULAR_VELOCITY, 0);
+ set_param_max(PARAM_ORBIT_VELOCITY, 0);
+ set_param_max(PARAM_LINEAR_ACCEL, 0);
+ set_param_max(PARAM_RADIAL_ACCEL, 0);
+ set_param_max(PARAM_TANGENTIAL_ACCEL, 0);
+ set_param_max(PARAM_DAMPING, 0);
+ set_param_max(PARAM_ANGLE, 0);
+ set_param_max(PARAM_SCALE, 1);
+ set_param_max(PARAM_HUE_VARIATION, 0);
+ set_param_max(PARAM_ANIM_SPEED, 0);
+ set_param_max(PARAM_ANIM_OFFSET, 0);
set_emission_shape(EMISSION_SHAPE_POINT);
set_emission_sphere_radius(1);
set_emission_box_extents(Vector3(1, 1, 1));
@@ -1505,10 +1525,6 @@ ParticlesMaterial::ParticlesMaterial() :
set_collision_friction(0.0);
set_collision_use_scale(false);
- for (int i = 0; i < PARAM_MAX; i++) {
- set_param_randomness(Parameter(i), 0);
- }
-
for (int i = 0; i < PARTICLE_FLAG_MAX; i++) {
particle_flags[i] = false;
}
diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h
index 1e1821024e..8ab26aff77 100644
--- a/scene/resources/particles_material.h
+++ b/scene/resources/particles_material.h
@@ -154,31 +154,31 @@ private:
StringName direction;
StringName spread;
StringName flatness;
- StringName initial_linear_velocity;
- StringName initial_angle;
- StringName angular_velocity;
- StringName orbit_velocity;
- StringName linear_accel;
- StringName radial_accel;
- StringName tangent_accel;
- StringName damping;
- StringName scale;
- StringName hue_variation;
- StringName anim_speed;
- StringName anim_offset;
-
- StringName initial_linear_velocity_random;
- StringName initial_angle_random;
- StringName angular_velocity_random;
- StringName orbit_velocity_random;
- StringName linear_accel_random;
- StringName radial_accel_random;
- StringName tangent_accel_random;
- StringName damping_random;
- StringName scale_random;
- StringName hue_variation_random;
- StringName anim_speed_random;
- StringName anim_offset_random;
+ StringName initial_linear_velocity_min;
+ StringName initial_angle_min;
+ StringName angular_velocity_min;
+ StringName orbit_velocity_min;
+ StringName linear_accel_min;
+ StringName radial_accel_min;
+ StringName tangent_accel_min;
+ StringName damping_min;
+ StringName scale_min;
+ StringName hue_variation_min;
+ StringName anim_speed_min;
+ StringName anim_offset_min;
+
+ StringName initial_linear_velocity_max;
+ StringName initial_angle_max;
+ StringName angular_velocity_max;
+ StringName orbit_velocity_max;
+ StringName linear_accel_max;
+ StringName radial_accel_max;
+ StringName tangent_accel_max;
+ StringName damping_max;
+ StringName scale_max;
+ StringName hue_variation_max;
+ StringName anim_speed_max;
+ StringName anim_offset_max;
StringName angle_texture;
StringName angular_velocity_texture;
@@ -230,8 +230,8 @@ private:
float spread;
float flatness;
- float parameters[PARAM_MAX];
- float randomness[PARAM_MAX];
+ float params_min[PARAM_MAX];
+ float params_max[PARAM_MAX];
Ref<Texture2D> tex_parameters[PARAM_MAX];
Color color;
@@ -283,11 +283,11 @@ public:
void set_flatness(float p_flatness);
float get_flatness() const;
- void set_param(Parameter p_param, float p_value);
- float get_param(Parameter p_param) const;
+ void set_param_min(Parameter p_param, float p_value);
+ float get_param_min(Parameter p_param) const;
- void set_param_randomness(Parameter p_param, float p_value);
- float get_param_randomness(Parameter p_param) const;
+ void set_param_max(Parameter p_param, float p_value);
+ float get_param_max(Parameter p_param) const;
void set_param_texture(Parameter p_param, const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_param_texture(Parameter p_param) const;
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index ba85ea4a6c..e7da41db9d 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1420,6 +1420,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const {
int i, j, prevrow, thisrow, point;
float x, y, z;
+ float scale = height * (is_hemisphere ? 1.0 : 0.5);
+
// set our bounding box
Vector<Vector3> points;
@@ -1443,7 +1445,7 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const {
v /= (rings + 1);
w = sin(Math_PI * v);
- y = height * (is_hemisphere ? 1.0 : 0.5) * cos(Math_PI * v);
+ y = scale * cos(Math_PI * v);
for (i = 0; i <= radial_segments; i++) {
float u = i;
@@ -1458,7 +1460,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const {
} else {
Vector3 p = Vector3(x * radius * w, y, z * radius * w);
points.push_back(p);
- normals.push_back(p.normalized());
+ Vector3 normal = Vector3(x * radius * w * scale, y / scale, z * radius * w * scale);
+ normals.push_back(normal.normalized());
};
ADD_TANGENT(z, 0.0, -x, 1.0)
uvs.push_back(Vector2(u, v));
diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp
index 2d5b42ddf4..e533fb054a 100644
--- a/scene/resources/skeleton_modification_2d.cpp
+++ b/scene/resources/skeleton_modification_2d.cpp
@@ -44,7 +44,7 @@
///////////////////////////////////////
void SkeletonModification2D::_execute(float p_delta) {
- call("_execute", p_delta);
+ GDVIRTUAL_CALL(_execute, p_delta);
if (!enabled) {
return;
@@ -59,11 +59,11 @@ void SkeletonModification2D::_setup_modification(SkeletonModificationStack2D *p_
WARN_PRINT("Could not setup modification with name " + get_name());
}
- call("_setup_modification", p_stack);
+ GDVIRTUAL_CALL(_setup_modification, Ref<SkeletonModificationStack2D>(p_stack));
}
void SkeletonModification2D::_draw_editor_gizmo() {
- call("_draw_editor_gizmo");
+ GDVIRTUAL_CALL(_draw_editor_gizmo);
}
void SkeletonModification2D::set_enabled(bool p_enabled) {
@@ -228,9 +228,9 @@ bool SkeletonModification2D::get_editor_draw_gizmo() const {
}
void SkeletonModification2D::_bind_methods() {
- BIND_VMETHOD(MethodInfo("_execute", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_setup_modification", PropertyInfo(Variant::OBJECT, "modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D")));
- BIND_VMETHOD(MethodInfo("_draw_editor_gizmo"));
+ GDVIRTUAL_BIND(_execute, "delta");
+ GDVIRTUAL_BIND(_setup_modification, "modification_stack")
+ GDVIRTUAL_BIND(_draw_editor_gizmo)
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification2D::set_enabled);
ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification2D::get_enabled);
diff --git a/scene/resources/skeleton_modification_2d.h b/scene/resources/skeleton_modification_2d.h
index 18633e55cb..aaddb9136e 100644
--- a/scene/resources/skeleton_modification_2d.h
+++ b/scene/resources/skeleton_modification_2d.h
@@ -57,6 +57,10 @@ protected:
bool _print_execution_error(bool p_condition, String p_message);
+ GDVIRTUAL1(_execute, double)
+ GDVIRTUAL1(_setup_modification, Ref<SkeletonModificationStack2D>)
+ GDVIRTUAL0(_draw_editor_gizmo)
+
public:
virtual void _execute(float _delta);
virtual void _setup_modification(SkeletonModificationStack2D *p_stack);
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
index 9306ee14cd..ee02ede2d5 100644
--- a/scene/resources/skeleton_modification_3d.cpp
+++ b/scene/resources/skeleton_modification_3d.cpp
@@ -32,11 +32,7 @@
#include "scene/3d/skeleton_3d.h"
void SkeletonModification3D::_execute(real_t p_delta) {
- if (get_script_instance()) {
- if (get_script_instance()->has_method("execute")) {
- get_script_instance()->call("execute", p_delta);
- }
- }
+ GDVIRTUAL_CALL(_execute, p_delta);
if (!enabled)
return;
@@ -50,11 +46,7 @@ void SkeletonModification3D::_setup_modification(SkeletonModificationStack3D *p_
WARN_PRINT("Could not setup modification with name " + this->get_name());
}
- if (get_script_instance()) {
- if (get_script_instance()->has_method("setup_modification")) {
- get_script_instance()->call("setup_modification", p_stack);
- }
- }
+ GDVIRTUAL_CALL(_setup_modification, Ref<SkeletonModificationStack3D>(p_stack));
}
void SkeletonModification3D::set_enabled(bool p_enabled) {
@@ -148,8 +140,8 @@ int SkeletonModification3D::get_execution_mode() const {
}
void SkeletonModification3D::_bind_methods() {
- BIND_VMETHOD(MethodInfo("_execute", PropertyInfo(Variant::FLOAT, "delta")));
- BIND_VMETHOD(MethodInfo("_setup_modification", PropertyInfo(Variant::OBJECT, "modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack3D")));
+ GDVIRTUAL_BIND(_execute, "delta");
+ GDVIRTUAL_BIND(_setup_modification, "modification_stack")
ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification3D::set_enabled);
ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification3D::get_enabled);
diff --git a/scene/resources/skeleton_modification_3d.h b/scene/resources/skeleton_modification_3d.h
index 94ab0bf32c..fb1f3d33d1 100644
--- a/scene/resources/skeleton_modification_3d.h
+++ b/scene/resources/skeleton_modification_3d.h
@@ -53,6 +53,9 @@ protected:
bool _print_execution_error(bool p_condition, String p_message);
+ GDVIRTUAL1(_execute, double)
+ GDVIRTUAL1(_setup_modification, Ref<SkeletonModificationStack3D>)
+
public:
virtual void _execute(real_t p_delta);
virtual void _setup_modification(SkeletonModificationStack3D *p_stack);
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index 173ce2adce..52a3abf74d 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -43,12 +43,10 @@ Dictionary SyntaxHighlighter::get_line_syntax_highlighting(int p_line) {
return color_map;
}
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_get_line_syntax_highlighting")) {
- color_map = si->call("_get_line_syntax_highlighting", p_line);
- } else {
- color_map = _get_line_syntax_highlighting(p_line);
+ if (!GDVIRTUAL_CALL(_get_line_syntax_highlighting, p_line, color_map)) {
+ color_map = _get_line_syntax_highlighting_impl(p_line);
}
+
highlighting_cache[p_line] = color_map;
return color_map;
}
@@ -69,9 +67,7 @@ void SyntaxHighlighter::_lines_edited_from(int p_from_line, int p_to_line) {
void SyntaxHighlighter::clear_highlighting_cache() {
highlighting_cache.clear();
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_clear_highlighting_cache")) {
- si->call("_clear_highlighting_cache");
+ if (GDVIRTUAL_CALL(_clear_highlighting_cache)) {
return;
}
_clear_highlighting_cache();
@@ -83,9 +79,7 @@ void SyntaxHighlighter::update_cache() {
if (text_edit == nullptr) {
return;
}
- ScriptInstance *si = get_script_instance();
- if (si && si->has_method("_update_cache")) {
- si->call("_update_cache");
+ if (GDVIRTUAL_CALL(_update_cache)) {
return;
}
_update_cache();
@@ -115,9 +109,9 @@ void SyntaxHighlighter::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_highlighting_cache"), &SyntaxHighlighter::clear_highlighting_cache);
ClassDB::bind_method(D_METHOD("get_text_edit"), &SyntaxHighlighter::get_text_edit);
- BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_line_syntax_highlighting", PropertyInfo(Variant::INT, "line")));
- BIND_VMETHOD(MethodInfo("_clear_highlighting_cache"));
- BIND_VMETHOD(MethodInfo("_update_cache"));
+ GDVIRTUAL_BIND(_get_line_syntax_highlighting, "line")
+ GDVIRTUAL_BIND(_clear_highlighting_cache)
+ GDVIRTUAL_BIND(_update_cache)
}
////////////////////////////////////////////////////////////////////////////////
@@ -130,7 +124,7 @@ static bool _is_hex_symbol(char32_t c) {
return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
-Dictionary CodeHighlighter::_get_line_syntax_highlighting(int p_line) {
+Dictionary CodeHighlighter::_get_line_syntax_highlighting_impl(int p_line) {
Dictionary color_map;
bool prev_is_char = false;
diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h
index f3964b0c8f..0fe39ccff6 100644
--- a/scene/resources/syntax_highlighter.h
+++ b/scene/resources/syntax_highlighter.h
@@ -32,6 +32,8 @@
#define SYNTAX_HIGHLIGHTER_H
#include "core/io/resource.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
class TextEdit;
@@ -48,9 +50,12 @@ protected:
static void _bind_methods();
+ GDVIRTUAL1RC(Dictionary, _get_line_syntax_highlighting, int)
+ GDVIRTUAL0(_clear_highlighting_cache)
+ GDVIRTUAL0(_update_cache)
public:
Dictionary get_line_syntax_highlighting(int p_line);
- virtual Dictionary _get_line_syntax_highlighting(int p_line) { return Dictionary(); }
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) { return Dictionary(); }
void clear_highlighting_cache();
virtual void _clear_highlighting_cache() {}
@@ -93,7 +98,7 @@ protected:
static void _bind_methods();
public:
- virtual Dictionary _get_line_syntax_highlighting(int p_line) override;
+ virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override;
virtual void _clear_highlighting_cache() override;
virtual void _update_cache() override;
diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp
index 357411ae04..763033354a 100644
--- a/scene/resources/text_paragraph.cpp
+++ b/scene/resources/text_paragraph.cpp
@@ -437,7 +437,8 @@ Size2 TextParagraph::get_non_wraped_size() const {
Size2 TextParagraph::get_size() const {
const_cast<TextParagraph *>(this)->_shape_lines();
Size2 size;
- for (int i = 0; i < lines_rid.size(); i++) {
+ int visible_lines = (max_lines_visible >= 0) ? MIN(max_lines_visible, lines_rid.size()) : lines_rid.size();
+ for (int i = 0; i < visible_lines; i++) {
Size2 lsize = TS->shaped_text_get_size(lines_rid[i]);
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
size.x = MAX(size.x, lsize.x);
@@ -587,15 +588,15 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
l_width -= h_offset;
}
}
- float length = TS->shaped_text_get_width(lines_rid[i]);
+ float line_width = TS->shaped_text_get_width(lines_rid[i]);
if (width > 0) {
switch (align) {
case HALIGN_FILL:
if (TS->shaped_text_get_direction(lines_rid[i]) == TextServer::DIRECTION_RTL) {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += l_width - length;
+ ofs.x += l_width - line_width;
} else {
- ofs.y += l_width - length;
+ ofs.y += l_width - line_width;
}
}
break;
@@ -603,16 +604,16 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo
break;
case HALIGN_CENTER: {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += Math::floor((l_width - length) / 2.0);
+ ofs.x += Math::floor((l_width - line_width) / 2.0);
} else {
- ofs.y += Math::floor((l_width - length) / 2.0);
+ ofs.y += Math::floor((l_width - line_width) / 2.0);
}
} break;
case HALIGN_RIGHT: {
if (TS->shaped_text_get_orientation(lines_rid[i]) == TextServer::ORIENTATION_HORIZONTAL) {
- ofs.x += l_width - length;
+ ofs.x += l_width - line_width;
} else {
- ofs.y += l_width - length;
+ ofs.y += l_width - line_width;
}
} break;
}
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 4ad5f2a506..063a13efc0 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -1758,11 +1758,16 @@ void GradientTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_gradient"), &GradientTexture::get_gradient);
ClassDB::bind_method(D_METHOD("set_width", "width"), &GradientTexture::set_width);
+ // The `get_width()` method is already exposed by the parent class Texture2D.
+
+ ClassDB::bind_method(D_METHOD("set_use_hdr", "enabled"), &GradientTexture::set_use_hdr);
+ ClassDB::bind_method(D_METHOD("is_using_hdr"), &GradientTexture::is_using_hdr);
ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient");
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hdr"), "set_use_hdr", "is_using_hdr");
}
void GradientTexture::set_gradient(Ref<Gradient> p_gradient) {
@@ -1800,30 +1805,49 @@ void GradientTexture::_update() {
return;
}
- Vector<uint8_t> data;
- data.resize(width * 4);
- {
- uint8_t *wd8 = data.ptrw();
+ if (use_hdr) {
+ // High dynamic range.
+ Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBAF));
Gradient &g = **gradient;
-
+ // `create()` isn't available for non-uint8_t data, so fill in the data manually.
for (int i = 0; i < width; i++) {
float ofs = float(i) / (width - 1);
- Color color = g.get_color_at_offset(ofs);
+ image->set_pixel(i, 0, g.get_color_at_offset(ofs));
+ }
- wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
- wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
- wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
- wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
+ } else {
+ // Low dynamic range. "Overbright" colors will be clamped.
+ Vector<uint8_t> data;
+ data.resize(width * 4);
+ {
+ uint8_t *wd8 = data.ptrw();
+ Gradient &g = **gradient;
+
+ for (int i = 0; i < width; i++) {
+ float ofs = float(i) / (width - 1);
+ Color color = g.get_color_at_offset(ofs);
+
+ wd8[i * 4 + 0] = uint8_t(CLAMP(color.r * 255.0, 0, 255));
+ wd8[i * 4 + 1] = uint8_t(CLAMP(color.g * 255.0, 0, 255));
+ wd8[i * 4 + 2] = uint8_t(CLAMP(color.b * 255.0, 0, 255));
+ wd8[i * 4 + 3] = uint8_t(CLAMP(color.a * 255.0, 0, 255));
+ }
}
- }
- Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
+ Ref<Image> image = memnew(Image(width, 1, false, Image::FORMAT_RGBA8, data));
- if (texture.is_valid()) {
- RID new_texture = RS::get_singleton()->texture_2d_create(image);
- RS::get_singleton()->texture_replace(texture, new_texture);
- } else {
- texture = RS::get_singleton()->texture_2d_create(image);
+ if (texture.is_valid()) {
+ RID new_texture = RS::get_singleton()->texture_2d_create(image);
+ RS::get_singleton()->texture_replace(texture, new_texture);
+ } else {
+ texture = RS::get_singleton()->texture_2d_create(image);
+ }
}
emit_changed();
@@ -1839,6 +1863,19 @@ int GradientTexture::get_width() const {
return width;
}
+void GradientTexture::set_use_hdr(bool p_enabled) {
+ if (p_enabled == use_hdr) {
+ return;
+ }
+
+ use_hdr = p_enabled;
+ _queue_update();
+}
+
+bool GradientTexture::is_using_hdr() const {
+ return use_hdr;
+}
+
Ref<Image> GradientTexture::get_image() const {
if (!texture.is_valid()) {
return Ref<Image>();
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 2e97c2deb1..f6b991c335 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -686,6 +686,7 @@ private:
bool update_pending = false;
RID texture;
int width = 2048;
+ bool use_hdr = false;
void _queue_update();
void _update();
@@ -700,6 +701,9 @@ public:
void set_width(int p_width);
int get_width() const override;
+ void set_use_hdr(bool p_enabled);
+ bool is_using_hdr() const;
+
virtual RID get_rid() const override { return texture; }
virtual int get_height() const override { return 1; }
virtual bool has_alpha() const override { return true; }
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index b00dcca004..a7f99a2113 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -261,54 +261,47 @@ VisualShaderNode::VisualShaderNode() {
/////////////////////////////////////////////////////////
void VisualShaderNodeCustom::update_ports() {
- ERR_FAIL_COND(!get_script_instance());
+ {
+ input_ports.clear();
+ int input_port_count;
+ if (GDVIRTUAL_CALL(_get_input_port_count, input_port_count)) {
+ for (int i = 0; i < input_port_count; i++) {
+ Port port;
+ if (!GDVIRTUAL_CALL(_get_input_port_name, i, port.name)) {
+ port.name = "in" + itos(i);
+ }
+ if (!GDVIRTUAL_CALL(_get_input_port_type, i, port.type)) {
+ port.type = (int)PortType::PORT_TYPE_SCALAR;
+ }
- input_ports.clear();
- if (get_script_instance()->has_method("_get_input_port_count")) {
- int input_port_count = (int)get_script_instance()->call("_get_input_port_count");
- bool has_name = get_script_instance()->has_method("_get_input_port_name");
- bool has_type = get_script_instance()->has_method("_get_input_port_type");
- for (int i = 0; i < input_port_count; i++) {
- Port port;
- if (has_name) {
- port.name = (String)get_script_instance()->call("_get_input_port_name", i);
- } else {
- port.name = "in" + itos(i);
+ input_ports.push_back(port);
}
- if (has_type) {
- port.type = (int)get_script_instance()->call("_get_input_port_type", i);
- } else {
- port.type = (int)PortType::PORT_TYPE_SCALAR;
- }
- input_ports.push_back(port);
}
}
- output_ports.clear();
- if (get_script_instance()->has_method("_get_output_port_count")) {
- int output_port_count = (int)get_script_instance()->call("_get_output_port_count");
- bool has_name = get_script_instance()->has_method("_get_output_port_name");
- bool has_type = get_script_instance()->has_method("_get_output_port_type");
- for (int i = 0; i < output_port_count; i++) {
- Port port;
- if (has_name) {
- port.name = (String)get_script_instance()->call("_get_output_port_name", i);
- } else {
- port.name = "out" + itos(i);
- }
- if (has_type) {
- port.type = (int)get_script_instance()->call("_get_output_port_type", i);
- } else {
- port.type = (int)PortType::PORT_TYPE_SCALAR;
+
+ {
+ output_ports.clear();
+ int output_port_count;
+ if (GDVIRTUAL_CALL(_get_output_port_count, output_port_count)) {
+ for (int i = 0; i < output_port_count; i++) {
+ Port port;
+ if (!GDVIRTUAL_CALL(_get_output_port_name, i, port.name)) {
+ port.name = "out" + itos(i);
+ }
+ if (!GDVIRTUAL_CALL(_get_output_port_type, i, port.type)) {
+ port.type = (int)PortType::PORT_TYPE_SCALAR;
+ }
+
+ output_ports.push_back(port);
}
- output_ports.push_back(port);
}
}
}
String VisualShaderNodeCustom::get_caption() const {
- ERR_FAIL_COND_V(!get_script_instance(), "");
- if (get_script_instance()->has_method("_get_name")) {
- return (String)get_script_instance()->call("_get_name");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_name, ret)) {
+ return ret;
}
return "Unnamed";
}
@@ -342,9 +335,8 @@ String VisualShaderNodeCustom::get_output_port_name(int p_port) const {
}
String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
- ERR_FAIL_COND_V(!get_script_instance(), "");
- ERR_FAIL_COND_V(!get_script_instance()->has_method("_get_code"), "");
- Array input_vars;
+ ERR_FAIL_COND_V(!GDVIRTUAL_IS_OVERRIDEN(_get_code), "");
+ Vector<String> input_vars;
for (int i = 0; i < get_input_port_count(); i++) {
input_vars.push_back(p_input_vars[i]);
}
@@ -353,7 +345,8 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::
output_vars.push_back(p_output_vars[i]);
}
String code = " {\n";
- String _code = (String)get_script_instance()->call("_get_code", input_vars, output_vars, (int)p_mode, (int)p_type);
+ String _code;
+ GDVIRTUAL_CALL(_get_code, input_vars, output_vars, (int)p_mode, (int)p_type, _code);
bool nend = _code.ends_with("\n");
_code = _code.insert(0, " ");
_code = _code.replace("\n", "\n ");
@@ -369,10 +362,10 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::
}
String VisualShaderNodeCustom::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- ERR_FAIL_COND_V(!get_script_instance(), "");
- if (get_script_instance()->has_method("_get_global_code")) {
+ String ret;
+ if (GDVIRTUAL_CALL(_get_global_code, (int)p_mode, ret)) {
String code = "// " + get_caption() + "\n";
- code += (String)get_script_instance()->call("_get_global_code", (int)p_mode);
+ code += ret;
code += "\n";
return code;
}
@@ -416,19 +409,19 @@ void VisualShaderNodeCustom::_set_initialized(bool p_enabled) {
}
void VisualShaderNodeCustom::_bind_methods() {
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_name"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_description"));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_category"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_return_icon_type"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_count"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_input_port_type", PropertyInfo(Variant::INT, "port")));
- BIND_VMETHOD(MethodInfo(Variant::STRING_NAME, "_get_input_port_name", PropertyInfo(Variant::INT, "port")));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_count"));
- BIND_VMETHOD(MethodInfo(Variant::INT, "_get_output_port_type", PropertyInfo(Variant::INT, "port")));
- BIND_VMETHOD(MethodInfo(Variant::STRING_NAME, "_get_output_port_name", PropertyInfo(Variant::INT, "port")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_code", PropertyInfo(Variant::ARRAY, "input_vars"), PropertyInfo(Variant::ARRAY, "output_vars"), PropertyInfo(Variant::INT, "mode"), PropertyInfo(Variant::INT, "type")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_global_code", PropertyInfo(Variant::INT, "mode")));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_highend"));
+ GDVIRTUAL_BIND(_get_name);
+ GDVIRTUAL_BIND(_get_description);
+ GDVIRTUAL_BIND(_get_category);
+ GDVIRTUAL_BIND(_get_return_icon_type);
+ GDVIRTUAL_BIND(_get_input_port_count);
+ GDVIRTUAL_BIND(_get_input_port_type, "port");
+ GDVIRTUAL_BIND(_get_input_port_name, "port");
+ GDVIRTUAL_BIND(_get_output_port_count);
+ GDVIRTUAL_BIND(_get_output_port_type, "port");
+ GDVIRTUAL_BIND(_get_output_port_name, "port");
+ GDVIRTUAL_BIND(_get_code, "input_vars", "output_vars", "mode", "type");
+ GDVIRTUAL_BIND(_get_global_code, "mode");
+ GDVIRTUAL_BIND(_is_highend);
ClassDB::bind_method(D_METHOD("_set_initialized", "enabled"), &VisualShaderNodeCustom::_set_initialized);
ClassDB::bind_method(D_METHOD("_is_initialized"), &VisualShaderNodeCustom::_is_initialized);
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index 31651318ae..b3efac02aa 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -314,6 +314,20 @@ protected:
virtual void remove_input_port_default_value(int p_port) override;
virtual void clear_default_input_values() override;
+ GDVIRTUAL0RC(String, _get_name)
+ GDVIRTUAL0RC(String, _get_description)
+ GDVIRTUAL0RC(String, _get_category)
+ GDVIRTUAL0RC(int, _get_return_icon_type)
+ GDVIRTUAL0RC(int, _get_input_port_count)
+ GDVIRTUAL1RC(int, _get_input_port_type, int)
+ GDVIRTUAL1RC(String, _get_input_port_name, int)
+ GDVIRTUAL0RC(int, _get_output_port_count)
+ GDVIRTUAL1RC(int, _get_output_port_type, int)
+ GDVIRTUAL1RC(String, _get_output_port_name, int)
+ GDVIRTUAL4RC(String, _get_code, Vector<String>, TypedArray<String>, int, int)
+ GDVIRTUAL1RC(String, _get_global_code, int)
+ GDVIRTUAL0RC(bool, _is_highend)
+
protected:
void _set_input_port_default_value(int p_port, const Variant &p_value);