summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/area_2d.cpp5
-rw-r--r--scene/2d/audio_stream_player_2d.cpp6
-rw-r--r--scene/2d/audio_stream_player_2d.h2
-rw-r--r--scene/2d/canvas_item.cpp6
-rw-r--r--scene/2d/canvas_item.h2
-rw-r--r--scene/2d/light_2d.cpp2
-rw-r--r--scene/2d/light_occluder_2d.cpp61
-rw-r--r--scene/2d/light_occluder_2d.h9
-rw-r--r--scene/3d/area.cpp4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp6
-rw-r--r--scene/3d/audio_stream_player_3d.h2
-rw-r--r--scene/3d/skeleton.cpp7
-rw-r--r--scene/animation/animation_blend_tree.cpp1
-rw-r--r--scene/animation/animation_node_state_machine.cpp2
-rw-r--r--scene/animation/animation_tree.cpp22
-rw-r--r--scene/animation/skeleton_ik.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp6
-rw-r--r--scene/audio/audio_stream_player.h3
-rw-r--r--scene/gui/line_edit.cpp6
-rw-r--r--scene/gui/slider.cpp15
-rw-r--r--scene/gui/text_edit.cpp18
-rw-r--r--scene/gui/text_edit.h2
-rw-r--r--scene/gui/tree.cpp37
-rw-r--r--scene/main/node.cpp10
-rw-r--r--scene/main/viewport.cpp4
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/bit_map.cpp58
-rw-r--r--scene/resources/bit_map.h4
-rw-r--r--scene/resources/mesh.cpp45
-rw-r--r--scene/resources/mesh.h7
-rw-r--r--scene/resources/resource_format_text.cpp64
-rw-r--r--scene/resources/resource_format_text.h9
-rw-r--r--scene/resources/surface_tool.cpp50
-rw-r--r--scene/resources/surface_tool.h8
-rw-r--r--scene/resources/texture.cpp133
-rw-r--r--scene/resources/texture.h43
-rw-r--r--scene/resources/visual_shader.cpp2
-rw-r--r--scene/resources/visual_shader_nodes.cpp137
-rw-r--r--scene/resources/visual_shader_nodes.h44
39 files changed, 792 insertions, 55 deletions
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 2a225e5797..b322cfe8f1 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -261,8 +261,9 @@ void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_
Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
- ERR_FAIL_COND(!area_in && !E);
-
+ if (!area_in && !E) {
+ return; //likely removed from the tree
+ }
locked = true;
if (area_in) {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 7b28ad2c12..faefd85968 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -473,6 +473,10 @@ bool AudioStreamPlayer2D::get_stream_paused() const {
return stream_paused;
}
+Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
+ return stream_playback;
+}
+
void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);
@@ -512,6 +516,8 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer2D::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer2D::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer2D::get_stream_playback);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer2D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index caf5c6ee49..0cd18fb93b 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -130,6 +130,8 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ Ref<AudioStreamPlayback> get_stream_playback();
+
AudioStreamPlayer2D();
~AudioStreamPlayer2D();
};
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 2739f71543..78e98deb93 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -891,13 +891,13 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased);
}
-void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform, const Color &p_modulate) {
ERR_FAIL_COND(p_mesh.is_null());
RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid);
+ VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), p_transform, p_modulate, texture_rid, normal_map_rid);
}
void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
@@ -1168,7 +1168,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map", "transform", "modulate"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()), DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture", "normal_map"), &CanvasItem::draw_multimesh, DEFVAL(Ref<Texture>()));
ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index bf7cfa8e75..a020ab5029 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -317,7 +317,7 @@ public:
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
- void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1));
void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index d1fce74085..6b12db9e44 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -438,7 +438,7 @@ void Light2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0.01,100,0.01"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Add,Sub,Mix,Mask"), "set_mode", "get_mode");
ADD_GROUP("Range", "range_");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-100,100,0.1"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "range_height", PROPERTY_HINT_RANGE, "-2048,2048,0.1,or_lesser,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_min", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_min", "get_z_range_min");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_z_max", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_range_max", "get_z_range_max");
ADD_PROPERTY(PropertyInfo(Variant::INT, "range_layer_min", PROPERTY_HINT_RANGE, "-512,512,1"), "set_layer_range_min", "get_layer_range_min");
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 5334caed67..3a3f90ac4b 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -32,9 +32,59 @@
#include "core/engine.h"
+#define LINE_GRAB_WIDTH 8
+Rect2 OccluderPolygon2D::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ if (closed) {
+ PoolVector<Vector2>::Read r = polygon.read();
+ item_rect = Rect2();
+ for (int i = 0; i < polygon.size(); i++) {
+ Vector2 pos = r[i];
+ if (i == 0)
+ item_rect.position = pos;
+ else
+ item_rect.expand_to(pos);
+ }
+ rect_cache_dirty = false;
+ } else {
+ if (polygon.size() == 0) {
+ item_rect = Rect2();
+ } else {
+ Vector2 d = Vector2(LINE_GRAB_WIDTH, LINE_GRAB_WIDTH);
+ item_rect = Rect2(polygon[0] - d, 2 * d);
+ for (int i = 1; i < polygon.size(); i++) {
+ item_rect.expand_to(polygon[i] - d);
+ item_rect.expand_to(polygon[i] + d);
+ }
+ }
+ }
+ }
+
+ return item_rect;
+}
+
+bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (closed) {
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+ } else {
+ const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance;
+ PoolVector<Vector2>::Read points = polygon.read();
+ for (int i = 0; i < polygon.size() - 1; i++) {
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]);
+ if (p.distance_to(p_point) <= d)
+ return true;
+ }
+
+ return false;
+ }
+}
+
void OccluderPolygon2D::set_polygon(const PoolVector<Vector2> &p_polygon) {
polygon = p_polygon;
+ rect_cache_dirty = true;
VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed);
emit_changed();
}
@@ -100,6 +150,7 @@ OccluderPolygon2D::OccluderPolygon2D() {
occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create();
closed = true;
cull = CULL_DISABLED;
+ rect_cache_dirty = true;
}
OccluderPolygon2D::~OccluderPolygon2D() {
@@ -164,6 +215,16 @@ void LightOccluder2D::_notification(int p_what) {
}
}
+Rect2 LightOccluder2D::_edit_get_rect() const {
+
+ return occluder_polygon.is_valid() ? occluder_polygon->_edit_get_rect() : Rect2();
+}
+
+bool LightOccluder2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return occluder_polygon.is_valid() ? occluder_polygon->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+
void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) {
#ifdef DEBUG_ENABLED
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index 498d65d764..7931cd0b30 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -50,10 +50,16 @@ private:
bool closed;
CullMode cull;
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_polygon(const PoolVector<Vector2> &p_polygon);
PoolVector<Vector2> get_polygon() const;
@@ -85,6 +91,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon);
Ref<OccluderPolygon2D> get_occluder_polygon() const;
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 13d9181082..3557f0425c 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -356,7 +356,9 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar
Map<ObjectID, AreaState>::Element *E = area_map.find(objid);
- ERR_FAIL_COND(!area_in && !E);
+ if (!area_in && !E) {
+ return; //likely removed from the tree
+ }
locked = true;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 4b3934c4ea..4d5ffc31b3 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -887,6 +887,10 @@ bool AudioStreamPlayer3D::get_stream_paused() const {
return stream_paused;
}
+Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
+ return stream_playback;
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
@@ -953,6 +957,8 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer3D::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer3D::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback);
+
ClassDB::bind_method(D_METHOD("_bus_layout_changed"), &AudioStreamPlayer3D::_bus_layout_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index e467c170fb..1175547028 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -206,6 +206,8 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ Ref<AudioStreamPlayback> get_stream_playback();
+
AudioStreamPlayer3D();
~AudioStreamPlayer3D();
};
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index b7279e4d4f..15c089ec10 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -540,10 +540,11 @@ void Skeleton::clear_bones() {
void Skeleton::set_bone_pose(int p_bone, const Transform &p_pose) {
ERR_FAIL_INDEX(p_bone, bones.size());
- ERR_FAIL_COND(!is_inside_tree());
bones.write[p_bone].pose = p_pose;
- _make_dirty();
+ if (is_inside_tree()) {
+ _make_dirty();
+ }
}
Transform Skeleton::get_bone_pose(int p_bone) const {
@@ -772,6 +773,8 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest);
ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest);
+ ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests);
+
ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest);
ClassDB::bind_method(D_METHOD("is_bone_rest_disabled", "bone_idx"), &Skeleton::is_bone_rest_disabled);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 11ce866690..e9b38ae990 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -363,6 +363,7 @@ AnimationNodeOneShot::AnimationNodeOneShot() {
fade_out = 0.1;
autorestart = false;
autorestart_delay = 1;
+ autorestart_random_delay = 0;
mix = MIX_MODE_BLEND;
sync = false;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 68ad71d01c..1e3470cd90 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -960,7 +960,7 @@ void AnimationNodeStateMachine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_end_node", "name"), &AnimationNodeStateMachine::set_end_node);
ClassDB::bind_method(D_METHOD("get_end_node"), &AnimationNodeStateMachine::get_end_node);
- ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset);
+ ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &AnimationNodeStateMachine::set_graph_offset);
ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeStateMachine::_tree_changed);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 2f209ed946..d1d3582c9d 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -891,7 +891,7 @@ void AnimationTree::_process_graph(float p_delta) {
t->loc = Vector3();
t->rot = Quat();
t->rot_blend_accum = 0;
- t->scale = Vector3();
+ t->scale = Vector3(1, 1, 1);
}
float prev_time = time - delta;
@@ -952,11 +952,9 @@ void AnimationTree::_process_graph(float p_delta) {
t->loc = loc;
t->rot = rot;
t->rot_blend_accum = 0;
- t->scale = Vector3();
+ t->scale = scale;
}
- scale -= Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes
-
if (err != OK)
continue;
@@ -1241,8 +1239,6 @@ void AnimationTree::_process_graph(float p_delta) {
Transform xform;
xform.origin = t->loc;
- t->scale += Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes and root motion
-
xform.basis.set_quat_scale(t->rot, t->scale);
if (t->root_motion) {
@@ -1302,9 +1298,17 @@ void AnimationTree::_notification(int p_what) {
_clear_caches();
if (last_animation_player) {
- Object *old_player = ObjectDB::get_instance(last_animation_player);
- if (old_player) {
- old_player->disconnect("caches_cleared", this, "_clear_caches");
+ Object *player = ObjectDB::get_instance(last_animation_player);
+ if (player) {
+ player->disconnect("caches_cleared", this, "_clear_caches");
+ }
+ }
+ } else if (p_what == NOTIFICATION_ENTER_TREE) {
+ if (last_animation_player) {
+
+ Object *player = ObjectDB::get_instance(last_animation_player);
+ if (player) {
+ player->connect("caches_cleared", this, "_clear_caches");
}
}
}
diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp
index 88fb2d5bfc..4da3e6ee28 100644
--- a/scene/animation/skeleton_ik.cpp
+++ b/scene/animation/skeleton_ik.cpp
@@ -335,7 +335,7 @@ void SkeletonIK::_validate_property(PropertyInfo &property) const {
if (skeleton) {
- String names;
+ String names("--,");
for (int i = 0; i < skeleton->get_bone_count(); i++) {
if (i > 0)
names += ",";
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 2688041d18..47278b8fc1 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -331,6 +331,10 @@ void AudioStreamPlayer::_bus_layout_changed() {
_change_notify();
}
+Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
+ return stream_playback;
+}
+
void AudioStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer::set_stream);
@@ -366,6 +370,8 @@ void AudioStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream_paused", "pause"), &AudioStreamPlayer::set_stream_paused);
ClassDB::bind_method(D_METHOD("get_stream_paused"), &AudioStreamPlayer::get_stream_paused);
+ ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer::get_stream_playback);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index fba8ce7dd3..590bef95b0 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -106,6 +106,9 @@ public:
void set_stream_paused(bool p_pause);
bool get_stream_paused() const;
+ Ref<AudioStreamPlayback> get_stream_playback();
+
+
AudioStreamPlayer();
~AudioStreamPlayer();
};
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 0c5dc39273..e83ef95db6 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1159,8 +1159,10 @@ void LineEdit::set_cursor_position(int p_pos) {
} else if (cursor_pos > window_pos) {
/* Adjust window if cursor goes too much to the right */
int window_width = get_size().width - style->get_minimum_size().width;
- if (right_icon.is_valid()) {
- window_width -= right_icon->get_width();
+ bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled;
+ if (right_icon.is_valid() || display_clear_icon) {
+ Ref<Texture> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon;
+ window_width -= r_icon->get_width();
}
if (window_width < 0)
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index eb04b85931..028ca41cbf 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -34,8 +34,15 @@
Size2 Slider::get_minimum_size() const {
Ref<StyleBox> style = get_stylebox("slider");
- Size2i ms = style->get_minimum_size() + style->get_center_size();
- return ms;
+ Size2i ss = style->get_minimum_size() + style->get_center_size();
+
+ Ref<Texture> grabber = get_icon("grabber");
+ Size2i rs = grabber->get_size();
+
+ if (orientation == HORIZONTAL)
+ return Size2i(ss.width, MAX(ss.height, rs.height));
+ else
+ return Size2i(MAX(ss.width, rs.width), ss.height);
}
void Slider::_gui_input(Ref<InputEvent> p_event) {
@@ -134,7 +141,11 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
void Slider::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ minimum_size_changed();
+ update();
+ } break;
case NOTIFICATION_MOUSE_ENTER: {
mouse_inside = true;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 9acf8d40c9..d06f066295 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -590,6 +590,12 @@ void TextEdit::_notification(int p_what) {
}
} break;
case NOTIFICATION_DRAW: {
+
+ if (first_draw) {
+ //size may not be the final one, so attempts to ensure cursor was visible may have failed
+ adjust_viewport_to_cursor();
+ first_draw = false;
+ }
Size2 size = get_size();
if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
draw_caret = false;
@@ -5183,6 +5189,17 @@ bool TextEdit::is_folded(int p_line) const {
return false;
}
+Vector<int> TextEdit::get_folded_lines() const {
+ Vector<int> folded_lines;
+
+ for (int i = 0; i < text.size(); i++) {
+ if (is_folded(i)) {
+ folded_lines.push_back(i);
+ }
+ }
+ return folded_lines;
+}
+
void TextEdit::fold_line(int p_line) {
ERR_FAIL_INDEX(p_line, text.size());
@@ -6356,6 +6373,7 @@ TextEdit::TextEdit() {
menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
menu->connect("id_pressed", this, "menu_option");
+ first_draw = true;
}
TextEdit::~TextEdit() {
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 33f0a3f45d..503bead785 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -275,6 +275,7 @@ private:
int wrap_at;
int wrap_right_offset;
+ bool first_draw;
bool setting_row;
bool draw_tabs;
bool override_selected_font_color;
@@ -489,6 +490,7 @@ public:
bool can_fold(int p_line) const;
bool is_folded(int p_line) const;
+ Vector<int> get_folded_lines() const;
void fold_line(int p_line);
void unfold_line(int p_line);
void toggle_fold_line(int p_line);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 7f00e7bd24..7e59606d2b 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2850,7 +2850,7 @@ void Tree::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAG_BEGIN) {
single_select_defer = NULL;
- if (cache.scroll_speed > 0 && get_rect().has_point(get_viewport()->get_mouse_position() - get_global_position())) {
+ if (cache.scroll_speed > 0) {
scrolling = true;
set_physics_process_internal(true);
}
@@ -2897,22 +2897,22 @@ void Tree::_notification(int p_what) {
}
}
- if (scrolling) {
- Point2 point = get_viewport()->get_mouse_position() - get_global_position();
- if (point.x < cache.scroll_border) {
- point.x -= cache.scroll_border;
- } else if (point.x > get_size().width - cache.scroll_border) {
- point.x -= get_size().width - cache.scroll_border;
- } else {
- point.x = 0;
+ Point2 mouse_position = get_viewport()->get_mouse_position() - get_global_position();
+ if (scrolling && get_rect().grow(cache.scroll_border).has_point(mouse_position)) {
+ Point2 point;
+
+ if ((ABS(mouse_position.x) < ABS(mouse_position.x - get_size().width)) && (ABS(mouse_position.x) < cache.scroll_border)) {
+ point.x = mouse_position.x - cache.scroll_border;
+ } else if (ABS(mouse_position.x - get_size().width) < cache.scroll_border) {
+ point.x = mouse_position.x - (get_size().width - cache.scroll_border);
}
- if (point.y < cache.scroll_border) {
- point.y -= cache.scroll_border;
- } else if (point.y > get_size().height - cache.scroll_border) {
- point.y -= get_size().height - cache.scroll_border;
- } else {
- point.y = 0;
+
+ if ((ABS(mouse_position.y) < ABS(mouse_position.y - get_size().height)) && (ABS(mouse_position.y) < cache.scroll_border)) {
+ point.y = mouse_position.y - cache.scroll_border;
+ } else if (ABS(mouse_position.y - get_size().height) < cache.scroll_border) {
+ point.y = mouse_position.y - (get_size().height - cache.scroll_border);
}
+
point *= cache.scroll_speed * get_physics_process_delta_time();
point += get_scroll();
h_scroll->set_value(point.x);
@@ -3388,10 +3388,13 @@ void Tree::ensure_cursor_is_visible() {
int h = compute_item_height(selected) + cache.vseparation;
int screenh = get_size().height - h_scroll->get_combined_minimum_size().height;
- if (ofs + h > v_scroll->get_value() + screenh)
+ if (h > screenh) { //screen size is too small, maybe it was not resized yet.
+ v_scroll->set_value(ofs);
+ } else if (ofs + h > v_scroll->get_value() + screenh) {
v_scroll->call_deferred("set_value", ofs - screenh + h);
- else if (ofs < v_scroll->get_value())
+ } else if (ofs < v_scroll->get_value()) {
v_scroll->set_value(ofs);
+ }
}
int Tree::get_pressed_button() const {
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 128168ca72..cbe700c826 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2421,7 +2421,7 @@ void Node::_replace_connections_target(Node *p_new_target) {
if (c.flags & CONNECT_PERSIST) {
c.source->disconnect(c.signal, this, c.method);
- bool valid = p_new_target->has_method(c.method) || p_new_target->get_script().is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
+ bool valid = p_new_target->has_method(c.method) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
ERR_EXPLAIN("Attempt to connect signal \'" + c.source->get_class() + "." + c.signal + "\' to nonexistent method \'" + c.target->get_class() + "." + c.method + "\'");
ERR_CONTINUE(!valid);
c.source->connect(c.signal, p_new_target, c.method, c.binds, c.flags);
@@ -2759,6 +2759,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process);
ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes);
ClassDB::bind_method(D_METHOD("get_position_in_parent"), &Node::get_position_in_parent);
+
ClassDB::bind_method(D_METHOD("set_display_folded", "fold"), &Node::set_display_folded);
ClassDB::bind_method(D_METHOD("is_displayed_folded"), &Node::is_displayed_folded);
@@ -2871,7 +2872,12 @@ void Node::_bind_methods() {
//ADD_PROPERTY( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
ADD_GROUP("Pause", "pause_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded");
+
+#ifdef ENABLE_DEPRECATED
+ //no longer exists, but remains for compatibility (keep previous scenes folded
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", 0), "set_display_folded", "is_displayed_folded");
+#endif
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 2524af9cfb..52f63ddc1d 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -391,9 +391,11 @@ void Viewport::_notification(int p_what) {
if (physics_object_picking && (to_screen_rect == Rect2() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) {
+#ifndef _3D_DISABLED
Vector2 last_pos(1e20, 1e20);
CollisionObject *last_object = NULL;
ObjectID last_id = 0;
+#endif
PhysicsDirectSpaceState::RayResult result;
Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space());
@@ -3222,7 +3224,7 @@ Viewport::Viewport() {
gui.tooltip_timer = -1;
//gui.tooltip_timer->force_parent_owned();
- gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.7);
+ gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
gui.tooltip = NULL;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 87a15bbeda..9face3e476 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -521,6 +521,8 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTransformUniform>();
ClassDB::register_class<VisualShaderNodeTextureUniform>();
ClassDB::register_class<VisualShaderNodeCubeMapUniform>();
+ ClassDB::register_class<VisualShaderNodeIf>();
+ ClassDB::register_class<VisualShaderNodeSwitch>();
ClassDB::register_class<ShaderMaterial>();
ClassDB::register_virtual_class<CanvasItem>();
@@ -633,6 +635,7 @@ void register_scene_types() {
ClassDB::register_class<StreamTexture>();
ClassDB::register_class<ImageTexture>();
ClassDB::register_class<AtlasTexture>();
+ ClassDB::register_class<MeshTexture>();
ClassDB::register_class<LargeTexture>();
ClassDB::register_class<CurveTexture>();
ClassDB::register_class<GradientTexture>();
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index 55264bcdf9..a9d85be0dc 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -595,6 +595,64 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con
return result_array;
}
+void BitMap::resize(const Size2& p_new_size) {
+
+ Ref<BitMap> new_bitmap;
+ new_bitmap.instance();
+ new_bitmap->create(p_new_size);
+ int lw = MIN(width,p_new_size.width);
+ int lh = MIN(height,p_new_size.height);
+ for(int x=0;x<lw;x++) {
+ for(int y=0;y<lh;y++) {
+ new_bitmap->set_bit(Vector2(x,y),get_bit(Vector2(x,y)));
+ }
+ }
+
+ width = new_bitmap->width;
+ height = new_bitmap->height;
+ bitmask = new_bitmap->bitmask;
+}
+
+Ref<Image> BitMap::convert_to_image() const {
+
+ Ref<Image> image;
+ image.instance();
+ image->create(width,height,false,Image::FORMAT_L8);
+ image->lock();
+ for(int i=0;i<width;i++) {
+ for(int j=0;j<height;j++) {
+ image->set_pixel( i,j,get_bit(Point2(i,j)) ? Color(1,1,1) : Color(0,0,0));
+ }
+ }
+
+ image->unlock();
+
+ return image;
+}
+void BitMap::blit(const Vector2& p_pos,const Ref<BitMap>& p_bitmap) {
+
+ int x = p_pos.x;
+ int y = p_pos.y;
+ int w = p_bitmap->get_size().width;
+ int h = p_bitmap->get_size().height;
+
+ for(int i=0;i<w;i++) {
+ for (int j=0;j<h;j++) {
+ int px = x+i;
+ int py = y+j;
+ if (px<0 || px>=width)
+ continue;
+ if (py<0 || py>=height)
+ continue;
+ if (p_bitmap->get_bit(Vector2(i,j))) {
+ set_bit(Vector2(x,y),true);
+ }
+ }
+ }
+
+}
+
+
void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h
index b3c86afd38..6e1171b8a9 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -64,9 +64,13 @@ public:
int get_true_bit_count() const;
Size2 get_size() const;
+ void resize(const Size2& p_new_size);
void grow_mask(int p_pixels, const Rect2 &p_rect);
+ void blit(const Vector2& p_pos,const Ref<BitMap>& p_bitmap);
+ Ref<Image> convert_to_image() const;
+
Vector<Vector<Vector2> > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
BitMap();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 85018f38d7..67639858ce 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -37,6 +37,8 @@
#include <stdlib.h>
+Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = NULL;
+
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid())
@@ -543,6 +545,49 @@ void Mesh::clear_cache() const {
debug_lines.clear();
}
+Vector<Ref<Shape> > Mesh::convex_decompose() const {
+
+ ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape> >());
+
+ PoolVector<Face3> faces = get_faces();
+ Vector<Face3> f3;
+ f3.resize(faces.size());
+ PoolVector<Face3>::Read f = faces.read();
+ for (int i = 0; i < f3.size(); i++) {
+ f3.write[i] = f[i];
+ }
+
+ Vector<Vector<Face3> > decomposed = convex_composition_function(f3);
+
+ Vector<Ref<Shape> > ret;
+
+ for (int i = 0; i < decomposed.size(); i++) {
+ Set<Vector3> points;
+ for (int j = 0; j < decomposed[i].size(); j++) {
+ points.insert(decomposed[i][j].vertex[0]);
+ points.insert(decomposed[i][j].vertex[1]);
+ points.insert(decomposed[i][j].vertex[2]);
+ }
+
+ PoolVector<Vector3> convex_points;
+ convex_points.resize(points.size());
+ {
+ PoolVector<Vector3>::Write w = convex_points.write();
+ int idx = 0;
+ for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
+ w[idx++] = E->get();
+ }
+ }
+
+ Ref<ConvexPolygonShape> shape;
+ shape.instance();
+ shape->set_points(convex_points);
+ ret.push_back(shape);
+ }
+
+ return ret;
+}
+
Mesh::Mesh() {
}
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index dabfc6ea60..1457d283bd 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -31,6 +31,7 @@
#ifndef MESH_H
#define MESH_H
+#include "core/math/face3.h"
#include "core/math/triangle_mesh.h"
#include "core/resource.h"
#include "scene/resources/material.h"
@@ -147,6 +148,12 @@ public:
Size2 get_lightmap_size_hint() const;
void clear_cache() const;
+ typedef Vector<Vector<Face3> > (*ConvexDecompositionFunc)(const Vector<Face3> &);
+
+ static ConvexDecompositionFunc convex_composition_function;
+
+ Vector<Ref<Shape> > convex_decompose() const;
+
Mesh();
};
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 2e54424c90..e9f90fc85f 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -445,6 +445,11 @@ Error ResourceInteractiveLoaderText::poll() {
} else {
resource_cache.push_back(res);
+#ifdef TOOLS_ENABLED
+ //remember ID for saving
+ res->set_id_for_path(local_path,index);
+#endif
+
}
ExtResource er;
@@ -1355,7 +1360,7 @@ String ResourceFormatSaverTextInstance::_write_resource(const RES &res) {
if (external_resources.has(res)) {
- return "ExtResource( " + itos(external_resources[res] + 1) + " )";
+ return "ExtResource( " + itos(external_resources[res]) + " )";
} else {
if (internal_resources.has(res)) {
@@ -1539,18 +1544,65 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
f->store_line("]\n"); //one empty line
}
- Vector<RES> sorted_er;
- sorted_er.resize(external_resources.size());
+ {
+
+
+
+ }
+
+#ifdef TOOLS_ENABLED
+ //keep order from cached ids
+ Set<int> cached_ids_found;
+ for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) {
+ int cached_id = E->key()->get_id_for_path(local_path);
+ if (cached_id < 0 || cached_ids_found.has(cached_id)) {
+ E->get() = -1; //reset
+ } else {
+ E->get() = cached_id;
+ cached_ids_found.insert(cached_id);
+ }
+ }
+ //create IDs for non cached resources
+ for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) {
+ if (cached_ids_found.has(E->get())) { //already cached, go on
+ continue;
+ }
+
+ int attempt = 1; //start from one, more readable format
+ while(cached_ids_found.has(attempt)) {
+ attempt++;
+ }
+
+ cached_ids_found.insert(attempt);
+ E->get() = attempt;
+ //update also in resource
+ Ref<Resource> res = E->key();
+ res->set_id_for_path(local_path,attempt);
+ }
+#else
+ //make sure to start from one, as it makes format more readable
+ for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) {
+ E->get() = E->get() + 1;
+ }
+#endif
+
+ Vector<ResourceSort> sorted_er;
for (Map<RES, int>::Element *E = external_resources.front(); E; E = E->next()) {
- sorted_er.write[E->get()] = E->key();
+ ResourceSort rs;
+ rs.resource = E->key();
+ rs.index = E->get();
+ sorted_er.push_back(rs);
}
+ sorted_er.sort();
+
+
for (int i = 0; i < sorted_er.size(); i++) {
- String p = sorted_er[i]->get_path();
+ String p = sorted_er[i].resource->get_path();
- f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i]->get_save_class() + "\" id=" + itos(i + 1) + "]\n"); //bundled
+ f->store_string("[ext_resource path=\"" + p + "\" type=\"" + sorted_er[i].resource->get_save_class() + "\" id=" + itos(sorted_er[i].index) + "]\n"); //bundled
}
if (external_resources.size())
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 8d78ab33b0..ab6f94986c 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -169,6 +169,15 @@ class ResourceFormatSaverTextInstance {
Map<RES, int> external_resources;
Map<RES, int> internal_resources;
+ struct ResourceSort {
+ RES resource;
+ int index;
+ bool operator<(const ResourceSort& p_right) const {
+ return index < p_right.index;
+ }
+
+ };
+
void _find_resources(const Variant &p_variant, bool p_main = false);
static String _write_resources(void *ud, const RES &p_resource);
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index c0abee2030..3ba43006a3 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -108,8 +108,55 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
vtx.bones = last_bones;
vtx.tangent = last_tangent.normal;
vtx.binormal = last_normal.cross(last_tangent.normal).normalized() * last_tangent.d;
+
+ const int expected_vertices = 4;
+
+ if ((format & Mesh::ARRAY_FORMAT_WEIGHTS || format & Mesh::ARRAY_FORMAT_BONES) && (vtx.weights.size() != expected_vertices || vtx.bones.size() != expected_vertices)) {
+ //ensure vertices are the expected amount
+ ERR_FAIL_COND(vtx.weights.size() != vtx.bones.size());
+ if (vtx.weights.size() < expected_vertices) {
+ //less than requred, fill
+ for (int i = vtx.weights.size(); i < expected_vertices; i++) {
+ vtx.weights.push_back(0);
+ vtx.bones.push_back(0);
+ }
+ } else if (vtx.weights.size() > expected_vertices) {
+ //more than required, sort, cap and normalize.
+ Vector<WeightSort> weights;
+ for (int i = 0; i < vtx.weights.size(); i++) {
+ WeightSort ws;
+ ws.index = vtx.bones[i];
+ ws.weight = vtx.weights[i];
+ weights.push_back(ws);
+ }
+
+ //sort
+ weights.sort();
+ //cap
+ weights.resize(expected_vertices);
+ //renormalize
+ float total = 0;
+ for (int i = 0; i < expected_vertices; i++) {
+ total += weights[i].weight;
+ }
+
+ vtx.weights.resize(expected_vertices);
+ vtx.bones.resize(expected_vertices);
+
+ for (int i = 0; i < expected_vertices; i++) {
+ if (total > 0) {
+ vtx.weights.write[i] = weights[i].weight / total;
+ } else {
+ vtx.weights.write[i] = 0;
+ }
+ vtx.bones.write[i] = weights[i].index;
+ }
+ }
+ }
+
vertex_array.push_back(vtx);
first = false;
+
format |= Mesh::ARRAY_FORMAT_VERTEX;
}
void SurfaceTool::add_color(Color p_color) {
@@ -161,7 +208,6 @@ void SurfaceTool::add_uv2(const Vector2 &p_uv2) {
void SurfaceTool::add_bones(const Vector<int> &p_bones) {
ERR_FAIL_COND(!begun);
- ERR_FAIL_COND(p_bones.size() != 4);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_BONES));
format |= Mesh::ARRAY_FORMAT_BONES;
@@ -171,8 +217,6 @@ void SurfaceTool::add_bones(const Vector<int> &p_bones) {
void SurfaceTool::add_weights(const Vector<float> &p_weights) {
ERR_FAIL_COND(!begun);
-
- ERR_FAIL_COND(p_weights.size() != 4);
ERR_FAIL_COND(!first && !(format & Mesh::ARRAY_FORMAT_WEIGHTS));
format |= Mesh::ARRAY_FORMAT_WEIGHTS;
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index a3b110f0d8..c55cade813 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -62,6 +62,14 @@ private:
static _FORCE_INLINE_ uint32_t hash(const Vertex &p_vtx);
};
+ struct WeightSort {
+ int index;
+ float weight;
+ bool operator<(const WeightSort &p_right) const {
+ return weight < p_right.weight;
+ }
+ };
+
bool begun;
bool first;
Mesh::PrimitiveType primitive;
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 3ca2b56d08..a5eb950c36 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -34,6 +34,7 @@
#include "core/io/image_loader.h"
#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
+#include "mesh.h"
#include "scene/resources/bit_map.h"
Size2 Texture::get_size() const {
@@ -1133,6 +1134,138 @@ AtlasTexture::AtlasTexture() {
filter_clip = false;
}
+/////////////////////////////////////////
+
+int MeshTexture::get_width() const {
+ return size.width;
+}
+int MeshTexture::get_height() const {
+ return size.height;
+}
+RID MeshTexture::get_rid() const {
+ return RID();
+}
+
+bool MeshTexture::has_alpha() const {
+ return false;
+}
+
+void MeshTexture::set_flags(uint32_t p_flags) {
+}
+
+uint32_t MeshTexture::get_flags() const {
+ return 0;
+}
+
+void MeshTexture::set_mesh(const Ref<Mesh> &p_mesh) {
+ mesh = p_mesh;
+}
+Ref<Mesh> MeshTexture::get_mesh() const {
+ return mesh;
+}
+
+void MeshTexture::set_image_size(const Size2 &p_size) {
+ size = p_size;
+}
+
+Size2 MeshTexture::get_image_size() const {
+
+ return size;
+}
+
+void MeshTexture::set_base_texture(const Ref<Texture> &p_texture) {
+ base_texture = p_texture;
+}
+
+Ref<Texture> MeshTexture::get_base_texture() const {
+ return base_texture;
+}
+
+void MeshTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
+
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ xform.set_origin(p_pos);
+ if (p_transpose) {
+ SWAP(xform.elements[0][1], xform.elements[1][0]);
+ SWAP(xform.elements[0][0], xform.elements[1][1]);
+ }
+ RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
+}
+void MeshTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ Vector2 origin = p_rect.position;
+ if (p_rect.size.x < 0) {
+ origin.x += size.x;
+ }
+ if (p_rect.size.y < 0) {
+ origin.y += size.y;
+ }
+ xform.set_origin(origin);
+ xform.set_scale(p_rect.size / size);
+
+ if (p_transpose) {
+ SWAP(xform.elements[0][1], xform.elements[1][0]);
+ SWAP(xform.elements[0][0], xform.elements[1][1]);
+ }
+ RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
+}
+void MeshTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
+
+ if (mesh.is_null() || base_texture.is_null()) {
+ return;
+ }
+ Transform2D xform;
+ Vector2 origin = p_rect.position;
+ if (p_rect.size.x < 0) {
+ origin.x += size.x;
+ }
+ if (p_rect.size.y < 0) {
+ origin.y += size.y;
+ }
+ xform.set_origin(origin);
+ xform.set_scale(p_rect.size / size);
+
+ if (p_transpose) {
+ SWAP(xform.elements[0][1], xform.elements[1][0]);
+ SWAP(xform.elements[0][0], xform.elements[1][1]);
+ }
+ RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ VisualServer::get_singleton()->canvas_item_add_mesh(p_canvas_item, mesh->get_rid(), xform, p_modulate, base_texture->get_rid(), normal_rid);
+}
+bool MeshTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
+ r_rect = p_rect;
+ r_src_rect = p_src_rect;
+ return true;
+}
+
+bool MeshTexture::is_pixel_opaque(int p_x, int p_y) const {
+ return true;
+}
+
+void MeshTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshTexture::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &MeshTexture::get_mesh);
+ ClassDB::bind_method(D_METHOD("set_image_size", "size"), &MeshTexture::set_image_size);
+ ClassDB::bind_method(D_METHOD("get_image_size"), &MeshTexture::get_image_size);
+ ClassDB::bind_method(D_METHOD("set_base_texture", "texture"), &MeshTexture::set_base_texture);
+ ClassDB::bind_method(D_METHOD("get_base_texture"), &MeshTexture::get_base_texture);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "base_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_base_texture", "get_base_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "image_size", PROPERTY_HINT_RANGE, "0,16384,1"), "set_image_size", "get_image_size");
+}
+
+MeshTexture::MeshTexture() {
+}
+
//////////////////////////////////////////
int LargeTexture::get_width() const {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 281a33929c..58287b7593 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -293,6 +293,49 @@ public:
AtlasTexture();
};
+class Mesh;
+
+class MeshTexture : public Texture {
+
+ GDCLASS(MeshTexture, Texture);
+ RES_BASE_EXTENSION("meshtex");
+
+ Ref<Texture> base_texture;
+ Ref<Mesh> mesh;
+ Size2i size;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual int get_width() const;
+ virtual int get_height() const;
+ virtual RID get_rid() const;
+
+ virtual bool has_alpha() const;
+
+ virtual void set_flags(uint32_t p_flags);
+ virtual uint32_t get_flags() const;
+
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ void set_image_size(const Size2 &p_size);
+ Size2 get_image_size() const;
+
+ void set_base_texture(const Ref<Texture> &p_texture);
+ Ref<Texture> get_base_texture() const;
+
+ virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
+ virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
+ virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
+ virtual bool get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const;
+
+ bool is_pixel_opaque(int p_x, int p_y) const;
+
+ MeshTexture();
+};
+
class LargeTexture : public Texture {
GDCLASS(LargeTexture, Texture);
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index fdb6f2ce09..4229147ba2 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -782,7 +782,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
} else if (in_type == VisualShaderNode::PORT_TYPE_VECTOR && out_type == VisualShaderNode::PORT_TYPE_SCALAR) {
inputs[i] = "vec3(" + src_var + ")";
} else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_VECTOR) {
- inputs[i] = "all(" + src_var + ")";
+ inputs[i] = "all(bvec3(" + src_var + "))";
} else if (in_type == VisualShaderNode::PORT_TYPE_BOOLEAN && out_type == VisualShaderNode::PORT_TYPE_SCALAR) {
inputs[i] = src_var + ">0.0?true:false";
} else if (in_type == VisualShaderNode::PORT_TYPE_SCALAR && out_type == VisualShaderNode::PORT_TYPE_BOOLEAN) {
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index dac999bf1d..d02902572c 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -2948,3 +2948,140 @@ String VisualShaderNodeCubeMapUniform::generate_code(Shader::Mode p_mode, Visual
VisualShaderNodeCubeMapUniform::VisualShaderNodeCubeMapUniform() {
}
+
+////////////// If
+
+String VisualShaderNodeIf::get_caption() const {
+ return "If";
+}
+
+int VisualShaderNodeIf::get_input_port_count() const {
+ return 6;
+}
+
+VisualShaderNodeIf::PortType VisualShaderNodeIf::get_input_port_type(int p_port) const {
+ if (p_port == 0 || p_port == 1 || p_port == 2) {
+ return PORT_TYPE_SCALAR;
+ }
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeIf::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "a";
+ case 1:
+ return "b";
+ case 2:
+ return "tolerance";
+ case 3:
+ return "a == b";
+ case 4:
+ return "a > b";
+ case 5:
+ return "a < b";
+ default:
+ return "";
+ }
+}
+
+int VisualShaderNodeIf::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeIf::PortType VisualShaderNodeIf::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeIf::get_output_port_name(int p_port) const {
+ return "result";
+}
+
+String VisualShaderNodeIf::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 {
+
+ String code;
+ code += "\tif(abs(" + p_input_vars[0] + "-" + p_input_vars[1] + ")<" + p_input_vars[2] + ")\n"; // abs(a - b) < tolerance eg. a == b
+ code += "\t{\n";
+ code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[3] + ";\n";
+ code += "\t}\n";
+ code += "\telse if(" + p_input_vars[0] + "<" + p_input_vars[1] + ")\n"; // a < b
+ code += "\t{\n";
+ code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[5] + ";\n";
+ code += "\t}\n";
+ code += "\telse\n"; // a > b (or a >= b if abs(a - b) < tolerance is false)
+ code += "\t{\n";
+ code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[4] + ";\n";
+ code += "\t}\n";
+ return code;
+}
+
+VisualShaderNodeIf::VisualShaderNodeIf() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, CMP_EPSILON);
+ set_input_port_default_value(3, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(4, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(5, Vector3(0.0, 0.0, 0.0));
+}
+
+////////////// Switch
+
+String VisualShaderNodeSwitch::get_caption() const {
+ return "Switch";
+}
+
+int VisualShaderNodeSwitch::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int p_port) const {
+ if (p_port == 0) {
+ return PORT_TYPE_BOOLEAN;
+ }
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeSwitch::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "value";
+ case 1:
+ return "true";
+ case 2:
+ return "false";
+ default:
+ return "";
+ }
+}
+
+int VisualShaderNodeSwitch::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR;
+}
+
+String VisualShaderNodeSwitch::get_output_port_name(int p_port) const {
+ return "result";
+}
+
+String VisualShaderNodeSwitch::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 {
+
+ String code;
+ code += "\tif(" + p_input_vars[0] + ")\n";
+ code += "\t{\n";
+ code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[1] + ";\n";
+ code += "\t}\n";
+ code += "\telse\n";
+ code += "\t{\n";
+ code += "\t\t" + p_output_vars[0] + "=" + p_input_vars[2] + ";\n";
+ code += "\t}\n";
+ return code;
+}
+
+VisualShaderNodeSwitch::VisualShaderNodeSwitch() {
+ set_input_port_default_value(0, false);
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0));
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 28ead64fe2..90c479bd48 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -1440,4 +1440,48 @@ public:
VisualShaderNodeCubeMapUniform();
};
+///////////////////////////////////////
+/// IF
+///////////////////////////////////////
+
+class VisualShaderNodeIf : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeIf, VisualShaderNode)
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String 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 = false) const;
+
+ VisualShaderNodeIf();
+};
+
+///////////////////////////////////////
+/// SWITCH
+///////////////////////////////////////
+
+class VisualShaderNodeSwitch : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeSwitch, VisualShaderNode)
+public:
+ virtual String get_caption() const;
+
+ virtual int get_input_port_count() const;
+ virtual PortType get_input_port_type(int p_port) const;
+ virtual String get_input_port_name(int p_port) const;
+
+ virtual int get_output_port_count() const;
+ virtual PortType get_output_port_type(int p_port) const;
+ virtual String get_output_port_name(int p_port) const;
+
+ virtual String 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 = false) const;
+
+ VisualShaderNodeSwitch();
+};
+
#endif // VISUAL_SHADER_NODES_H