summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp8
-rw-r--r--scene/2d/canvas_item.cpp26
-rw-r--r--scene/2d/canvas_item.h1
-rw-r--r--scene/2d/cpu_particles_2d.cpp151
-rw-r--r--scene/2d/cpu_particles_2d.h1
-rw-r--r--scene/2d/joints_2d.cpp8
-rw-r--r--scene/2d/sprite.cpp4
-rw-r--r--scene/2d/touch_screen_button.cpp8
-rw-r--r--scene/3d/cpu_particles.cpp178
-rw-r--r--scene/3d/cpu_particles.h1
-rw-r--r--scene/3d/navigation_mesh.cpp35
-rw-r--r--scene/3d/navigation_mesh.h16
-rw-r--r--scene/3d/soft_body.cpp4
-rw-r--r--scene/3d/spatial.cpp5
-rw-r--r--scene/3d/sprite_3d.cpp4
-rw-r--r--scene/animation/tween.cpp44
-rw-r--r--scene/animation/tween.h3
-rw-r--r--scene/gui/control.cpp6
-rw-r--r--scene/gui/dialogs.cpp2
-rw-r--r--scene/gui/file_dialog.cpp28
-rw-r--r--scene/gui/file_dialog.h3
-rw-r--r--scene/gui/label.cpp5
-rw-r--r--scene/gui/rich_text_label.cpp115
-rw-r--r--scene/gui/rich_text_label.h8
-rw-r--r--scene/gui/spin_box.cpp6
-rw-r--r--scene/gui/text_edit.cpp157
-rw-r--r--scene/gui/text_edit.h9
-rw-r--r--scene/gui/video_player.cpp23
-rw-r--r--scene/gui/video_player.h7
-rw-r--r--scene/main/node.cpp2
-rw-r--r--scene/main/scene_tree.cpp17
-rw-r--r--scene/main/scene_tree.h2
-rw-r--r--scene/main/viewport.cpp1
-rw-r--r--scene/resources/animation.cpp108
-rw-r--r--scene/resources/default_theme/default_theme.cpp9
-rw-r--r--scene/resources/material.cpp77
-rw-r--r--scene/resources/theme.cpp115
-rw-r--r--scene/resources/theme.h72
-rw-r--r--scene/resources/video_stream.h2
-rw-r--r--scene/resources/visual_shader.cpp4
40 files changed, 866 insertions, 409 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 20ec06f033..9d02408641 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -604,10 +604,14 @@ bool AnimatedSprite::_is_playing() const {
void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) {
- if (p_animation)
+ backwards = p_backwards;
+
+ if (p_animation) {
set_animation(p_animation);
+ if (backwards && get_frame() == 0)
+ set_frame(frames->get_frame_count(p_animation) - 1);
+ }
- backwards = p_backwards;
_set_playing(true);
}
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index b4f97a11c9..fa23e3fd39 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -739,6 +739,19 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect
VisualServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
}
+void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
+
+ Vector<Point2> points;
+ points.resize(p_point_count);
+ const float delta_angle = p_end_angle - p_start_angle;
+ for (int i = 0; i < p_point_count; i++) {
+ float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle;
+ points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
+ }
+
+ draw_polyline(points, p_color, p_width, p_antialiased);
+}
+
void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -781,29 +794,29 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(-offset, 0),
+ p_rect.position + Size2(-offset, 0),
p_rect.position + Size2(p_rect.size.width + offset, 0),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(0, offset),
- p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(p_rect.size.width, offset),
+ p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(-offset, p_rect.size.height),
p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
+ p_rect.position + Size2(-offset, p_rect.size.height),
p_color,
p_width,
p_antialiased);
VisualServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Point2(p_rect.size.width, offset),
- p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
+ p_rect.position + Size2(0, p_rect.size.height - offset),
+ p_rect.position + Size2(0, offset),
p_color,
p_width,
p_antialiased);
@@ -1157,6 +1170,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width", "antialiased"), &CanvasItem::draw_multiline, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width", "antialiased"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0), DEFVAL(false));
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index a1724aa532..e51ee601e2 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -307,6 +307,7 @@ public:
void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
+ void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0, bool p_antialiased = false);
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 85c423964b..372d8f614b 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -37,6 +37,9 @@
void CPUParticles2D::set_emitting(bool p_emitting) {
+ if (emitting == p_emitting)
+ return;
+
emitting = p_emitting;
if (emitting)
set_process_internal(true);
@@ -257,8 +260,7 @@ void CPUParticles2D::restart() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
-
- set_emitting(true);
+ emitting = false;
{
int pc = particles.size();
@@ -268,6 +270,8 @@ void CPUParticles2D::restart() {
w[i].active = false;
}
}
+
+ set_emitting(true);
}
void CPUParticles2D::set_direction(Vector2 p_direction) {
@@ -535,6 +539,74 @@ static float rand_from_seed(uint32_t &seed) {
return float(seed % uint32_t(65536)) / 65535.0;
}
+void CPUParticles2D::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ }
+
+ _update_particle_data_buffer();
+}
+
void CPUParticles2D::_particles_process(float p_delta) {
p_delta *= speed_scale;
@@ -965,7 +1037,9 @@ void CPUParticles2D::_set_redraw(bool p_redraw) {
VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ }
VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
@@ -1000,6 +1074,10 @@ void CPUParticles2D::_notification(int p_what) {
}
if (p_what == NOTIFICATION_DRAW) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+
if (!redraw)
return; // don't add to render list
@@ -1017,71 +1095,7 @@ void CPUParticles2D::_notification(int p_what) {
}
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- }
-
- _update_particle_data_buffer();
+ _update_internal();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
@@ -1411,6 +1425,7 @@ CPUParticles2D::CPUParticles2D() {
frame_remainder = 0;
cycle = 0;
redraw = false;
+ emitting = false;
mesh = VisualServer::get_singleton()->mesh_create();
multimesh = VisualServer::get_singleton()->multimesh_create();
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index da668664b9..47b4568dd4 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -174,6 +174,7 @@ private:
Vector2 gravity;
+ void _update_internal();
void _particles_process(float p_delta);
void _update_particle_data_buffer();
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index d8156a0afe..847d08b025 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -37,8 +37,8 @@
void Joint2D::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid())
- Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb);
+ if (ba.is_valid() && bb.is_valid() && exclude_from_collision)
+ Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, false);
Physics2DServer::get_singleton()->free(joint);
joint = RID();
@@ -61,8 +61,6 @@ void Joint2D::_update_joint(bool p_only_free) {
if (!body_a || !body_b)
return;
- SWAP(body_a, body_b);
-
joint = _configure_joint(body_a, body_b);
if (!joint.is_valid())
@@ -133,6 +131,8 @@ void Joint2D::set_exclude_nodes_from_collision(bool p_enable) {
if (exclude_from_collision == p_enable)
return;
+
+ _update_joint(true);
exclude_from_collision = p_enable;
_update_joint();
}
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index d2e1e494e3..8cdfceea52 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -387,6 +387,10 @@ void Sprite::_validate_property(PropertyInfo &property) const {
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
}
void Sprite::_texture_changed() {
diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp
index 9a1a759e72..cf68528388 100644
--- a/scene/2d/touch_screen_button.cpp
+++ b/scene/2d/touch_screen_button.cpp
@@ -325,8 +325,12 @@ void TouchScreenButton::_release(bool p_exiting_tree) {
}
Rect2 TouchScreenButton::_edit_get_rect() const {
- if (texture.is_null())
- return CanvasItem::_edit_get_rect();
+ if (texture.is_null()) {
+ if (shape.is_valid())
+ return shape->get_rect();
+ else
+ return CanvasItem::_edit_get_rect();
+ }
return Rect2(Size2(), texture->get_size());
}
diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp
index 93ff60bc4e..86daabefd2 100644
--- a/scene/3d/cpu_particles.cpp
+++ b/scene/3d/cpu_particles.cpp
@@ -46,9 +46,17 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const {
void CPUParticles::set_emitting(bool p_emitting) {
+ if (emitting == p_emitting)
+ return;
+
emitting = p_emitting;
- if (emitting)
+ if (emitting) {
set_process_internal(true);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (time == 0)
+ _update_internal();
+ }
}
void CPUParticles::set_amount(int p_amount) {
@@ -232,8 +240,7 @@ void CPUParticles::restart() {
inactive_time = 0;
frame_remainder = 0;
cycle = 0;
-
- set_emitting(true);
+ emitting = false;
{
int pc = particles.size();
@@ -243,6 +250,8 @@ void CPUParticles::restart() {
w[i].active = false;
}
}
+
+ set_emitting(true);
}
void CPUParticles::set_direction(Vector3 p_direction) {
@@ -508,6 +517,81 @@ static float rand_from_seed(uint32_t &seed) {
return float(seed % uint32_t(65536)) / 65535.0;
}
+void CPUParticles::_update_internal() {
+
+ if (particles.size() == 0 || !is_visible_in_tree()) {
+ _set_redraw(false);
+ return;
+ }
+
+ float delta = get_process_delta_time();
+ if (emitting) {
+ inactive_time = 0;
+ } else {
+ inactive_time += delta;
+ if (inactive_time > lifetime * 1.2) {
+ set_process_internal(false);
+ _set_redraw(false);
+
+ //reset variables
+ time = 0;
+ inactive_time = 0;
+ frame_remainder = 0;
+ cycle = 0;
+ return;
+ }
+ }
+ _set_redraw(true);
+
+ bool processed = false;
+
+ if (time == 0 && pre_process_time > 0.0) {
+
+ float frame_time;
+ if (fixed_fps > 0)
+ frame_time = 1.0 / fixed_fps;
+ else
+ frame_time = 1.0 / 30.0;
+
+ float todo = pre_process_time;
+
+ while (todo >= 0) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= frame_time;
+ }
+ }
+
+ if (fixed_fps > 0) {
+ float frame_time = 1.0 / fixed_fps;
+ float decr = frame_time;
+
+ float ldelta = delta;
+ if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
+ ldelta = 0.1;
+ } else if (ldelta <= 0.0) { //unlikely but..
+ ldelta = 0.001;
+ }
+ float todo = frame_remainder + ldelta;
+
+ while (todo >= frame_time) {
+ _particles_process(frame_time);
+ processed = true;
+ todo -= decr;
+ }
+
+ frame_remainder = todo;
+
+ } else {
+ _particles_process(delta);
+ processed = true;
+ }
+
+ if (processed) {
+ _update_particle_data_buffer();
+ }
+}
+
void CPUParticles::_particles_process(float p_delta) {
p_delta *= speed_scale;
@@ -1040,7 +1124,9 @@ void CPUParticles::_set_redraw(bool p_redraw) {
VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1);
} else {
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_update_render_thread")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread");
+ }
VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false);
VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0);
}
@@ -1068,85 +1154,24 @@ void CPUParticles::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
set_process_internal(emitting);
+
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
}
if (p_what == NOTIFICATION_EXIT_TREE) {
_set_redraw(false);
}
- if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
-
- if (particles.size() == 0 || !is_visible_in_tree()) {
- _set_redraw(false);
- return;
- }
-
- float delta = get_process_delta_time();
- if (emitting) {
- inactive_time = 0;
- } else {
- inactive_time += delta;
- if (inactive_time > lifetime * 1.2) {
- set_process_internal(false);
- _set_redraw(false);
-
- //reset variables
- time = 0;
- inactive_time = 0;
- frame_remainder = 0;
- cycle = 0;
- return;
- }
- }
- _set_redraw(true);
-
- bool processed = false;
-
- if (time == 0 && pre_process_time > 0.0) {
-
- float frame_time;
- if (fixed_fps > 0)
- frame_time = 1.0 / fixed_fps;
- else
- frame_time = 1.0 / 30.0;
-
- float todo = pre_process_time;
-
- while (todo >= 0) {
- _particles_process(frame_time);
- processed = true;
- todo -= frame_time;
- }
- }
-
- if (fixed_fps > 0) {
- float frame_time = 1.0 / fixed_fps;
- float decr = frame_time;
-
- float ldelta = delta;
- if (ldelta > 0.1) { //avoid recursive stalls if fps goes below 10
- ldelta = 0.1;
- } else if (ldelta <= 0.0) { //unlikely but..
- ldelta = 0.001;
- }
- float todo = frame_remainder + ldelta;
-
- while (todo >= frame_time) {
- _particles_process(frame_time);
- processed = true;
- todo -= decr;
- }
-
- frame_remainder = todo;
-
- } else {
- _particles_process(delta);
- processed = true;
- }
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+ // first update before rendering to avoid one frame delay after emitting starts
+ if (emitting && (time == 0))
+ _update_internal();
+ }
- if (processed) {
- _update_particle_data_buffer();
- }
+ if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
+ _update_internal();
}
if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
@@ -1472,6 +1497,7 @@ CPUParticles::CPUParticles() {
frame_remainder = 0;
cycle = 0;
redraw = false;
+ emitting = false;
set_notify_transform(true);
diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h
index 66b37f359a..635265be7f 100644
--- a/scene/3d/cpu_particles.h
+++ b/scene/3d/cpu_particles.h
@@ -173,6 +173,7 @@ private:
Vector3 gravity;
+ void _update_internal();
void _particles_process(float p_delta);
void _update_particle_data_buffer();
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index f82543b789..496dc4b411 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -108,6 +108,24 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const {
return get_collision_mask() & (1 << p_bit);
}
+void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) {
+ ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX);
+ source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode);
+ _change_notify();
+}
+
+int NavigationMesh::get_source_geometry_mode() const {
+ return source_geometry_mode;
+}
+
+void NavigationMesh::set_source_group_name(StringName p_group_name) {
+ source_group_name = p_group_name;
+}
+
+StringName NavigationMesh::get_source_group_name() const {
+ return source_group_name;
+}
+
void NavigationMesh::set_cell_size(float p_value) {
cell_size = p_value;
}
@@ -387,6 +405,12 @@ void NavigationMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &NavigationMesh::set_collision_mask_bit);
ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &NavigationMesh::get_collision_mask_bit);
+ ClassDB::bind_method(D_METHOD("set_source_geometry_mode", "mask"), &NavigationMesh::set_source_geometry_mode);
+ ClassDB::bind_method(D_METHOD("get_source_geometry_mode"), &NavigationMesh::get_source_geometry_mode);
+
+ ClassDB::bind_method(D_METHOD("set_source_group_name", "mask"), &NavigationMesh::set_source_group_name);
+ ClassDB::bind_method(D_METHOD("get_source_group_name"), &NavigationMesh::get_source_group_name);
+
ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &NavigationMesh::set_cell_size);
ClassDB::bind_method(D_METHOD("get_cell_size"), &NavigationMesh::get_cell_size);
@@ -462,6 +486,8 @@ void NavigationMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/parsed_geometry_type", PROPERTY_HINT_ENUM, "Mesh Instances,Static Colliders,Both"), "set_parsed_geometry_type", "get_parsed_geometry_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "geometry/source_geometry_mode", PROPERTY_HINT_ENUM, "Navmesh Children, Group With Children, Group Explicit"), "set_source_geometry_mode", "get_source_geometry_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "geometry/source_group_name"), "set_source_group_name", "get_source_group_name");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/size", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_size", "get_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "cell/height", PROPERTY_HINT_RANGE, "0.1,1.0,0.01,or_greater"), "set_cell_height", "get_cell_height");
@@ -489,6 +515,13 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const {
return;
}
}
+
+ if (property.name == "geometry/source_group_name") {
+ if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) {
+ property.usage = 0;
+ return;
+ }
+ }
}
NavigationMesh::NavigationMesh() {
@@ -509,6 +542,8 @@ NavigationMesh::NavigationMesh() {
partition_type = SAMPLE_PARTITION_WATERSHED;
parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES;
collision_mask = 0xFFFFFFFF;
+ source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN;
+ source_group_name = "navmesh";
filter_low_hanging_obstacles = false;
filter_ledge_spans = false;
filter_walkable_low_height_spans = false;
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index 5fbf3998ff..d5de653e40 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -77,6 +77,13 @@ public:
PARSED_GEOMETRY_MAX
};
+ enum SourceGeometryMode {
+ SOURCE_GEOMETRY_NAVMESH_CHILDREN = 0,
+ SOURCE_GEOMETRY_GROUPS_WITH_CHILDREN,
+ SOURCE_GEOMETRY_GROUPS_EXPLICIT,
+ SOURCE_GEOMETRY_MAX
+ };
+
protected:
float cell_size;
float cell_height;
@@ -96,6 +103,9 @@ protected:
ParsedGeometryType parsed_geometry_type;
uint32_t collision_mask;
+ SourceGeometryMode source_geometry_mode;
+ StringName source_group_name;
+
bool filter_low_hanging_obstacles;
bool filter_ledge_spans;
bool filter_walkable_low_height_spans;
@@ -114,6 +124,12 @@ public:
void set_collision_mask_bit(int p_bit, bool p_value);
bool get_collision_mask_bit(int p_bit) const;
+ void set_source_geometry_mode(int p_geometry_mode);
+ int get_source_geometry_mode() const;
+
+ void set_source_group_name(StringName p_group_name);
+ StringName get_source_group_name() const;
+
void set_cell_size(float p_value);
float get_cell_size() const;
diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp
index 6c3949a0a8..9bd89f1121 100644
--- a/scene/3d/soft_body.cpp
+++ b/scene/3d/soft_body.cpp
@@ -460,7 +460,9 @@ void SoftBody::update_physics_server() {
} else {
PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL);
- VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ if (VS::get_singleton()->is_connected("frame_pre_draw", this, "_draw_soft_mesh")) {
+ VS::get_singleton()->disconnect("frame_pre_draw", this, "_draw_soft_mesh");
+ }
}
}
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index df831f92ef..9a659ef4af 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -690,11 +690,10 @@ void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_targe
Transform lookat;
lookat.origin = p_pos;
- Vector3 original_scale(get_global_transform().basis.get_scale());
+ Vector3 original_scale(get_scale());
lookat = lookat.looking_at(p_target, p_up);
- // as basis was normalized, we just need to apply original scale back
- lookat.basis.scale(original_scale);
set_global_transform(lookat);
+ set_scale(original_scale);
}
Vector3 Spatial::to_local(Vector3 p_global) const {
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index a8d2f4d415..adcd80b0ab 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -662,6 +662,10 @@ void Sprite3D::_validate_property(PropertyInfo &property) const {
property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
+
+ if (property.name == "frame_coords") {
+ property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ }
}
void Sprite3D::_bind_methods() {
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 1f9793190d..a7d936fcd3 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -281,7 +281,7 @@ void Tween::_bind_methods() {
BIND_ENUM_CONSTANT(EASE_OUT_IN);
}
-Variant &Tween::_get_initial_val(InterpolateData &p_data) {
+Variant Tween::_get_initial_val(const InterpolateData &p_data) const {
// What type of data are we interpolating?
switch (p_data.type) {
@@ -299,7 +299,7 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) {
ERR_FAIL_COND_V(object == NULL, p_data.initial_val);
// Are we targeting a property or a method?
- static Variant initial_val;
+ Variant initial_val;
if (p_data.type == TARGETING_PROPERTY) {
// Get the property from the target object
bool valid = false;
@@ -322,6 +322,41 @@ Variant &Tween::_get_initial_val(InterpolateData &p_data) {
return p_data.delta_val;
}
+Variant Tween::_get_final_val(const InterpolateData &p_data) const {
+ switch (p_data.type) {
+ case FOLLOW_PROPERTY:
+ case FOLLOW_METHOD: {
+ // Get the object that is being followed
+ Object *target = ObjectDB::get_instance(p_data.target_id);
+ ERR_FAIL_COND_V(target == NULL, p_data.initial_val);
+
+ // We want to figure out the final value
+ Variant final_val;
+ if (p_data.type == FOLLOW_PROPERTY) {
+ // Read the property as-is
+ bool valid = false;
+ final_val = target->get_indexed(p_data.target_key, &valid);
+ ERR_FAIL_COND_V(!valid, p_data.initial_val);
+ } else {
+ // We're looking at a method. Call the method on the target object
+ Variant::CallError error;
+ final_val = target->call(p_data.target_key[0], NULL, 0, error);
+ ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, p_data.initial_val);
+ }
+
+ // If we're looking at an INT value, instead convert it to a REAL
+ // This is better for interpolation
+ if (final_val.get_type() == Variant::INT) final_val = final_val.operator real_t();
+
+ return final_val;
+ }
+ default: {
+ // If we're not following a final value/method, use the final value from the data
+ return p_data.final_val;
+ }
+ }
+}
+
Variant &Tween::_get_delta_val(InterpolateData &p_data) {
// What kind of data are we interpolating?
@@ -384,7 +419,7 @@ Variant &Tween::_get_delta_val(InterpolateData &p_data) {
Variant Tween::_run_equation(InterpolateData &p_data) {
// Get the initial and delta values from the data
- Variant &initial_val = _get_initial_val(p_data);
+ Variant initial_val = _get_initial_val(p_data);
Variant &delta_val = _get_delta_val(p_data);
Variant result;
@@ -718,7 +753,8 @@ void Tween::_tween_process(float p_delta) {
// Is the tween now finished?
if (data.finish) {
// Set it to the final value directly
- _apply_tween_value(data, data.final_val);
+ Variant final_val = _get_final_val(data);
+ _apply_tween_value(data, final_val);
// Mark the tween as completed and emit the signal
data.elapsed = 0;
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 64ce099ecd..574238f5c9 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -127,7 +127,8 @@ private:
real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
Variant &_get_delta_val(InterpolateData &p_data);
- Variant &_get_initial_val(InterpolateData &p_data);
+ Variant _get_initial_val(const InterpolateData &p_data) const;
+ Variant _get_final_val(const InterpolateData &p_data) const;
Variant _run_equation(InterpolateData &p_data);
bool _calc_delta_val(const Variant &p_initial_val, const Variant &p_final_val, Variant &p_delta_val);
bool _apply_tween_value(InterpolateData &p_data, Variant &value);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index fafbcf0c55..8b4d5d4980 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2221,9 +2221,11 @@ void Control::_modal_stack_remove() {
if (!data.MI)
return;
- get_viewport()->_gui_remove_from_modal_stack(data.MI, data.modal_prev_focus_owner);
-
+ List<Control *>::Element *element = data.MI;
data.MI = NULL;
+
+ get_viewport()->_gui_remove_from_modal_stack(element, data.modal_prev_focus_owner);
+
data.modal_prev_focus_owner = 0;
}
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 31551d6257..062089d80b 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -356,7 +356,7 @@ void PopupDialog::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item();
- get_stylebox("panel", "PopupMenu")->draw(ci, Rect2(Point2(), get_size()));
+ get_stylebox("panel")->draw(ci, Rect2(Point2(), get_size()));
}
}
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 5cb4bcc64f..6400061309 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -178,8 +178,12 @@ void FileDialog::_post_popup() {
set_process_unhandled_input(true);
// For open dir mode, deselect all items on file dialog open.
- if (mode == MODE_OPEN_DIR)
+ if (mode == MODE_OPEN_DIR) {
deselect_items();
+ file_box->set_visible(false);
+ } else {
+ file_box->set_visible(true);
+ }
}
void FileDialog::_action_pressed() {
@@ -413,6 +417,10 @@ void FileDialog::update_file_name() {
void FileDialog::update_file_list() {
tree->clear();
+
+ // Scroll back to the top after opening a directory
+ tree->get_vscroll_bar()->set_value(0);
+
dir_access->list_dir_begin();
TreeItem *root = tree->create_item();
@@ -894,6 +902,10 @@ FileDialog::FileDialog() {
hbc->add_child(dir_up);
dir_up->connect("pressed", this, "_go_up");
+ drives = memnew(OptionButton);
+ hbc->add_child(drives);
+ drives->connect("item_selected", this, "_select_drive");
+
hbc->add_child(memnew(Label(RTR("Path:"))));
dir = memnew(LineEdit);
hbc->add_child(dir);
@@ -911,10 +923,6 @@ FileDialog::FileDialog() {
show_hidden->connect("toggled", this, "set_show_hidden_files");
hbc->add_child(show_hidden);
- drives = memnew(OptionButton);
- hbc->add_child(drives);
- drives->connect("item_selected", this, "_select_drive");
-
makedir = memnew(Button);
makedir->set_text(RTR("Create Folder"));
makedir->connect("pressed", this, "_make_dir");
@@ -925,18 +933,18 @@ FileDialog::FileDialog() {
tree->set_hide_root(true);
vbc->add_margin_child(RTR("Directories & Files:"), tree, true);
- hbc = memnew(HBoxContainer);
- hbc->add_child(memnew(Label(RTR("File:"))));
+ file_box = memnew(HBoxContainer);
+ file_box->add_child(memnew(Label(RTR("File:"))));
file = memnew(LineEdit);
file->set_stretch_ratio(4);
file->set_h_size_flags(SIZE_EXPAND_FILL);
- hbc->add_child(file);
+ file_box->add_child(file);
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
filter->set_h_size_flags(SIZE_EXPAND_FILL);
filter->set_clip_text(true); // too many extensions overflows it
- hbc->add_child(filter);
- vbc->add_child(hbc);
+ file_box->add_child(filter);
+ vbc->add_child(file_box);
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
access = ACCESS_RESOURCES;
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index 4fd6d0d13c..687ebc8036 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -78,10 +78,11 @@ private:
LineEdit *dir;
OptionButton *drives;
Tree *tree;
+ HBoxContainer *file_box;
LineEdit *file;
+ OptionButton *filter;
AcceptDialog *mkdirerr;
AcceptDialog *exterr;
- OptionButton *filter;
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 510f1b18ad..4edd4b8530 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -452,6 +452,11 @@ void Label::regenerate_word_cache() {
current_word_size += char_width;
line_width += char_width;
total_char_cache++;
+
+ // allow autowrap to cut words when they exceed line width
+ if (autowrap && (current_word_size > width)) {
+ separatable = true;
+ }
}
if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) {
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 42cb89b2d6..0331046492 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -555,12 +555,12 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_font_color_shadow.a > 0) {
float x_ofs_shadow = align_ofs + pofs;
float y_ofs_shadow = y + lh - line_descent;
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
if (p_shadow_as_outline) {
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y), fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
}
}
@@ -624,19 +624,19 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_mode == PROCESS_POINTER && r_click_char)
*r_click_char = 0;
- ENSURE_WIDTH(img->image->get_width());
+ ENSURE_WIDTH(img->size.width);
- bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->image->get_height(), img->image->get_height()));
+ bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height));
if (visible)
line_is_blank = false;
if (p_mode == PROCESS_DRAW && visible) {
- img->image->draw(ci, p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->image->get_height()));
+ img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size));
}
p_char_count++;
- ADVANCE(img->image->get_width());
- CHECK_HEIGHT((img->image->get_height() + font->get_descent()));
+ ADVANCE(img->size.width);
+ CHECK_HEIGHT((img->size.height + font->get_descent()));
} break;
case ITEM_NEWLINE: {
@@ -859,7 +859,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
void RichTextLabel::_scroll_changed(double) {
- if (updating_scroll)
+ if (updating_scroll || !scroll_active)
return;
if (scroll_follow && vscroll->get_value() >= (vscroll->get_max() - vscroll->get_page()))
@@ -1634,7 +1634,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
}
}
-void RichTextLabel::add_image(const Ref<Texture> &p_image) {
+void RichTextLabel::add_image(const Ref<Texture> &p_image, const int p_width, const int p_height) {
if (current->type == ITEM_TABLE)
return;
@@ -1643,6 +1643,30 @@ void RichTextLabel::add_image(const Ref<Texture> &p_image) {
ItemImage *item = memnew(ItemImage);
item->image = p_image;
+
+ if (p_width > 0) {
+ // custom width
+ item->size.width = p_width;
+ if (p_height > 0) {
+ // custom height
+ item->size.height = p_height;
+ } else {
+ // calculate height to keep aspect ratio
+ item->size.height = p_image->get_height() * p_width / p_image->get_width();
+ }
+ } else {
+ if (p_height > 0) {
+ // custom height
+ item->size.height = p_height;
+ // calculate width to keep aspect ratio
+ item->size.width = p_image->get_width() * p_height / p_image->get_height();
+ } else {
+ // keep original width and height
+ item->size.height = p_image->get_height();
+ item->size.width = p_image->get_width();
+ }
+ }
+
_add_item(item, false);
}
@@ -1697,6 +1721,41 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) {
_add_item(item, true);
}
+void RichTextLabel::push_normal() {
+ Ref<Font> normal_font = get_font("normal_font");
+ ERR_FAIL_COND(normal_font.is_null());
+
+ push_font(normal_font);
+}
+
+void RichTextLabel::push_bold() {
+ Ref<Font> bold_font = get_font("bold_font");
+ ERR_FAIL_COND(bold_font.is_null());
+
+ push_font(bold_font);
+}
+
+void RichTextLabel::push_bold_italics() {
+ Ref<Font> bold_italics_font = get_font("bold_italics_font");
+ ERR_FAIL_COND(bold_italics_font.is_null());
+
+ push_font(bold_italics_font);
+}
+
+void RichTextLabel::push_italics() {
+ Ref<Font> italics_font = get_font("italics_font");
+ ERR_FAIL_COND(italics_font.is_null());
+
+ push_font(italics_font);
+}
+
+void RichTextLabel::push_mono() {
+ Ref<Font> mono_font = get_font("mono_font");
+ ERR_FAIL_COND(mono_font.is_null());
+
+ push_font(mono_font);
+}
+
void RichTextLabel::push_color(const Color &p_color) {
ERR_FAIL_COND(current->type == ITEM_TABLE);
@@ -2125,6 +2184,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
int end = p_bbcode.find("[", brk_end);
if (end == -1)
end = p_bbcode.length();
+
String image = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
Ref<Texture> texture = ResourceLoader::load(image, "Texture");
@@ -2133,6 +2193,32 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = end;
tag_stack.push_front(tag);
+ } else if (tag.begins_with("img=")) {
+
+ int width = 0;
+ int height = 0;
+
+ String params = tag.substr(4, tag.length());
+ int sep = params.find("x");
+ if (sep == -1) {
+ width = params.to_int();
+ } else {
+ width = params.substr(0, sep).to_int();
+ height = params.substr(sep + 1, params.length()).to_int();
+ }
+
+ int end = p_bbcode.find("[", brk_end);
+ if (end == -1)
+ end = p_bbcode.length();
+
+ String image = p_bbcode.substr(brk_end + 1, end - brk_end - 1);
+
+ Ref<Texture> texture = ResourceLoader::load(image, "Texture");
+ if (texture.is_valid())
+ add_image(texture, width, height);
+
+ pos = end;
+ tag_stack.push_front("img");
} else if (tag.begins_with("color=")) {
String col = tag.substr(6, tag.length());
@@ -2581,10 +2667,15 @@ void RichTextLabel::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("add_image", "image"), &RichTextLabel::add_image);
+ ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
+ ClassDB::bind_method(D_METHOD("push_normal"), &RichTextLabel::push_normal);
+ ClassDB::bind_method(D_METHOD("push_bold"), &RichTextLabel::push_bold);
+ ClassDB::bind_method(D_METHOD("push_bold_italics"), &RichTextLabel::push_bold_italics);
+ ClassDB::bind_method(D_METHOD("push_italics"), &RichTextLabel::push_italics);
+ ClassDB::bind_method(D_METHOD("push_mono"), &RichTextLabel::push_mono);
ClassDB::bind_method(D_METHOD("push_color", "color"), &RichTextLabel::push_color);
ClassDB::bind_method(D_METHOD("push_align", "align"), &RichTextLabel::push_align);
ClassDB::bind_method(D_METHOD("push_indent", "level"), &RichTextLabel::push_indent);
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index 1c90d974e4..b9837fdfcc 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -148,6 +148,7 @@ private:
struct ItemImage : public Item {
Ref<Texture> image;
+ Size2 size;
ItemImage() { type = ITEM_IMAGE; }
};
@@ -406,10 +407,15 @@ protected:
public:
String get_text();
void add_text(const String &p_text);
- void add_image(const Ref<Texture> &p_image);
+ void add_image(const Ref<Texture> &p_image, const int p_width = 0, const int p_height = 0);
void add_newline();
bool remove_line(const int p_line);
void push_font(const Ref<Font> &p_font);
+ void push_normal();
+ void push_bold();
+ void push_bold_italics();
+ void push_italics();
+ void push_mono();
void push_color(const Color &p_color);
void push_underline();
void push_strikethrough();
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 172c366c41..bf067898e6 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -108,21 +108,21 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) {
case BUTTON_LEFT: {
+ line_edit->grab_focus();
+
set_value(get_value() + (up ? get_step() : -get_step()));
range_click_timer->set_wait_time(0.6);
range_click_timer->set_one_shot(true);
range_click_timer->start();
- line_edit->grab_focus();
-
drag.allowed = true;
drag.capture_pos = mb->get_position();
} break;
case BUTTON_RIGHT: {
- set_value((up ? get_max() : get_min()));
line_edit->grab_focus();
+ set_value((up ? get_max() : get_min()));
} break;
case BUTTON_WHEEL_UP: {
if (line_edit->has_focus()) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5f9b913e8c..8cf6099279 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -161,57 +161,58 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
/* BEGIN */
int lr = cr.begin_key.length();
- if (lr == 0 || lr > left)
- continue;
+ const CharType *kc;
+ bool match;
- const CharType *kc = cr.begin_key.c_str();
+ if (lr != 0 && lr <= left) {
+ kc = cr.begin_key.c_str();
- bool match = true;
+ match = true;
- for (int k = 0; k < lr; k++) {
- if (kc[k] != str[i + k]) {
- match = false;
- break;
+ for (int k = 0; k < lr; k++) {
+ if (kc[k] != str[i + k]) {
+ match = false;
+ break;
+ }
}
- }
- if (match) {
+ if (match) {
- ColorRegionInfo cri;
- cri.end = false;
- cri.region = j;
- text.write[p_line].region_info[i] = cri;
- i += lr - 1;
+ ColorRegionInfo cri;
+ cri.end = false;
+ cri.region = j;
+ text.write[p_line].region_info[i] = cri;
+ i += lr - 1;
- break;
+ break;
+ }
}
/* END */
lr = cr.end_key.length();
- if (lr == 0 || lr > left)
- continue;
+ if (lr != 0 && lr <= left) {
+ kc = cr.end_key.c_str();
- kc = cr.end_key.c_str();
+ match = true;
- match = true;
-
- for (int k = 0; k < lr; k++) {
- if (kc[k] != str[i + k]) {
- match = false;
- break;
+ for (int k = 0; k < lr; k++) {
+ if (kc[k] != str[i + k]) {
+ match = false;
+ break;
+ }
}
- }
- if (match) {
+ if (match) {
- ColorRegionInfo cri;
- cri.end = true;
- cri.region = j;
- text.write[p_line].region_info[i] = cri;
- i += lr - 1;
+ ColorRegionInfo cri;
+ cri.end = true;
+ cri.region = j;
+ text.write[p_line].region_info[i] = cri;
+ i += lr - 1;
- break;
+ break;
+ }
}
}
}
@@ -268,6 +269,12 @@ void TextEdit::Text::clear_wrap_cache() {
}
}
+void TextEdit::Text::clear_info_icons() {
+ for (int i = 0; i < text.size(); i++) {
+ text.write[i].has_info = false;
+ }
+}
+
void TextEdit::Text::clear() {
text.clear();
@@ -302,6 +309,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) {
line.breakpoint = false;
line.bookmark = false;
line.hidden = false;
+ line.has_info = false;
line.width_cache = -1;
line.wrap_amount_cache = -1;
line.data = p_text;
@@ -935,7 +943,7 @@ void TextEdit::_notification(int p_what) {
int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
if (minimap_line >= 0) {
minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
- minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
}
int minimap_draw_amount = minimap_visible_lines + times_line_wraps(minimap_line + 1);
@@ -957,6 +965,10 @@ void TextEdit::_notification(int p_what) {
}
}
+ if (minimap_line < 0 || minimap_line >= (int)text.size()) {
+ break;
+ }
+
Map<int, HighlighterInfo> color_map;
if (syntax_coloring) {
color_map = _get_line_syntax_highlighting(minimap_line);
@@ -1723,7 +1735,9 @@ void TextEdit::_notification(int p_what) {
end = font->get_string_size(l.substr(0, l.rfind(String::chr(0xFFFF)))).x;
}
- draw_string(font, hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font->get_height() * i + spacing), l.replace(String::chr(0xFFFF), ""), font_color);
+ Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent() + font->get_height() * i + spacing);
+ round_ofs = round_ofs.round();
+ draw_string(font, round_ofs, l.replace(String::chr(0xFFFF), ""), font_color);
if (end > 0) {
Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font->get_height() + font->get_height() * i + spacing - 1);
draw_line(b, b + Vector2(end - begin, 0), font_color);
@@ -2146,7 +2160,7 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_visible_line;
if (first_visible_line > 0 && minimap_line >= 0) {
minimap_line -= num_lines_from_rows(first_visible_line, 0, -num_lines_before, wi);
- minimap_line -= (smooth_scroll_enabled ? 1 : 0);
+ minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0);
} else {
minimap_line = 0;
}
@@ -2843,19 +2857,51 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// No need to indent if we are going upwards.
if (auto_indent && !(k->get_command() && k->get_shift())) {
- // Indent once again if previous line will end with ':' or '{' and the line is not a comment
+ // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment
// (i.e. colon/brace precedes current cursor position).
- if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{') && !is_line_comment(cursor.line)) {
- if (indent_using_spaces) {
- ins += space_indent;
- } else {
- ins += "\t";
+ if (cursor.column > 0) {
+ const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(cursor.line);
+ bool indent_char_found = false;
+ bool should_indent = false;
+ char indent_char = ':';
+ char c = text[cursor.line][cursor.column];
+
+ for (int i = 0; i < cursor.column; i++) {
+ c = text[cursor.line][i];
+ switch (c) {
+ case ':':
+ case '{':
+ case '[':
+ case '(':
+ indent_char_found = true;
+ should_indent = true;
+ indent_char = c;
+ continue;
+ }
+
+ if (indent_char_found && cri_map.has(i) && (color_regions[cri_map[i].region].begin_key == "#" || color_regions[cri_map[i].region].begin_key == "//")) {
+
+ should_indent = true;
+ break;
+ } else if (indent_char_found && !_is_whitespace(c)) {
+ should_indent = false;
+ indent_char_found = false;
+ }
}
- // No need to move the brace below if we are not taking the text with us.
- if (text[cursor.line][cursor.column] == '}' && !k->get_command()) {
- brace_indent = true;
- ins += "\n" + ins.substr(1, ins.length() - 2);
+ if (!is_line_comment(cursor.line) && should_indent) {
+ if (indent_using_spaces) {
+ ins += space_indent;
+ } else {
+ ins += "\t";
+ }
+
+ // No need to move the brace below if we are not taking the text with us.
+ char closing_char = _get_right_pair_symbol(indent_char);
+ if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column]) && !k->get_command()) {
+ brace_indent = true;
+ ins += "\n" + ins.substr(1, ins.length() - 2);
+ }
}
}
}
@@ -4751,6 +4797,9 @@ void TextEdit::set_text(String p_text) {
selection.active = false;
}
+ cursor_set_line(0);
+ cursor_set_column(0);
+
update();
setting_text = false;
};
@@ -5052,15 +5101,18 @@ Map<int, TextEdit::Text::ColorRegionInfo> TextEdit::_get_line_color_region_info(
void TextEdit::clear_colors() {
keywords.clear();
+ member_keywords.clear();
color_regions.clear();
color_region_cache.clear();
syntax_highlighting_cache.clear();
text.clear_width_cache();
+ update();
}
void TextEdit::add_keyword_color(const String &p_keyword, const Color &p_color) {
keywords[p_keyword] = p_color;
+ syntax_highlighting_cache.clear();
update();
}
@@ -5077,12 +5129,14 @@ Color TextEdit::get_keyword_color(String p_keyword) const {
void TextEdit::add_color_region(const String &p_begin_key, const String &p_end_key, const Color &p_color, bool p_line_only) {
color_regions.push_back(ColorRegion(p_begin_key, p_end_key, p_color, p_line_only));
+ syntax_highlighting_cache.clear();
text.clear_width_cache();
update();
}
void TextEdit::add_member_keyword(const String &p_keyword, const Color &p_color) {
member_keywords[p_keyword] = p_color;
+ syntax_highlighting_cache.clear();
update();
}
@@ -5096,6 +5150,7 @@ Color TextEdit::get_member_color(String p_member) const {
void TextEdit::clear_member_keywords() {
member_keywords.clear();
+ syntax_highlighting_cache.clear();
update();
}
@@ -5636,9 +5691,7 @@ void TextEdit::set_line_info_icon(int p_line, Ref<Texture> p_icon, String p_info
}
void TextEdit::clear_info_icons() {
- for (int i = 0; i < text.size(); i++) {
- text.set_info_icon(i, NULL, "");
- }
+ text.clear_info_icons();
update();
}
@@ -6020,6 +6073,7 @@ void TextEdit::undo() {
}
}
+ _update_scrollbars();
if (undo_stack_pos->get().type == TextOperation::TYPE_REMOVE) {
cursor_set_line(undo_stack_pos->get().to_line);
cursor_set_column(undo_stack_pos->get().to_column);
@@ -6055,6 +6109,8 @@ void TextEdit::redo() {
break;
}
}
+
+ _update_scrollbars();
cursor_set_line(undo_stack_pos->get().to_line);
cursor_set_column(undo_stack_pos->get().to_column);
undo_stack_pos = undo_stack_pos->next();
@@ -6330,8 +6386,9 @@ void TextEdit::_confirm_completion() {
String line = text[cursor.line];
CharType next_char = line[cursor.column];
CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1];
+ CharType last_completion_char_display = completion_current.display[completion_current.display.length() - 1];
- if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) {
+ if ((last_completion_char == '"' || last_completion_char == '\'') && (last_completion_char == next_char || last_completion_char_display == next_char)) {
_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1);
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index e5d9b006fe..e640bf0ea9 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -78,6 +78,7 @@ public:
bool bookmark : 1;
bool hidden : 1;
bool safe : 1;
+ bool has_info : 1;
int wrap_amount_cache : 24;
Map<int, ColorRegionInfo> region_info;
Ref<Texture> info_icon;
@@ -115,10 +116,15 @@ public:
void set_safe(int p_line, bool p_safe) { text.write[p_line].safe = p_safe; }
bool is_safe(int p_line) const { return text[p_line].safe; }
void set_info_icon(int p_line, Ref<Texture> p_icon, String p_info) {
+ if (p_icon.is_null()) {
+ text.write[p_line].has_info = false;
+ return;
+ }
text.write[p_line].info_icon = p_icon;
text.write[p_line].info = p_info;
+ text.write[p_line].has_info = true;
}
- bool has_info_icon(int p_line) const { return text[p_line].info_icon.is_valid(); }
+ bool has_info_icon(int p_line) const { return text[p_line].has_info; }
const Ref<Texture> &get_info_icon(int p_line) const { return text[p_line].info_icon; }
const String &get_info(int p_line) const { return text[p_line].info; }
void insert(int p_at, const String &p_text);
@@ -127,6 +133,7 @@ public:
void clear();
void clear_width_cache();
void clear_wrap_cache();
+ void clear_info_icons();
_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
Text() { indent_size = 4; }
};
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 5768f58977..fd2d4a1a11 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -36,6 +36,10 @@
int VideoPlayer::sp_get_channel_count() const {
+ if (playback.is_null()) {
+ return 0;
+ }
+
return playback->get_channels();
}
@@ -56,6 +60,9 @@ bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) {
// Called from main thread (eg VideoStreamPlaybackWebm::update)
int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_frames) {
+ ERR_FAIL_NULL_V(p_udata, 0);
+ ERR_FAIL_NULL_V(p_data, 0);
+
VideoPlayer *vp = (VideoPlayer *)p_udata;
int todo = MIN(vp->resampler.get_writer_space(), p_frames);
@@ -71,6 +78,12 @@ int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_f
return todo;
}
+void VideoPlayer::_mix_audios(void *p_self) {
+
+ ERR_FAIL_NULL(p_self);
+ reinterpret_cast<VideoPlayer *>(p_self)->_mix_audio();
+}
+
// Called from audio thread
void VideoPlayer::_mix_audio() {
@@ -143,7 +156,7 @@ void VideoPlayer::_notification(int p_notification) {
bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
- if (stream.is_null() || paused || !playback->is_playing())
+ if (stream.is_null() || paused || playback.is_null() || !playback->is_playing())
return;
double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec());
@@ -358,7 +371,7 @@ void VideoPlayer::set_stream_position(float p_position) {
playback->seek(p_position);
}
-Ref<Texture> VideoPlayer::get_video_texture() {
+Ref<Texture> VideoPlayer::get_video_texture() const {
if (playback.is_valid())
return playback->get_texture();
@@ -394,9 +407,9 @@ StringName VideoPlayer::get_bus() const {
return "Master";
}
-void VideoPlayer::_validate_property(PropertyInfo &property) const {
+void VideoPlayer::_validate_property(PropertyInfo &p_property) const {
- if (property.name == "bus") {
+ if (p_property.name == "bus") {
String options;
for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
@@ -406,7 +419,7 @@ void VideoPlayer::_validate_property(PropertyInfo &property) const {
options += name;
}
- property.hint_string = options;
+ p_property.hint_string = options;
}
}
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 62fb7838b6..7d2821427e 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -55,7 +55,6 @@ class VideoPlayer : public Control {
RID stream_rid;
Ref<ImageTexture> texture;
- Ref<Image> last_frame;
AudioRBResampler resampler;
Vector<AudioFrame> mix_buffer;
@@ -75,19 +74,19 @@ class VideoPlayer : public Control {
void _mix_audio();
static int _audio_mix_callback(void *p_udata, const float *p_data, int p_frames);
- static void _mix_audios(void *self) { reinterpret_cast<VideoPlayer *>(self)->_mix_audio(); }
+ static void _mix_audios(void *p_self);
protected:
static void _bind_methods();
void _notification(int p_notification);
- void _validate_property(PropertyInfo &property) const;
+ void _validate_property(PropertyInfo &p_property) const;
public:
Size2 get_minimum_size() const;
void set_expand(bool p_expand);
bool has_expand() const;
- Ref<Texture> get_video_texture();
+ Ref<Texture> get_video_texture() const;
void set_stream(const Ref<VideoStream> &p_stream);
Ref<VideoStream> get_stream() const;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 7b6c90766f..217dacfbfe 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2832,6 +2832,8 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable);
ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id);
+ ClassDB::bind_method(D_METHOD("update_configuration_warning"), &Node::update_configuration_warning);
+
BIND_CONSTANT(NOTIFICATION_ENTER_TREE);
BIND_CONSTANT(NOTIFICATION_EXIT_TREE);
BIND_CONSTANT(NOTIFICATION_MOVED_IN_PARENT);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 830d314245..38ad6886b1 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -78,6 +78,17 @@ bool SceneTreeTimer::is_pause_mode_process() {
return process_pause;
}
+void SceneTreeTimer::release_connections() {
+
+ List<Connection> connections;
+ get_all_signal_connections(&connections);
+
+ for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
+ Connection const &connection = E->get();
+ disconnect(connection.signal, connection.target, connection.method);
+ }
+}
+
SceneTreeTimer::SceneTreeTimer() {
time_left = 0;
process_pause = true;
@@ -611,6 +622,12 @@ void SceneTree::finish() {
memdelete(root); //delete root
root = NULL;
}
+
+ // cleanup timers
+ for (List<Ref<SceneTreeTimer> >::Element *E = timers.front(); E; E = E->next()) {
+ E->get()->release_connections();
+ }
+ timers.clear();
}
void SceneTree::quit() {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index d387886d61..ef847ebb5b 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -61,6 +61,8 @@ public:
void set_pause_mode_process(bool p_pause_mode_process);
bool is_pause_mode_process();
+ void release_connections();
+
SceneTreeTimer();
};
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 52ef225364..95536bbb23 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -2374,7 +2374,6 @@ void Viewport::_gui_remove_from_modal_stack(List<Control *>::Element *MI, Object
List<Control *>::Element *next = MI->next();
gui.modal_stack.erase(MI);
- MI = NULL;
if (p_prev_focus_owner) {
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 985b38f913..d932545da4 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2741,77 +2741,77 @@ void Animation::copy_track(int p_track, Ref<Animation> p_to_animation) {
void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_track", "type", "at_position"), &Animation::add_track, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("remove_track", "idx"), &Animation::remove_track);
+ ClassDB::bind_method(D_METHOD("remove_track", "track_idx"), &Animation::remove_track);
ClassDB::bind_method(D_METHOD("get_track_count"), &Animation::get_track_count);
- ClassDB::bind_method(D_METHOD("track_get_type", "idx"), &Animation::track_get_type);
- ClassDB::bind_method(D_METHOD("track_get_path", "idx"), &Animation::track_get_path);
- ClassDB::bind_method(D_METHOD("track_set_path", "idx", "path"), &Animation::track_set_path);
+ ClassDB::bind_method(D_METHOD("track_get_type", "track_idx"), &Animation::track_get_type);
+ ClassDB::bind_method(D_METHOD("track_get_path", "track_idx"), &Animation::track_get_path);
+ ClassDB::bind_method(D_METHOD("track_set_path", "track_idx", "path"), &Animation::track_set_path);
ClassDB::bind_method(D_METHOD("find_track", "path"), &Animation::find_track);
- ClassDB::bind_method(D_METHOD("track_move_up", "idx"), &Animation::track_move_up);
- ClassDB::bind_method(D_METHOD("track_move_down", "idx"), &Animation::track_move_down);
- ClassDB::bind_method(D_METHOD("track_move_to", "idx", "to_idx"), &Animation::track_move_to);
- ClassDB::bind_method(D_METHOD("track_swap", "idx", "with_idx"), &Animation::track_swap);
+ ClassDB::bind_method(D_METHOD("track_move_up", "track_idx"), &Animation::track_move_up);
+ ClassDB::bind_method(D_METHOD("track_move_down", "track_idx"), &Animation::track_move_down);
+ ClassDB::bind_method(D_METHOD("track_move_to", "track_idx", "to_idx"), &Animation::track_move_to);
+ ClassDB::bind_method(D_METHOD("track_swap", "track_idx", "with_idx"), &Animation::track_swap);
- ClassDB::bind_method(D_METHOD("track_set_imported", "idx", "imported"), &Animation::track_set_imported);
- ClassDB::bind_method(D_METHOD("track_is_imported", "idx"), &Animation::track_is_imported);
+ ClassDB::bind_method(D_METHOD("track_set_imported", "track_idx", "imported"), &Animation::track_set_imported);
+ ClassDB::bind_method(D_METHOD("track_is_imported", "track_idx"), &Animation::track_is_imported);
- ClassDB::bind_method(D_METHOD("track_set_enabled", "idx", "enabled"), &Animation::track_set_enabled);
- ClassDB::bind_method(D_METHOD("track_is_enabled", "idx"), &Animation::track_is_enabled);
+ ClassDB::bind_method(D_METHOD("track_set_enabled", "track_idx", "enabled"), &Animation::track_set_enabled);
+ ClassDB::bind_method(D_METHOD("track_is_enabled", "track_idx"), &Animation::track_is_enabled);
- ClassDB::bind_method(D_METHOD("transform_track_insert_key", "idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
- ClassDB::bind_method(D_METHOD("track_insert_key", "idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
- ClassDB::bind_method(D_METHOD("track_remove_key", "idx", "key_idx"), &Animation::track_remove_key);
- ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "idx", "position"), &Animation::track_remove_key_at_position);
- ClassDB::bind_method(D_METHOD("track_set_key_value", "idx", "key", "value"), &Animation::track_set_key_value);
- ClassDB::bind_method(D_METHOD("track_set_key_transition", "idx", "key_idx", "transition"), &Animation::track_set_key_transition);
- ClassDB::bind_method(D_METHOD("track_set_key_time", "idx", "key_idx", "time"), &Animation::track_set_key_time);
- ClassDB::bind_method(D_METHOD("track_get_key_transition", "idx", "key_idx"), &Animation::track_get_key_transition);
+ ClassDB::bind_method(D_METHOD("transform_track_insert_key", "track_idx", "time", "location", "rotation", "scale"), &Animation::transform_track_insert_key);
+ ClassDB::bind_method(D_METHOD("track_insert_key", "track_idx", "time", "key", "transition"), &Animation::track_insert_key, DEFVAL(1));
+ ClassDB::bind_method(D_METHOD("track_remove_key", "track_idx", "key_idx"), &Animation::track_remove_key);
+ ClassDB::bind_method(D_METHOD("track_remove_key_at_position", "track_idx", "position"), &Animation::track_remove_key_at_position);
+ ClassDB::bind_method(D_METHOD("track_set_key_value", "track_idx", "key", "value"), &Animation::track_set_key_value);
+ ClassDB::bind_method(D_METHOD("track_set_key_transition", "track_idx", "key_idx", "transition"), &Animation::track_set_key_transition);
+ ClassDB::bind_method(D_METHOD("track_set_key_time", "track_idx", "key_idx", "time"), &Animation::track_set_key_time);
+ ClassDB::bind_method(D_METHOD("track_get_key_transition", "track_idx", "key_idx"), &Animation::track_get_key_transition);
- ClassDB::bind_method(D_METHOD("track_get_key_count", "idx"), &Animation::track_get_key_count);
- ClassDB::bind_method(D_METHOD("track_get_key_value", "idx", "key_idx"), &Animation::track_get_key_value);
- ClassDB::bind_method(D_METHOD("track_get_key_time", "idx", "key_idx"), &Animation::track_get_key_time);
- ClassDB::bind_method(D_METHOD("track_find_key", "idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
+ ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
+ ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
+ ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "idx", "interpolation"), &Animation::track_set_interpolation_type);
- ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "idx"), &Animation::track_get_interpolation_type);
+ ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
+ ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);
- ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap);
- ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "idx"), &Animation::track_get_interpolation_loop_wrap);
+ ClassDB::bind_method(D_METHOD("track_set_interpolation_loop_wrap", "track_idx", "interpolation"), &Animation::track_set_interpolation_loop_wrap);
+ ClassDB::bind_method(D_METHOD("track_get_interpolation_loop_wrap", "track_idx"), &Animation::track_get_interpolation_loop_wrap);
- ClassDB::bind_method(D_METHOD("transform_track_interpolate", "idx", "time_sec"), &Animation::_transform_track_interpolate);
- ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "idx", "mode"), &Animation::value_track_set_update_mode);
- ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "idx"), &Animation::value_track_get_update_mode);
+ ClassDB::bind_method(D_METHOD("transform_track_interpolate", "track_idx", "time_sec"), &Animation::_transform_track_interpolate);
+ ClassDB::bind_method(D_METHOD("value_track_set_update_mode", "track_idx", "mode"), &Animation::value_track_set_update_mode);
+ ClassDB::bind_method(D_METHOD("value_track_get_update_mode", "track_idx"), &Animation::value_track_get_update_mode);
- ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices);
+ ClassDB::bind_method(D_METHOD("value_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_value_track_get_key_indices);
- ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices);
- ClassDB::bind_method(D_METHOD("method_track_get_name", "idx", "key_idx"), &Animation::method_track_get_name);
- ClassDB::bind_method(D_METHOD("method_track_get_params", "idx", "key_idx"), &Animation::method_track_get_params);
+ ClassDB::bind_method(D_METHOD("method_track_get_key_indices", "track_idx", "time_sec", "delta"), &Animation::_method_track_get_key_indices);
+ ClassDB::bind_method(D_METHOD("method_track_get_name", "track_idx", "key_idx"), &Animation::method_track_get_name);
+ ClassDB::bind_method(D_METHOD("method_track_get_params", "track_idx", "key_idx"), &Animation::method_track_get_params);
- ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
+ ClassDB::bind_method(D_METHOD("bezier_track_insert_key", "track_idx", "time", "value", "in_handle", "out_handle"), &Animation::bezier_track_insert_key, DEFVAL(Vector2()), DEFVAL(Vector2()));
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_value", "track_idx", "key_idx", "value"), &Animation::bezier_track_set_key_value);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_in_handle", "track_idx", "key_idx", "in_handle"), &Animation::bezier_track_set_key_in_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_set_key_out_handle", "track_idx", "key_idx", "out_handle"), &Animation::bezier_track_set_key_out_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "idx", "key_idx"), &Animation::bezier_track_get_key_value);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_in_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_get_key_out_handle", "idx", "key_idx"), &Animation::bezier_track_get_key_out_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_value", "track_idx", "key_idx"), &Animation::bezier_track_get_key_value);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_in_handle", "track_idx", "key_idx"), &Animation::bezier_track_get_key_in_handle);
+ ClassDB::bind_method(D_METHOD("bezier_track_get_key_out_handle", "track_idx", "key_idx"), &Animation::bezier_track_get_key_out_handle);
- ClassDB::bind_method(D_METHOD("bezier_track_interpolate", "track", "time"), &Animation::bezier_track_interpolate);
+ ClassDB::bind_method(D_METHOD("bezier_track_interpolate", "track_idx", "time"), &Animation::bezier_track_interpolate);
- ClassDB::bind_method(D_METHOD("audio_track_insert_key", "track", "time", "stream", "start_offset", "end_offset"), &Animation::audio_track_insert_key, DEFVAL(0), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("audio_track_set_key_stream", "idx", "key_idx", "stream"), &Animation::audio_track_set_key_stream);
- ClassDB::bind_method(D_METHOD("audio_track_set_key_start_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_start_offset);
- ClassDB::bind_method(D_METHOD("audio_track_set_key_end_offset", "idx", "key_idx", "offset"), &Animation::audio_track_set_key_end_offset);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "idx", "key_idx"), &Animation::audio_track_get_key_stream);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
- ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_insert_key", "track_idx", "time", "stream", "start_offset", "end_offset"), &Animation::audio_track_insert_key, DEFVAL(0), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_stream", "track_idx", "key_idx", "stream"), &Animation::audio_track_set_key_stream);
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_start_offset", "track_idx", "key_idx", "offset"), &Animation::audio_track_set_key_start_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_set_key_end_offset", "track_idx", "key_idx", "offset"), &Animation::audio_track_set_key_end_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_stream", "track_idx", "key_idx"), &Animation::audio_track_get_key_stream);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_start_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_start_offset);
+ ClassDB::bind_method(D_METHOD("audio_track_get_key_end_offset", "track_idx", "key_idx"), &Animation::audio_track_get_key_end_offset);
- ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track", "time", "animation"), &Animation::animation_track_insert_key);
- ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
- ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "idx", "key_idx"), &Animation::animation_track_get_key_animation);
+ ClassDB::bind_method(D_METHOD("animation_track_insert_key", "track_idx", "time", "animation"), &Animation::animation_track_insert_key);
+ ClassDB::bind_method(D_METHOD("animation_track_set_key_animation", "track_idx", "key_idx", "animation"), &Animation::animation_track_set_key_animation);
+ ClassDB::bind_method(D_METHOD("animation_track_get_key_animation", "track_idx", "key_idx"), &Animation::animation_track_get_key_animation);
ClassDB::bind_method(D_METHOD("set_length", "time_sec"), &Animation::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &Animation::get_length);
@@ -2823,7 +2823,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_step"), &Animation::get_step);
ClassDB::bind_method(D_METHOD("clear"), &Animation::clear);
- ClassDB::bind_method(D_METHOD("copy_track", "track", "to_animation"), &Animation::copy_track);
+ ClassDB::bind_method(D_METHOD("copy_track", "track_idx", "to_animation"), &Animation::copy_track);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 0dcc184a1d..e82819f270 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -432,7 +432,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_font("font", "TextEdit", default_font);
- theme->set_color("background_color", "TextEdit", Color(0, 0, 0));
+ theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2));
theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27));
theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13));
@@ -558,9 +558,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("panel", "PopupPanel", style_pp);
+ // PopupDialog
+
+ Ref<StyleBoxTexture> style_pd = make_stylebox(popup_bg_png, 4, 4, 4, 4, 10, 10, 10, 10);
+ theme->set_stylebox("panel", "PopupDialog", style_pd);
+
// PopupMenu
- theme->set_stylebox("panel", "PopupMenu", make_stylebox(popup_bg_png, 4, 4, 4, 4, 10, 10, 10, 10));
+ theme->set_stylebox("panel", "PopupMenu", style_pd);
theme->set_stylebox("panel_disabled", "PopupMenu", make_stylebox(popup_bg_disabled_png, 4, 4, 4, 4));
theme->set_stylebox("hover", "PopupMenu", selected);
theme->set_stylebox("separator", "PopupMenu", make_stylebox(vseparator_png, 3, 3, 3, 3));
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 0de462d616..b10db9ee61 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -476,7 +476,9 @@ void SpatialMaterial::_update_shader() {
code += ";\n";
code += "uniform vec4 albedo : hint_color;\n";
- code += "uniform sampler2D texture_albedo : hint_albedo;\n";
+ if (textures[TEXTURE_ALBEDO] != NULL) {
+ code += "uniform sampler2D texture_albedo : hint_albedo;\n";
+ }
code += "uniform float specular;\n";
code += "uniform float metallic;\n";
if (grow_enabled) {
@@ -496,10 +498,16 @@ void SpatialMaterial::_update_shader() {
}
code += "uniform float roughness : hint_range(0,1);\n";
code += "uniform float point_size : hint_range(0,128);\n";
- code += "uniform sampler2D texture_metallic : hint_white;\n";
- code += "uniform vec4 metallic_texture_channel;\n";
- code += "uniform sampler2D texture_roughness : hint_white;\n";
- code += "uniform vec4 roughness_texture_channel;\n";
+
+ if (textures[TEXTURE_METALLIC] != NULL) {
+ code += "uniform sampler2D texture_metallic : hint_white;\n";
+ code += "uniform vec4 metallic_texture_channel;\n";
+ }
+
+ if (textures[TEXTURE_ROUGHNESS] != NULL) {
+ code += "uniform sampler2D texture_roughness : hint_white;\n";
+ code += "uniform vec4 roughness_texture_channel;\n";
+ }
if (billboard_mode == BILLBOARD_PARTICLES) {
code += "uniform int particles_anim_h_frames;\n";
code += "uniform int particles_anim_v_frames;\n";
@@ -773,37 +781,51 @@ void SpatialMaterial::_update_shader() {
code += "\t}\n";
}
- if (flags[FLAG_USE_POINT_SIZE]) {
- code += "\tvec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n";
- } else {
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tvec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);\n";
+ if (textures[TEXTURE_ALBEDO] != NULL) {
+ if (flags[FLAG_USE_POINT_SIZE]) {
+ code += "\tvec4 albedo_tex = texture(texture_albedo,POINT_COORD);\n";
} else {
- code += "\tvec4 albedo_tex = texture(texture_albedo,base_uv);\n";
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tvec4 albedo_tex = triplanar_texture(texture_albedo,uv1_power_normal,uv1_triplanar_pos);\n";
+ } else {
+ code += "\tvec4 albedo_tex = texture(texture_albedo,base_uv);\n";
+ }
}
- }
- if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) {
- code += "\talbedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n";
+ if (flags[FLAG_ALBEDO_TEXTURE_FORCE_SRGB]) {
+ code += "\talbedo_tex.rgb = mix(pow((albedo_tex.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),albedo_tex.rgb.rgb * (1.0 / 12.92),lessThan(albedo_tex.rgb,vec3(0.04045)));\n";
+ }
+ } else {
+ code += "\tvec4 albedo_tex = vec4(1.0, 1.0, 1.0, 1.0);\n";
}
if (flags[FLAG_ALBEDO_FROM_VERTEX_COLOR]) {
code += "\talbedo_tex *= COLOR;\n";
}
-
code += "\tALBEDO = albedo.rgb * albedo_tex.rgb;\n";
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n";
+
+ if (textures[TEXTURE_METALLIC] != NULL) {
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tfloat metallic_tex = dot(triplanar_texture(texture_metallic,uv1_power_normal,uv1_triplanar_pos),metallic_texture_channel);\n";
+ } else {
+ code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
+ }
+ code += "\tMETALLIC = metallic_tex * metallic;\n";
} else {
- code += "\tfloat metallic_tex = dot(texture(texture_metallic,base_uv),metallic_texture_channel);\n";
+ code += "\tMETALLIC = metallic;\n";
}
- code += "\tMETALLIC = metallic_tex * metallic;\n";
- if (flags[FLAG_UV1_USE_TRIPLANAR]) {
- code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n";
+
+ if (textures[TEXTURE_ROUGHNESS] != NULL) {
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tfloat roughness_tex = dot(triplanar_texture(texture_roughness,uv1_power_normal,uv1_triplanar_pos),roughness_texture_channel);\n";
+ } else {
+ code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
+ }
+ code += "\tROUGHNESS = roughness_tex * roughness;\n";
} else {
- code += "\tfloat roughness_tex = dot(texture(texture_roughness,base_uv),roughness_texture_channel);\n";
+ code += "\tROUGHNESS = roughness;\n";
}
- code += "\tROUGHNESS = roughness_tex * roughness;\n";
+
code += "\tSPECULAR = specular;\n";
if (features[FEATURE_NORMAL_MAPPING]) {
@@ -1754,6 +1776,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_roughness_texture_channel()
void SpatialMaterial::set_ao_texture_channel(TextureChannel p_channel) {
+ ERR_FAIL_INDEX(p_channel, 5);
ao_texture_channel = p_channel;
VS::get_singleton()->material_set_param(_get_material(), shader_names->ao_texture_channel, _get_texture_mask(p_channel));
}
@@ -1764,6 +1787,7 @@ SpatialMaterial::TextureChannel SpatialMaterial::get_ao_texture_channel() const
void SpatialMaterial::set_refraction_texture_channel(TextureChannel p_channel) {
+ ERR_FAIL_INDEX(p_channel, 5);
refraction_texture_channel = p_channel;
VS::get_singleton()->material_set_param(_get_material(), shader_names->refraction_texture_channel, _get_texture_mask(p_channel));
}
@@ -1804,10 +1828,9 @@ RID SpatialMaterial::get_material_rid_for_2d(bool p_shaded, bool p_transparent,
material->set_flag(FLAG_SRGB_VERTEX_COLOR, true);
material->set_flag(FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
material->set_flag(FLAG_USE_ALPHA_SCISSOR, p_cut_alpha);
- if (p_billboard) {
- material->set_billboard_mode(BILLBOARD_ENABLED);
- } else if (p_billboard_y) {
- material->set_billboard_mode(BILLBOARD_FIXED_Y);
+ if (p_billboard || p_billboard_y) {
+ material->set_flag(FLAG_BILLBOARD_KEEP_SCALE, true);
+ material->set_billboard_mode(p_billboard_y ? BILLBOARD_FIXED_Y : BILLBOARD_ENABLED);
}
materials_for_2d[version] = material;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index ae18be1695..f1429a7d7b 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -37,6 +37,97 @@ void Theme::_emit_theme_changed() {
emit_changed();
}
+PoolVector<String> Theme::_get_icon_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_icon_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_stylebox_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_stylebox_types(void) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_types(&il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_font_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_font_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_color_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_color_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_constant_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_constant_list(p_type, &il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
+PoolVector<String> Theme::_get_type_list(const String &p_type) const {
+
+ PoolVector<String> ilret;
+ List<StringName> il;
+
+ get_type_list(&il);
+ ilret.resize(il.size());
+ for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
+ ilret.push_back(E->get());
+ }
+ return ilret;
+}
+
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
@@ -300,6 +391,8 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_type) {
void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!icon_map.has(p_type))
return;
@@ -344,6 +437,9 @@ void Theme::clear_shader(const StringName &p_name, const StringName &p_type) {
}
void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list) const {
+
+ ERR_FAIL_NULL(p_list);
+
if (!shader_map.has(p_type))
return;
@@ -408,6 +504,8 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_type) {
void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!style_map.has(p_type))
return;
@@ -420,6 +518,8 @@ void Theme::get_stylebox_list(StringName p_type, List<StringName> *p_list) const
}
void Theme::get_stylebox_types(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
const StringName *key = NULL;
while ((key = style_map.next(key))) {
p_list->push_back(*key);
@@ -478,6 +578,8 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_type) {
void Theme::get_font_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!font_map.has(p_type))
return;
@@ -526,6 +628,8 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_type) {
void Theme::get_color_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!color_map.has(p_type))
return;
@@ -574,6 +678,8 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_type) {
void Theme::get_constant_list(StringName p_type, List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
+
if (!constant_map.has(p_type))
return;
@@ -637,6 +743,12 @@ void Theme::copy_default_theme() {
void Theme::copy_theme(const Ref<Theme> &p_other) {
+ if (p_other.is_null()) {
+ clear();
+
+ return;
+ }
+
//these need reconnecting, so add normally
{
const StringName *K = NULL;
@@ -680,8 +792,9 @@ void Theme::copy_theme(const Ref<Theme> &p_other) {
void Theme::get_type_list(List<StringName> *p_list) const {
- Set<StringName> types;
+ ERR_FAIL_NULL(p_list);
+ Set<StringName> types;
const StringName *key = NULL;
while ((key = icon_map.next(key))) {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 187694de65..471e5b1a51 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -52,6 +52,14 @@ class Theme : public Resource {
HashMap<StringName, HashMap<StringName, Color> > color_map;
HashMap<StringName, HashMap<StringName, int> > constant_map;
+ PoolVector<String> _get_icon_list(const String &p_type) const;
+ PoolVector<String> _get_stylebox_list(const String &p_type) const;
+ PoolVector<String> _get_stylebox_types(void) const;
+ PoolVector<String> _get_font_list(const String &p_type) const;
+ PoolVector<String> _get_color_list(const String &p_type) const;
+ PoolVector<String> _get_constant_list(const String &p_type) const;
+ PoolVector<String> _get_type_list(const String &p_type) const;
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -65,70 +73,6 @@ protected:
Ref<Font> default_theme_font;
- PoolVector<String> _get_icon_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_icon_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_stylebox_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_stylebox_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_stylebox_types(void) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_stylebox_types(&il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_font_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_font_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_color_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_color_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_constant_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_constant_list(p_type, &il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
- PoolVector<String> _get_type_list(const String &p_type) const {
- PoolVector<String> ilret;
- List<StringName> il;
- get_type_list(&il);
- for (List<StringName>::Element *E = il.front(); E; E = E->next()) {
- ilret.push_back(E->get());
- }
- return ilret;
- }
-
static void _bind_methods();
public:
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index eb3bf6770f..81c7b062cc 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -63,7 +63,7 @@ public:
//virtual int mix(int16_t* p_buffer,int p_frames)=0;
- virtual Ref<Texture> get_texture() = 0;
+ virtual Ref<Texture> get_texture() const = 0;
virtual void update(float p_delta) = 0;
virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) = 0;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index bd6835f816..cfc57b6e33 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -1599,7 +1599,7 @@ String VisualShaderNodeInput::get_output_port_name(int p_port) const {
}
String VisualShaderNodeInput::get_caption() const {
- return TTR("Input");
+ return "Input";
}
String VisualShaderNodeInput::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 {
@@ -1921,7 +1921,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
String VisualShaderNodeOutput::get_caption() const {
- return TTR("Output");
+ return "Output";
}
String VisualShaderNodeOutput::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 {