summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/animation.cpp130
-rw-r--r--scene/resources/animation.h2
-rw-r--r--scene/resources/bit_map.cpp40
-rw-r--r--scene/resources/bit_map.h4
-rw-r--r--scene/resources/curve.cpp9
-rw-r--r--scene/resources/default_theme/default_theme.cpp14
-rw-r--r--scene/resources/default_theme/space.pngbin0 -> 122 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h4
-rw-r--r--scene/resources/environment.cpp6
-rw-r--r--scene/resources/font.cpp8
-rw-r--r--scene/resources/height_map_shape.cpp49
-rw-r--r--scene/resources/material.cpp16
-rw-r--r--scene/resources/material.h1
-rw-r--r--scene/resources/mesh.cpp2
-rw-r--r--scene/resources/mesh.h5
-rw-r--r--scene/resources/packed_scene.cpp4
-rw-r--r--scene/resources/particles_material.cpp1
-rw-r--r--scene/resources/primitive_meshes.cpp6
-rw-r--r--scene/resources/primitive_meshes.h1
-rw-r--r--scene/resources/resource_format_text.cpp17
-rw-r--r--scene/resources/resource_format_text.h3
-rw-r--r--scene/resources/sky.cpp2
-rw-r--r--scene/resources/surface_tool.cpp24
-rw-r--r--scene/resources/surface_tool.h1
-rw-r--r--scene/resources/texture.cpp19
-rw-r--r--scene/resources/tile_set.cpp32
-rw-r--r--scene/resources/tile_set.h1
-rw-r--r--scene/resources/visual_shader.cpp664
-rw-r--r--scene/resources/visual_shader.h93
-rw-r--r--scene/resources/visual_shader_nodes.cpp79
-rw-r--r--scene/resources/visual_shader_nodes.h28
31 files changed, 1146 insertions, 119 deletions
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 9c79b2ba3b..e4da659b0d 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -93,7 +93,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]);
PoolVector<float> values = p_value;
int vcount = values.size();
- ERR_FAIL_COND_V(vcount % 12, false); // shuld be multiple of 11
+ ERR_FAIL_COND_V(vcount % 12, false); // should be multiple of 11
PoolVector<float>::Read r = values.read();
@@ -819,15 +819,17 @@ int Animation::_insert(float p_time, T &p_keys, const V &p_value) {
while (true) {
- if (idx == 0 || p_keys[idx - 1].time < p_time) {
- //condition for insertion.
- p_keys.insert(idx, p_value);
- return idx;
- } else if (p_keys[idx - 1].time == p_time) {
+ // Condition for replacement.
+ if (idx > 0 && Math::is_equal_approx(p_keys[idx - 1].time, p_time)) {
- // condition for replacing.
p_keys.write[idx - 1] = p_value;
return idx - 1;
+
+ // Condition for insert.
+ } else if (idx == 0 || p_keys[idx - 1].time < p_time) {
+
+ p_keys.insert(idx, p_value);
+ return idx;
}
idx--;
@@ -1296,6 +1298,78 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const {
ERR_FAIL_V(-1);
}
+void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) {
+
+ ERR_FAIL_INDEX(p_track, tracks.size());
+ Track *t = tracks[p_track];
+
+ switch (t->type) {
+
+ case TYPE_TRANSFORM: {
+
+ TransformTrack *tt = static_cast<TransformTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, tt->transforms.size());
+ TKey<TransformKey> key = tt->transforms[p_key_idx];
+ key.time = p_time;
+ tt->transforms.remove(p_key_idx);
+ _insert(p_time, tt->transforms, key);
+ return;
+ }
+ case TYPE_VALUE: {
+
+ ValueTrack *vt = static_cast<ValueTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, vt->values.size());
+ TKey<Variant> key = vt->values[p_key_idx];
+ key.time = p_time;
+ vt->values.remove(p_key_idx);
+ _insert(p_time, vt->values, key);
+ return;
+ }
+ case TYPE_METHOD: {
+
+ MethodTrack *mt = static_cast<MethodTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, mt->methods.size());
+ MethodKey key = mt->methods[p_key_idx];
+ key.time = p_time;
+ mt->methods.remove(p_key_idx);
+ _insert(p_time, mt->methods, key);
+ return;
+ }
+ case TYPE_BEZIER: {
+
+ BezierTrack *bt = static_cast<BezierTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, bt->values.size());
+ TKey<BezierKey> key = bt->values[p_key_idx];
+ key.time = p_time;
+ bt->values.remove(p_key_idx);
+ _insert(p_time, bt->values, key);
+ return;
+ }
+ case TYPE_AUDIO: {
+
+ AudioTrack *at = static_cast<AudioTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, at->values.size());
+ TKey<AudioKey> key = at->values[p_key_idx];
+ key.time = p_time;
+ at->values.remove(p_key_idx);
+ _insert(p_time, at->values, key);
+ return;
+ }
+ case TYPE_ANIMATION: {
+
+ AnimationTrack *at = static_cast<AnimationTrack *>(t);
+ ERR_FAIL_INDEX(p_key_idx, at->values.size());
+ TKey<StringName> key = at->values[p_key_idx];
+ key.time = p_time;
+ at->values.remove(p_key_idx);
+ _insert(p_time, at->values, key);
+ return;
+ }
+ }
+
+ ERR_FAIL();
+}
+
float Animation::track_get_key_transition(int p_track, int p_key_idx) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
@@ -2559,17 +2633,6 @@ bool Animation::has_loop() const {
return loop;
}
-void Animation::track_move_up(int p_track) {
-
- if (p_track >= 0 && p_track < (tracks.size() - 1)) {
-
- SWAP(tracks.write[p_track], tracks.write[p_track + 1]);
- }
-
- emit_changed();
- emit_signal(SceneStringNames::get_singleton()->tracks_changed);
-}
-
void Animation::track_set_imported(int p_track, bool p_imported) {
ERR_FAIL_INDEX(p_track, tracks.size());
@@ -2595,12 +2658,40 @@ bool Animation::track_is_enabled(int p_track) const {
return tracks[p_track]->enabled;
}
+void Animation::track_move_up(int p_track) {
+
+ if (p_track >= 0 && p_track < (tracks.size() - 1)) {
+
+ SWAP(tracks.write[p_track], tracks.write[p_track + 1]);
+ }
+
+ emit_changed();
+ emit_signal(SceneStringNames::get_singleton()->tracks_changed);
+}
+
void Animation::track_move_down(int p_track) {
if (p_track > 0 && p_track < tracks.size()) {
SWAP(tracks.write[p_track], tracks.write[p_track - 1]);
}
+
+ emit_changed();
+ emit_signal(SceneStringNames::get_singleton()->tracks_changed);
+}
+
+void Animation::track_move_to(int p_track, int p_to_index) {
+
+ ERR_FAIL_INDEX(p_track, tracks.size());
+ ERR_FAIL_INDEX(p_to_index, tracks.size() + 1);
+ if (p_track == p_to_index || p_track == p_to_index - 1)
+ return;
+
+ Track *track = tracks.get(p_track);
+ tracks.remove(p_track);
+ // Take into account that the position of the tracks that come after the one removed will change.
+ tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track);
+
emit_changed();
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
@@ -2612,6 +2703,7 @@ void Animation::track_swap(int p_track, int p_with_track) {
if (p_track == p_with_track)
return;
SWAP(tracks.write[p_track], tracks.write[p_with_track]);
+
emit_changed();
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
@@ -2656,6 +2748,7 @@ void Animation::_bind_methods() {
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_set_imported", "idx", "imported"), &Animation::track_set_imported);
@@ -2670,6 +2763,7 @@ void Animation::_bind_methods() {
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("track_get_key_count", "idx"), &Animation::track_get_key_count);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 3d38a8902f..59f2ae24c7 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -293,6 +293,7 @@ public:
void track_move_up(int p_track);
void track_move_down(int p_track);
+ void track_move_to(int p_track, int p_to_index);
void track_swap(int p_track, int p_with_track);
void track_set_imported(int p_track, bool p_imported);
@@ -304,6 +305,7 @@ public:
void track_insert_key(int p_track, float p_time, const Variant &p_key, float p_transition = 1);
void track_set_key_transition(int p_track, int p_key_idx, float p_transition);
void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
+ void track_set_key_time(int p_track, int p_key_idx, float p_time);
int track_find_key(int p_track, float p_time, bool p_exact = false) const;
void track_remove_key(int p_track, int p_idx);
void track_remove_key_at_position(int p_track, float p_pos);
diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp
index a9d85be0dc..e4a64a1de1 100644
--- a/scene/resources/bit_map.cpp
+++ b/scene/resources/bit_map.cpp
@@ -595,16 +595,16 @@ 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) {
+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)));
+ 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)));
}
}
@@ -617,11 +617,11 @@ Ref<Image> BitMap::convert_to_image() const {
Ref<Image> image;
image.instance();
- image->create(width,height,false,Image::FORMAT_L8);
+ 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));
+ 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));
}
}
@@ -629,30 +629,28 @@ Ref<Image> BitMap::convert_to_image() const {
return image;
}
-void BitMap::blit(const Vector2& p_pos,const Ref<BitMap>& p_bitmap) {
+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)
+ 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)
+ if (py < 0 || py >= height)
continue;
- if (p_bitmap->get_bit(Vector2(i,j))) {
- set_bit(Vector2(x,y),true);
+ 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 6e1171b8a9..daf24affb1 100644
--- a/scene/resources/bit_map.h
+++ b/scene/resources/bit_map.h
@@ -64,11 +64,11 @@ public:
int get_true_bit_count() const;
Size2 get_size() const;
- void resize(const Size2& p_new_size);
+ 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);
+ 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;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index ece8ad4bb0..950518aa6e 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -782,7 +782,8 @@ Vector2 Curve2D::interpolate_baked(float p_offset, bool p_cubic) const {
if (idx >= bpc - 1) {
return r[bpc - 1];
} else if (idx == bpc - 2) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ if (frac > 0)
+ frac /= Math::fmod(baked_max_ofs, bake_interval);
} else {
frac /= bake_interval;
}
@@ -1352,7 +1353,8 @@ Vector3 Curve3D::interpolate_baked(float p_offset, bool p_cubic) const {
if (idx >= bpc - 1) {
return r[bpc - 1];
} else if (idx == bpc - 2) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ if (frac > 0)
+ frac /= Math::fmod(baked_max_ofs, bake_interval);
} else {
frac /= bake_interval;
}
@@ -1396,7 +1398,8 @@ float Curve3D::interpolate_baked_tilt(float p_offset) const {
if (idx >= bpc - 1) {
return r[bpc - 1];
} else if (idx == bpc - 2) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ if (frac > 0)
+ frac /= Math::fmod(baked_max_ofs, bake_interval);
} else {
frac /= bake_interval;
}
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index b3bd3f47e6..e8359e3dfe 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -425,6 +425,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
+ theme->set_icon("space", "TextEdit", make_icon(space_png));
theme->set_icon("folded", "TextEdit", make_icon(arrow_right_png));
theme->set_icon("fold", "TextEdit", make_icon(arrow_down_png));
@@ -440,6 +441,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color_selected", "TextEdit", Color(0, 0, 0));
theme->set_color("selection_color", "TextEdit", font_color_selection);
theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 0.4));
+ theme->set_color("bookmark_color", "TextEdit", Color(0.08, 0.49, 0.98));
theme->set_color("breakpoint_color", "TextEdit", Color(0.8, 0.8, 0.4, 0.2));
theme->set_color("executing_line_color", "TextEdit", Color(0.2, 0.8, 0.2, 0.4));
theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8));
@@ -580,14 +582,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// GraphNode
- Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 5);
+ Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 6);
Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png, 4, 4, 4, 4, 6, 4, 4, 4);
Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png, 4, 4, 4, 4, 6, 4, 4, 4);
- Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 5);
+ Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 6);
//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
diff --git a/scene/resources/default_theme/space.png b/scene/resources/default_theme/space.png
new file mode 100644
index 0000000000..7e458a6c45
--- /dev/null
+++ b/scene/resources/default_theme/space.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index a09b811b37..87b8afd6a3 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -358,6 +358,10 @@ static const unsigned char selection_oof_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x2, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xfd, 0xfb, 0xff, 0xaf, 0xdf, 0x90, 0xa5, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0xa, 0x1a, 0x26, 0x29, 0x2a, 0x48, 0x65, 0x6d, 0x6e, 0x66, 0x3, 0x20, 0x25, 0x16, 0xc, 0x1f, 0x74, 0xbf, 0x74, 0x0, 0x0, 0x0, 0x37, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x64, 0x54, 0x52, 0x64, 0x60, 0x60, 0x78, 0x77, 0x8f, 0x51, 0x34, 0x8, 0xcc, 0xb8, 0xcd, 0xa8, 0xd9, 0x4, 0x66, 0xdc, 0x60, 0x74, 0x2f, 0x33, 0x4, 0x32, 0xde, 0xce, 0x64, 0xf4, 0x68, 0x53, 0x0, 0x32, 0xfe, 0xcd, 0xa0, 0x90, 0x1, 0x37, 0x10, 0x6e, 0x5, 0xdc, 0x52, 0xb8, 0x33, 0x0, 0xcc, 0x7, 0x26, 0xff, 0x1f, 0x38, 0x23, 0x97, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
+static const unsigned char space_png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc4, 0xf, 0xbe, 0x8b, 0x0, 0x0, 0x0, 0x6, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xa0, 0xbd, 0xa7, 0x93, 0x0, 0x0, 0x0, 0x2f, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x63, 0x60, 0xa0, 0x2a, 0xf8, 0xff, 0xff, 0xbf, 0xe0, 0xff, 0xff, 0xff, 0x5, 0x91, 0xc5, 0x58, 0x90, 0x24, 0x85, 0x18, 0x18, 0x18, 0x14, 0xa0, 0x6c, 0x6, 0x46, 0x46, 0xc6, 0xf7, 0xc, 0xc, 0xc, 0xc, 0x4c, 0x14, 0x5b, 0x41, 0x39, 0x0, 0x0, 0x71, 0x1a, 0x13, 0x5d, 0x87, 0xfe, 0x9e, 0x7d, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
+};
+
static const unsigned char spinbox_updown_png[] = {
0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x59, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x20, 0x11, 0xdc, 0x4f, 0x7f, 0x98, 0x86, 0x47, 0xfa, 0x81, 0xe5, 0x83, 0x1f, 0xf, 0x7e, 0x3d, 0xb2, 0xc5, 0xa5, 0x5b, 0xe2, 0xc1, 0x93, 0x7, 0xff, 0x81, 0xf0, 0xf9, 0x63, 0x69, 0x2c, 0xd2, 0x67, 0x58, 0xef, 0x1f, 0x2, 0x4a, 0x42, 0xe0, 0xf1, 0xdb, 0xec, 0x98, 0xfa, 0x67, 0x2, 0x25, 0xe0, 0xf0, 0xe1, 0x2, 0x86, 0x41, 0x7, 0x30, 0x1d, 0x39, 0x3, 0xbf, 0x37, 0x8f, 0xdd, 0x66, 0x27, 0x29, 0xa0, 0x10, 0x4a, 0x2c, 0xa0, 0x41, 0x8d, 0x1b, 0x3c, 0x4c, 0x3, 0x46, 0x16, 0x69, 0x0, 0x0, 0x87, 0x2a, 0x58, 0xb5, 0x18, 0xe9, 0x80, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 17609ed505..52dfffda5b 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1294,8 +1294,8 @@ void Environment::_bind_methods() {
Environment::Environment() :
bg_mode(BG_CLEAR_COLOR),
tone_mapper(TONE_MAPPER_LINEAR),
- ssao_blur(SSAO_BLUR_DISABLED),
- ssao_quality(SSAO_QUALITY_LOW),
+ ssao_blur(SSAO_BLUR_3x3),
+ ssao_quality(SSAO_QUALITY_MEDIUM),
glow_blend_mode(GLOW_BLEND_MODE_ADDITIVE),
dof_blur_far_quality(DOF_BLUR_QUALITY_LOW),
dof_blur_near_quality(DOF_BLUR_QUALITY_LOW) {
@@ -1346,7 +1346,7 @@ Environment::Environment() :
ssao_ao_channel_affect = 0.0;
ssao_blur = SSAO_BLUR_3x3;
set_ssao_edge_sharpness(4);
- set_ssao_quality(SSAO_QUALITY_LOW);
+ set_ssao_quality(SSAO_QUALITY_MEDIUM);
glow_enabled = false;
glow_levels = (1 << 2) | (1 << 4);
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 128db3f109..627397f0ab 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -530,7 +530,13 @@ Size2 Font::get_wordwrap_string_size(const String &p_string, float p_width) cons
void BitmapFont::set_fallback(const Ref<BitmapFont> &p_fallback) {
- ERR_FAIL_COND(p_fallback == this);
+ for (Ref<BitmapFont> fallback_child = p_fallback; fallback_child != NULL; fallback_child = fallback_child->get_fallback()) {
+ if (fallback_child == this) {
+ ERR_EXPLAIN("Can't set as fallback one of its parents to prevent crashes due to recursive loop.");
+ ERR_FAIL_COND(fallback_child == this);
+ }
+ }
+
fallback = p_fallback;
}
diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
index 32e9c527ef..f763700d52 100644
--- a/scene/resources/height_map_shape.cpp
+++ b/scene/resources/height_map_shape.cpp
@@ -34,35 +34,43 @@
Vector<Vector3> HeightMapShape::_gen_debug_mesh_lines() {
Vector<Vector3> points;
- // This will be slow for large maps...
- // also we'll have to figure out how well bullet centers this shape...
+ if ((map_width != 0) && (map_depth != 0)) {
- Vector2 size(map_width - 1, map_depth - 1);
- Vector2 start = size * -0.5;
- int offset = 0;
+ // This will be slow for large maps...
+ // also we'll have to figure out how well bullet centers this shape...
- PoolRealArray::Read r = map_data.read();
+ Vector2 size(map_width - 1, map_depth - 1);
+ Vector2 start = size * -0.5;
- for (int d = 0; d < map_depth; d++) {
- Vector3 height(start.x, 0.0, start.y);
+ PoolRealArray::Read r = map_data.read();
- for (int w = 0; w < map_width; w++) {
- height.y = r[offset++];
+ // reserve some memory for our points..
+ points.resize(((map_width - 1) * map_depth * 2) + (map_width * (map_depth - 1) * 2));
- if (w != map_width - 1) {
- points.push_back(height);
- points.push_back(Vector3(height.x + 1.0, r[offset], height.z));
- }
+ // now set our points
+ int r_offset = 0;
+ int w_offset = 0;
+ for (int d = 0; d < map_depth; d++) {
+ Vector3 height(start.x, 0.0, start.y);
+
+ for (int w = 0; w < map_width; w++) {
+ height.y = r[r_offset++];
+
+ if (w != map_width - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x + 1.0, r[r_offset], height.z);
+ }
- if (d != map_depth - 1) {
- points.push_back(height);
- points.push_back(Vector3(height.x, r[offset + map_width - 1], height.z + 1.0));
+ if (d != map_depth - 1) {
+ points.write[w_offset++] = height;
+ points.write[w_offset++] = Vector3(height.x, r[r_offset + map_width - 1], height.z + 1.0);
+ }
+
+ height.x += 1.0;
}
- height.x += 1.0;
+ start.y += 1.0;
}
-
- start.y += 1.0;
}
return points;
@@ -77,6 +85,7 @@ void HeightMapShape::_update_shape() {
d["min_height"] = min_height;
d["max_height"] = max_height;
PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
+ Shape::_update_shape();
}
void HeightMapShape::set_map_width(int p_new) {
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 766c7bbd9f..ada0ac07a3 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -38,7 +38,12 @@
void Material::set_next_pass(const Ref<Material> &p_pass) {
- ERR_FAIL_COND(p_pass == this);
+ for (Ref<Material> pass_child = p_pass; pass_child != NULL; pass_child = pass_child->get_next_pass()) {
+ if (pass_child == this) {
+ ERR_EXPLAIN("Can't set as next_pass one of its parents to prevent crashes due to recursive loop.");
+ ERR_FAIL_COND(pass_child == this);
+ }
+ }
if (next_pass == p_pass)
return;
@@ -468,6 +473,9 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_ENSURE_CORRECT_NORMALS]) {
code += ",ensure_correct_normals";
}
+ if (flags[FLAG_USE_SHADOW_TO_OPACITY]) {
+ code += ",shadow_to_opacity";
+ }
code += ";\n";
code += "uniform vec4 albedo : hint_color;\n";
@@ -849,7 +857,7 @@ void SpatialMaterial::_update_shader() {
code += "\tALBEDO *= 1.0 - ref_amount;\n";
code += "\tALPHA = 1.0;\n";
- } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
+ } else if (features[FEATURE_TRANSPARENT] || flags[FLAG_USE_ALPHA_SCISSOR] || flags[FLAG_USE_SHADOW_TO_OPACITY] || (distance_fade == DISTANCE_FADE_PIXEL_ALPHA) || proximity_fade_enabled) {
code += "\tALPHA = albedo.a * albedo_tex.a;\n";
}
@@ -1349,7 +1357,7 @@ void SpatialMaterial::set_flag(Flags p_flag, bool p_enabled) {
return;
flags[p_flag] = p_enabled;
- if (p_flag == FLAG_USE_ALPHA_SCISSOR || p_flag == FLAG_UNSHADED) {
+ if ((p_flag == FLAG_USE_ALPHA_SCISSOR) || (p_flag == FLAG_UNSHADED) || (p_flag == FLAG_USE_SHADOW_TO_OPACITY)) {
_change_notify();
}
_queue_shader_change();
@@ -2060,6 +2068,7 @@ void SpatialMaterial::_bind_methods() {
ADD_GROUP("Flags", "flags_");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_transparent"), "set_feature", "get_feature", FEATURE_TRANSPARENT);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_use_shadow_to_opacity"), "set_flag", "get_flag", FLAG_USE_SHADOW_TO_OPACITY);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_unshaded"), "set_flag", "get_flag", FLAG_UNSHADED);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_vertex_lighting"), "set_flag", "get_flag", FLAG_USE_VERTEX_LIGHTING);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_no_depth_test"), "set_flag", "get_flag", FLAG_DISABLE_DEPTH_TEST);
@@ -2266,6 +2275,7 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_DONT_RECEIVE_SHADOWS);
BIND_ENUM_CONSTANT(FLAG_DISABLE_AMBIENT_LIGHT);
BIND_ENUM_CONSTANT(FLAG_ENSURE_CORRECT_NORMALS);
+ BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 1f7fc267af..29b45f769b 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -196,6 +196,7 @@ public:
FLAG_DONT_RECEIVE_SHADOWS,
FLAG_ENSURE_CORRECT_NORMALS,
FLAG_DISABLE_AMBIENT_LIGHT,
+ FLAG_USE_SHADOW_TO_OPACITY,
FLAG_MAX
};
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 67639858ce..6443b44bb6 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -489,6 +489,7 @@ void Mesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count);
ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays);
ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays);
+ ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &Mesh::surface_set_material);
ClassDB::bind_method(D_METHOD("surface_get_material", "surf_idx"), &Mesh::surface_get_material);
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
@@ -1305,7 +1306,6 @@ void ArrayMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("surface_get_array_index_len", "surf_idx"), &ArrayMesh::surface_get_array_index_len);
ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format);
ClassDB::bind_method(D_METHOD("surface_get_primitive_type", "surf_idx"), &ArrayMesh::surface_get_primitive_type);
- ClassDB::bind_method(D_METHOD("surface_set_material", "surf_idx", "material"), &ArrayMesh::surface_set_material);
ClassDB::bind_method(D_METHOD("surface_find_by_name", "name"), &ArrayMesh::surface_find_by_name);
ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name);
ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 1457d283bd..b38791b9a6 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -128,6 +128,7 @@ public:
virtual Array surface_get_blend_shape_arrays(int p_surface) const = 0;
virtual uint32_t surface_get_format(int p_idx) const = 0;
virtual PrimitiveType surface_get_primitive_type(int p_idx) const = 0;
+ virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) = 0;
virtual Ref<Material> surface_get_material(int p_idx) const = 0;
virtual int get_blend_shape_count() const = 0;
virtual StringName get_blend_shape_name(int p_index) const = 0;
@@ -215,8 +216,8 @@ public:
PrimitiveType surface_get_primitive_type(int p_idx) const;
bool surface_is_alpha_sorting_enabled(int p_idx) const;
- void surface_set_material(int p_idx, const Ref<Material> &p_material);
- Ref<Material> surface_get_material(int p_idx) const;
+ virtual void surface_set_material(int p_idx, const Ref<Material> &p_material);
+ virtual Ref<Material> surface_get_material(int p_idx) const;
int surface_find_by_name(const String &p_name) const;
void surface_set_name(int p_idx, const String &p_name);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 2c6f30f429..99286668ce 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -92,8 +92,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (i > 0) {
- ERR_EXPLAIN(vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]))
- ERR_FAIL_COND_V(n.parent == -1, NULL)
+ ERR_EXPLAIN(vformat("Invalid scene: node %s does not specify its parent node.", snames[n.name]));
+ ERR_FAIL_COND_V(n.parent == -1, NULL);
NODE_FROM_ID(nparent, n.parent);
#ifdef DEBUG_ENABLED
if (!nparent && (n.parent & FLAG_ID_IS_PATH)) {
diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp
index ef67e6ea80..758475b75e 100644
--- a/scene/resources/particles_material.cpp
+++ b/scene/resources/particles_material.cpp
@@ -1186,6 +1186,7 @@ void ParticlesMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_ALIGN_Y_TO_VELOCITY);
BIND_ENUM_CONSTANT(FLAG_ROTATE_Y);
+ BIND_ENUM_CONSTANT(FLAG_DISABLE_Z);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(EMISSION_SHAPE_POINT);
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index db58fe7823..04d13c8869 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -157,6 +157,12 @@ Mesh::PrimitiveType PrimitiveMesh::surface_get_primitive_type(int p_idx) const {
return primitive_type;
}
+void PrimitiveMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) {
+ ERR_FAIL_INDEX(p_idx, 1);
+
+ set_material(p_material);
+}
+
Ref<Material> PrimitiveMesh::surface_get_material(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, 1, NULL);
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 88a26801b7..0045a48736 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -72,6 +72,7 @@ public:
virtual Array surface_get_blend_shape_arrays(int p_surface) const;
virtual uint32_t surface_get_format(int p_idx) const;
virtual Mesh::PrimitiveType surface_get_primitive_type(int p_idx) const;
+ virtual void surface_set_material(int p_idx, const Ref<Material> &p_material);
virtual Ref<Material> surface_get_material(int p_idx) const;
virtual int get_blend_shape_count() const;
virtual StringName get_blend_shape_name(int p_index) const;
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index e9f90fc85f..0921c0dae9 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -447,9 +447,8 @@ Error ResourceInteractiveLoaderText::poll() {
resource_cache.push_back(res);
#ifdef TOOLS_ENABLED
//remember ID for saving
- res->set_id_for_path(local_path,index);
+ res->set_id_for_path(local_path, index);
#endif
-
}
ExtResource er;
@@ -1545,9 +1544,6 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
{
-
-
-
}
#ifdef TOOLS_ENABLED
@@ -1569,7 +1565,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
}
int attempt = 1; //start from one, more readable format
- while(cached_ids_found.has(attempt)) {
+ while (cached_ids_found.has(attempt)) {
attempt++;
}
@@ -1577,7 +1573,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
E->get() = attempt;
//update also in resource
Ref<Resource> res = E->key();
- res->set_id_for_path(local_path,attempt);
+ res->set_id_for_path(local_path, attempt);
}
#else
//make sure to start from one, as it makes format more readable
@@ -1598,7 +1594,6 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
sorted_er.sort();
-
for (int i = 0; i < sorted_er.size(); i++) {
String p = sorted_er[i].resource->get_path();
@@ -1717,15 +1712,15 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
Vector<StringName> groups = state->get_node_groups(i);
String header = "[node";
- header += " name=\"" + String(name) + "\"";
+ header += " name=\"" + String(name).c_escape() + "\"";
if (type != StringName()) {
header += " type=\"" + String(type) + "\"";
}
if (path != NodePath()) {
- header += " parent=\"" + String(path.simplified()) + "\"";
+ header += " parent=\"" + String(path.simplified()).c_escape() + "\"";
}
if (owner != NodePath() && owner != NodePath(".")) {
- header += " owner=\"" + String(owner.simplified()) + "\"";
+ header += " owner=\"" + String(owner.simplified()).c_escape() + "\"";
}
if (index >= 0) {
header += " index=\"" + itos(index) + "\"";
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index ab6f94986c..06c841229b 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -172,10 +172,9 @@ class ResourceFormatSaverTextInstance {
struct ResourceSort {
RES resource;
int index;
- bool operator<(const ResourceSort& p_right) const {
+ bool operator<(const ResourceSort &p_right) const {
return index < p_right.index;
}
-
};
void _find_resources(const Variant &p_variant, bool p_main = false);
diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp
index 48945d4e63..292fdcdbd2 100644
--- a/scene/resources/sky.cpp
+++ b/scene/resources/sky.cpp
@@ -62,7 +62,7 @@ void Sky::_bind_methods() {
}
Sky::Sky() {
- radiance_size = RADIANCE_SIZE_512;
+ radiance_size = RADIANCE_SIZE_128;
}
/////////////////////////////////////////
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 3ba43006a3..496b1b2bdc 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -115,7 +115,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) {
//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
+ //less than required, fill
for (int i = vtx.weights.size(); i < expected_vertices; i++) {
vtx.weights.push_back(0);
vtx.bones.push_back(0);
@@ -769,6 +769,26 @@ void SurfaceTool::create_from(const Ref<Mesh> &p_existing, int p_surface) {
material = p_existing->surface_get_material(p_surface);
}
+void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name) {
+ clear();
+ primitive = p_existing->surface_get_primitive_type(p_surface);
+ Array arr = p_existing->surface_get_blend_shape_arrays(p_surface);
+ Array blend_shape_names;
+ int32_t shape_idx = -1;
+ for (int32_t i = 0; i < p_existing->get_blend_shape_count(); i++) {
+ String name = p_existing->get_blend_shape_name(i);
+ if (name == p_blend_shape_name) {
+ shape_idx = i;
+ break;
+ }
+ }
+ ERR_FAIL_COND(shape_idx == -1);
+ ERR_FAIL_COND(shape_idx >= arr.size());
+ Array mesh = arr[shape_idx];
+ ERR_FAIL_COND(mesh.size() != VS::ARRAY_MAX);
+ _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format);
+}
+
void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) {
if (vertex_array.size() == 0) {
@@ -1071,8 +1091,10 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear);
ClassDB::bind_method(D_METHOD("create_from", "existing", "surface"), &SurfaceTool::create_from);
+ ClassDB::bind_method(D_METHOD("create_from_blend_shape", "existing", "surface", "blend_shape"), &SurfaceTool::create_from_blend_shape);
ClassDB::bind_method(D_METHOD("append_from", "existing", "surface", "transform"), &SurfaceTool::append_from);
ClassDB::bind_method(D_METHOD("commit", "existing", "flags"), &SurfaceTool::commit, DEFVAL(Variant()), DEFVAL(Mesh::ARRAY_COMPRESS_DEFAULT));
+ ClassDB::bind_method(D_METHOD("commit_to_arrays"), &SurfaceTool::commit_to_arrays);
}
SurfaceTool::SurfaceTool() {
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index c55cade813..c4c71dca13 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -136,6 +136,7 @@ public:
static Vector<Vertex> create_vertex_array_from_triangle_arrays(const Array &p_arrays);
Array commit_to_arrays();
void create_from(const Ref<Mesh> &p_existing, int p_surface);
+ void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String p_blend_shape_name);
void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform);
Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = Mesh::ARRAY_COMPRESS_DEFAULT);
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index a5eb950c36..503949fd60 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -111,10 +111,12 @@ void ImageTexture::reload_from_file() {
Ref<Image> img;
img.instance();
- Error err = ImageLoader::load_image(path, img);
- ERR_FAIL_COND(err != OK);
-
- create_from_image(img, flags);
+ if (ImageLoader::load_image(path, img) == OK) {
+ create_from_image(img, flags);
+ } else {
+ Resource::reload_from_file();
+ _change_notify();
+ }
}
bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
@@ -230,7 +232,7 @@ Image::Format ImageTexture::get_format() const {
#ifndef DISABLE_DEPRECATED
Error ImageTexture::load(const String &p_path) {
- WARN_DEPRECATED
+ WARN_DEPRECATED;
Ref<Image> img;
img.instance();
Error err = img->load(p_path);
@@ -638,7 +640,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
bool mipmaps = df & FORMAT_BIT_HAS_MIPMAPS;
if (!mipmaps) {
- int size = Image::get_image_data_size(tw, th, format, 0);
+ int size = Image::get_image_data_size(tw, th, format, false);
PoolVector<uint8_t> img_data;
img_data.resize(size);
@@ -660,7 +662,6 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
int mipmaps2 = Image::get_image_required_mipmaps(tw, th, format);
int total_size = Image::get_image_data_size(tw, th, format, true);
int idx = 0;
- int ofs = 0;
while (mipmaps2 > 1 && p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) {
@@ -670,9 +671,7 @@ Error StreamTexture::_load_data(const String &p_path, int &tw, int &th, int &tw_
idx++;
}
- if (idx > 0) {
- ofs = Image::get_image_data_size(tw, th, format, idx - 1);
- }
+ int ofs = Image::get_image_mipmap_offset(tw, th, format, idx);
if (total_size - ofs <= 0) {
memdelete(f);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 5b5968c10f..d09fac47f0 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -319,6 +319,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/z_index_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset"));
@@ -646,6 +647,36 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
}
}
+Vector2 TileSet::atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node, const Vector2 &p_tile_location) {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), Vector2());
+ //First try to forward selection to script
+ if (get_script_instance() != NULL) {
+ if (get_script_instance()->has_method("_forward_atlas_subtile_selection")) {
+ Variant ret = get_script_instance()->call("_forward_atlas_subtile_selection", p_id, p_tilemap_node, p_tile_location);
+ if (ret.get_type() == Variant::VECTOR2) {
+ return ret;
+ }
+ }
+ }
+
+ Vector2 coord = tile_get_region(p_id).size / autotile_get_size(p_id);
+
+ List<Vector2> coords;
+ for (int x = 0; x < coord.x; x++) {
+ for (int y = 0; y < coord.y; y++) {
+ for (int i = 0; i < autotile_get_subtile_priority(p_id, Vector2(x, y)); i++) {
+ coords.push_back(Vector2(x, y));
+ }
+ }
+ }
+ if (coords.size() == 0) {
+ return autotile_get_icon_coordinate(p_id);
+ } else {
+ return coords[Math::random(0, (int)coords.size())];
+ }
+}
+
void TileSet::tile_set_name(int p_id, const String &p_name) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -1141,6 +1172,7 @@ void TileSet::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_tile_bound", PropertyInfo(Variant::INT, "drawn_id"), PropertyInfo(Variant::INT, "neighbor_id")));
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
+ BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_atlas_subtile_selection", PropertyInfo(Variant::INT, "atlastile_id"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
BIND_ENUM_CONSTANT(BITMASK_2X2);
BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index fb84cee218..5fc22b9fc6 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -195,6 +195,7 @@ public:
uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord);
const Map<Vector2, uint32_t> &autotile_get_bitmask_map(int p_id);
Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
+ Vector2 atlastile_get_subtile_by_priority(int p_id, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape);
Ref<Shape2D> tile_get_shape(int p_id, int p_shape_id) const;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index b8f21948c3..dd595d9ff8 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "visual_shader.h"
+
#include "core/vmap.h"
#include "servers/visual/shader_types.h"
@@ -159,6 +160,7 @@ Vector2 VisualShader::get_node_position(Type p_type, int p_id) const {
ERR_FAIL_COND_V(!g->nodes.has(p_id), Vector2());
return g->nodes[p_id].position;
}
+
Ref<VisualShaderNode> VisualShader::get_node(Type p_type, int p_id) const {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, Ref<VisualShaderNode>());
const Graph *g = &graph[p_type];
@@ -269,6 +271,18 @@ bool VisualShader::can_connect_nodes(Type p_type, int p_from_node, int p_from_po
return true;
}
+void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
+ ERR_FAIL_INDEX(p_type, TYPE_MAX);
+ Graph *g = &graph[p_type];
+ Connection c;
+ c.from_node = p_from_node;
+ c.from_port = p_from_port;
+ c.to_node = p_to_node;
+ c.to_port = p_to_port;
+ g->connections.push_back(c);
+ _queue_update();
+}
+
Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
ERR_FAIL_INDEX_V(p_type, TYPE_MAX, ERR_CANT_CONNECT);
Graph *g = &graph[p_type];
@@ -283,7 +297,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
if (MAX(0, from_port_type - 2) != (MAX(0, to_port_type - 2))) {
ERR_EXPLAIN("Incompatible port types (scalar/vec/bool with transform");
- ERR_FAIL_V(ERR_INVALID_PARAMETER)
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
return ERR_INVALID_PARAMETER;
}
@@ -304,6 +318,7 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
_queue_update();
return OK;
}
+
void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) {
ERR_FAIL_INDEX(p_type, TYPE_MAX);
Graph *g = &graph[p_type];
@@ -334,6 +349,7 @@ Array VisualShader::_get_node_connections(Type p_type) const {
return ret;
}
+
void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connections) const {
ERR_FAIL_INDEX(p_type, TYPE_MAX);
const Graph *g = &graph[p_type];
@@ -477,6 +493,54 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
#define IS_SYMBOL_CHAR(m_d) (((m_d) >= 'a' && (m_d) <= 'z') || ((m_d) >= 'A' && (m_d) <= 'Z') || ((m_d) >= '0' && (m_d) <= '9') || (m_d) == '_')
+String VisualShader::validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const {
+ String name = p_name;
+
+ while (name.length() && !IS_INITIAL_CHAR(name[0])) {
+ name = name.substr(1, name.length() - 1);
+ }
+
+ if (name != String()) {
+
+ String valid_name;
+
+ for (int i = 0; i < name.length(); i++) {
+ if (IS_SYMBOL_CHAR(name[i])) {
+ valid_name += String::chr(name[i]);
+ } else if (name[i] == ' ') {
+ valid_name += "_";
+ }
+ }
+
+ name = valid_name;
+ }
+
+ String valid_name = name;
+ bool is_equal = false;
+
+ for (int i = 0; i < p_input_ports.size(); i++) {
+ if (name == p_input_ports[i]) {
+ is_equal = true;
+ break;
+ }
+ }
+
+ if (!is_equal) {
+ for (int i = 0; i < p_output_ports.size(); i++) {
+ if (name == p_output_ports[i]) {
+ is_equal = true;
+ break;
+ }
+ }
+ }
+
+ if (is_equal) {
+ name = "";
+ }
+
+ return name;
+}
+
String VisualShader::validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const {
String name = p_name; //validate name first
@@ -596,7 +660,7 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
Vector<int> conns = p_value;
if (conns.size() % 4 == 0) {
for (int i = 0; i < conns.size(); i += 4) {
- connect_nodes(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
+ connect_nodes_forced(type, conns[i + 0], conns[i + 1], conns[i + 2], conns[i + 3]);
}
}
return true;
@@ -611,6 +675,18 @@ bool VisualShader::_set(const StringName &p_name, const Variant &p_value) {
} else if (what == "position") {
set_node_position(type, id, p_value);
return true;
+ } else if (what == "size") {
+ ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_size(p_value);
+ return true;
+ } else if (what == "input_ports") {
+ ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_inputs(p_value);
+ return true;
+ } else if (what == "output_ports") {
+ ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->set_outputs(p_value);
+ return true;
+ } else if (what == "expression") {
+ ((VisualShaderNodeExpression *)get_node(type, id).ptr())->set_expression(p_value);
+ return true;
}
}
return false;
@@ -668,6 +744,18 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const {
} else if (what == "position") {
r_ret = get_node_position(type, id);
return true;
+ } else if (what == "size") {
+ r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_size();
+ return true;
+ } else if (what == "input_ports") {
+ r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_inputs();
+ return true;
+ } else if (what == "output_ports") {
+ r_ret = ((VisualShaderNodeGroupBase *)get_node(type, id).ptr())->get_outputs();
+ return true;
+ } else if (what == "expression") {
+ r_ret = ((VisualShaderNodeExpression *)get_node(type, id).ptr())->get_expression();
+ return true;
}
}
return false;
@@ -727,6 +815,15 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, prop_name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+
+ if (Object::cast_to<VisualShaderNodeGroupBase>(E->get().node.ptr()) != NULL) {
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, prop_name + "/size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/input_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ }
+ if (Object::cast_to<VisualShaderNodeExpression>(E->get().node.ptr()) != NULL) {
+ p_list->push_back(PropertyInfo(Variant::STRING, prop_name + "/expression", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ }
}
p_list->push_back(PropertyInfo(Variant::POOL_INT_ARRAY, "nodes/" + String(type_string[i]) + "/connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
}
@@ -993,26 +1090,33 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) {
}
}
+void VisualShader::rebuild() {
+ dirty = true;
+ _update_shader();
+}
+
void VisualShader::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShader::set_mode);
ClassDB::bind_method(D_METHOD("add_node", "type", "node", "position", "id"), &VisualShader::add_node);
- ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
-
ClassDB::bind_method(D_METHOD("get_node", "type", "id"), &VisualShader::get_node);
+
+ ClassDB::bind_method(D_METHOD("set_node_position", "type", "id", "position"), &VisualShader::set_node_position);
ClassDB::bind_method(D_METHOD("get_node_position", "type", "id"), &VisualShader::get_node_position);
ClassDB::bind_method(D_METHOD("get_node_list", "type"), &VisualShader::get_node_list);
ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id);
ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node);
+ ClassDB::bind_method(D_METHOD("rebuild"), &VisualShader::rebuild);
ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection);
ClassDB::bind_method(D_METHOD("connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes);
ClassDB::bind_method(D_METHOD("disconnect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::disconnect_nodes);
+ ClassDB::bind_method(D_METHOD("connect_nodes_forced", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::connect_nodes_forced);
ClassDB::bind_method(D_METHOD("get_node_connections", "type"), &VisualShader::_get_node_connections);
@@ -1627,3 +1731,555 @@ void VisualShaderNodeUniform::_bind_methods() {
VisualShaderNodeUniform::VisualShaderNodeUniform() {
}
+
+////////////// GroupBase
+
+String VisualShaderNodeGroupBase::get_caption() const {
+ return "Group";
+}
+
+void VisualShaderNodeGroupBase::set_size(const Vector2 &p_size) {
+ size = p_size;
+}
+
+Vector2 VisualShaderNodeGroupBase::get_size() const {
+ return size;
+}
+
+void VisualShaderNodeGroupBase::set_inputs(const String &p_inputs) {
+
+ if (inputs == p_inputs)
+ return;
+
+ clear_input_ports();
+
+ inputs = p_inputs;
+
+ Vector<String> input_strings = inputs.split(";", false);
+
+ int input_port_count = input_strings.size();
+
+ for (int i = 0; i < input_port_count; i++) {
+
+ Vector<String> arr = input_strings[i].split(",");
+
+ int port_idx = arr[0].to_int();
+ int port_type = arr[1].to_int();
+ String port_name = arr[2];
+
+ Port port;
+ port.type = (PortType)port_type;
+ port.name = port_name;
+ input_ports[port_idx] = port;
+ }
+}
+
+String VisualShaderNodeGroupBase::get_inputs() const {
+ return inputs;
+}
+
+void VisualShaderNodeGroupBase::set_outputs(const String &p_outputs) {
+
+ if (outputs == p_outputs)
+ return;
+
+ clear_output_ports();
+
+ outputs = p_outputs;
+
+ Vector<String> output_strings = outputs.split(";", false);
+
+ int output_port_count = output_strings.size();
+
+ for (int i = 0; i < output_port_count; i++) {
+
+ Vector<String> arr = output_strings[i].split(",");
+
+ int port_idx = arr[0].to_int();
+ int port_type = arr[1].to_int();
+ String port_name = arr[2];
+
+ Port port;
+ port.type = (PortType)port_type;
+ port.name = port_name;
+ output_ports[port_idx] = port;
+ }
+}
+
+String VisualShaderNodeGroupBase::get_outputs() const {
+ return outputs;
+}
+
+void VisualShaderNodeGroupBase::add_input_port(int p_id, int p_type, const String &p_name) {
+
+ String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
+ Vector<String> inputs_strings = inputs.split(";", false);
+ int index = 0;
+ if (p_id < inputs_strings.size()) {
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ if (i == p_id) {
+ inputs = inputs.insert(index, str);
+ break;
+ }
+ index += inputs_strings[i].size();
+ }
+ } else {
+ inputs += str;
+ }
+
+ inputs_strings = inputs.split(";", false);
+ index = 0;
+
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ int count = 0;
+ for (int j = 0; j < inputs_strings[i].size(); j++) {
+ if (inputs_strings[i][j] == ',') {
+ break;
+ }
+ count++;
+ }
+
+ inputs.erase(index, count);
+ inputs = inputs.insert(index, itos(i));
+ index += inputs_strings[i].size();
+ }
+
+ _apply_port_changes();
+}
+
+void VisualShaderNodeGroupBase::remove_input_port(int p_id) {
+
+ Vector<String> inputs_strings = inputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ Vector<String> arr = inputs_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ count = inputs_strings[i].size();
+ break;
+ }
+ index += inputs_strings[i].size();
+ }
+ inputs.erase(index, count);
+
+ inputs_strings = inputs.split(";", false);
+ for (int i = p_id; i < inputs_strings.size(); i++) {
+ inputs = inputs.replace_first(inputs_strings[i].split(",")[0], itos(i));
+ }
+
+ _apply_port_changes();
+}
+
+int VisualShaderNodeGroupBase::get_input_port_count() const {
+ return input_ports.size();
+}
+
+bool VisualShaderNodeGroupBase::has_input_port(int p_id) const {
+ return input_ports.has(p_id);
+}
+
+void VisualShaderNodeGroupBase::add_output_port(int p_id, int p_type, const String &p_name) {
+
+ String str = itos(p_id) + "," + itos(p_type) + "," + p_name + ";";
+ Vector<String> outputs_strings = outputs.split(";", false);
+ int index = 0;
+ if (p_id < outputs_strings.size()) {
+ for (int i = 0; i < outputs_strings.size(); i++) {
+ if (i == p_id) {
+ outputs = outputs.insert(index, str);
+ break;
+ }
+ index += outputs_strings[i].size();
+ }
+ } else {
+ outputs += str;
+ }
+
+ outputs_strings = outputs.split(";", false);
+ index = 0;
+
+ for (int i = 0; i < outputs_strings.size(); i++) {
+ int count = 0;
+ for (int j = 0; j < outputs_strings[i].size(); j++) {
+ if (outputs_strings[i][j] == ',') {
+ break;
+ }
+ count++;
+ }
+
+ outputs.erase(index, count);
+ outputs = outputs.insert(index, itos(i));
+ index += outputs_strings[i].size();
+ }
+
+ _apply_port_changes();
+}
+
+void VisualShaderNodeGroupBase::remove_output_port(int p_id) {
+
+ Vector<String> outputs_strings = outputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < outputs_strings.size(); i++) {
+ Vector<String> arr = outputs_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ count = outputs_strings[i].size();
+ break;
+ }
+ index += outputs_strings[i].size();
+ }
+ outputs.erase(index, count);
+
+ outputs_strings = outputs.split(";", false);
+ for (int i = p_id; i < outputs_strings.size(); i++) {
+ outputs = outputs.replace_first(outputs_strings[i].split(",")[0], itos(i));
+ }
+
+ _apply_port_changes();
+}
+
+int VisualShaderNodeGroupBase::get_output_port_count() const {
+ return output_ports.size();
+}
+
+bool VisualShaderNodeGroupBase::has_output_port(int p_id) const {
+ return output_ports.has(p_id);
+}
+
+void VisualShaderNodeGroupBase::clear_input_ports() {
+ input_ports.clear();
+}
+
+void VisualShaderNodeGroupBase::clear_output_ports() {
+ output_ports.clear();
+}
+
+void VisualShaderNodeGroupBase::set_input_port_type(int p_id, int p_type) {
+
+ if (input_ports[p_id].type == p_type)
+ return;
+
+ Vector<String> inputs_strings = inputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ Vector<String> arr = inputs_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ index += arr[0].size();
+ count = arr[1].size() - 1;
+ break;
+ }
+ index += inputs_strings[i].size();
+ }
+
+ inputs.erase(index, count);
+
+ inputs = inputs.insert(index, itos(p_type));
+
+ _apply_port_changes();
+}
+
+VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_input_port_type(int p_id) const {
+ ERR_FAIL_COND_V(!input_ports.has(p_id), (PortType)0);
+ return input_ports[p_id].type;
+}
+
+void VisualShaderNodeGroupBase::set_input_port_name(int p_id, const String &p_name) {
+
+ if (input_ports[p_id].name == p_name)
+ return;
+
+ Vector<String> inputs_strings = inputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ Vector<String> arr = inputs_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ index += arr[0].size() + arr[1].size();
+ count = arr[2].size() - 1;
+ break;
+ }
+ index += inputs_strings[i].size();
+ }
+
+ inputs.erase(index, count);
+
+ inputs = inputs.insert(index, p_name);
+
+ _apply_port_changes();
+}
+
+String VisualShaderNodeGroupBase::get_input_port_name(int p_id) const {
+ ERR_FAIL_COND_V(!input_ports.has(p_id), "");
+ return input_ports[p_id].name;
+}
+
+void VisualShaderNodeGroupBase::set_output_port_type(int p_id, int p_type) {
+
+ if (output_ports[p_id].type == p_type)
+ return;
+
+ Vector<String> output_strings = outputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < output_strings.size(); i++) {
+ Vector<String> arr = output_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ index += arr[0].size();
+ count = arr[1].size() - 1;
+ break;
+ }
+ index += output_strings[i].size();
+ }
+
+ outputs.erase(index, count);
+
+ outputs = outputs.insert(index, itos(p_type));
+
+ _apply_port_changes();
+}
+
+VisualShaderNodeGroupBase::PortType VisualShaderNodeGroupBase::get_output_port_type(int p_id) const {
+ ERR_FAIL_COND_V(!output_ports.has(p_id), (PortType)0);
+ return output_ports[p_id].type;
+}
+
+void VisualShaderNodeGroupBase::set_output_port_name(int p_id, const String &p_name) {
+ if (output_ports[p_id].name == p_name)
+ return;
+
+ Vector<String> output_strings = outputs.split(";", false);
+ int count = 0;
+ int index = 0;
+ for (int i = 0; i < output_strings.size(); i++) {
+ Vector<String> arr = output_strings[i].split(",");
+ if (arr[0].to_int() == p_id) {
+ index += arr[0].size() + arr[1].size();
+ count = arr[2].size() - 1;
+ break;
+ }
+ index += output_strings[i].size();
+ }
+
+ outputs.erase(index, count);
+
+ outputs = outputs.insert(index, p_name);
+
+ _apply_port_changes();
+}
+
+String VisualShaderNodeGroupBase::get_output_port_name(int p_id) const {
+ ERR_FAIL_COND_V(!output_ports.has(p_id), "");
+ return output_ports[p_id].name;
+}
+
+int VisualShaderNodeGroupBase::get_free_input_port_id() const {
+ return input_ports.size();
+}
+
+int VisualShaderNodeGroupBase::get_free_output_port_id() const {
+ return output_ports.size();
+}
+
+void VisualShaderNodeGroupBase::set_control(Control *p_control, int p_index) {
+ controls[p_index] = p_control;
+}
+
+Control *VisualShaderNodeGroupBase::get_control(int p_index) {
+ ERR_FAIL_COND_V(!controls.has(p_index), NULL);
+ return controls[p_index];
+}
+
+void VisualShaderNodeGroupBase::_apply_port_changes() {
+
+ Vector<String> inputs_strings = inputs.split(";", false);
+ Vector<String> outputs_strings = outputs.split(";", false);
+
+ clear_input_ports();
+ clear_output_ports();
+
+ for (int i = 0; i < inputs_strings.size(); i++) {
+ Vector<String> arr = inputs_strings[i].split(",");
+ Port port;
+ port.type = (PortType)arr[1].to_int();
+ port.name = arr[2];
+ input_ports[i] = port;
+ }
+ for (int i = 0; i < outputs_strings.size(); i++) {
+ Vector<String> arr = outputs_strings[i].split(",");
+ Port port;
+ port.type = (PortType)arr[1].to_int();
+ port.name = arr[2];
+ output_ports[i] = port;
+ }
+}
+
+void VisualShaderNodeGroupBase::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &VisualShaderNodeGroupBase::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &VisualShaderNodeGroupBase::get_size);
+
+ ClassDB::bind_method(D_METHOD("set_inputs", "inputs"), &VisualShaderNodeGroupBase::set_inputs);
+ ClassDB::bind_method(D_METHOD("get_inputs"), &VisualShaderNodeGroupBase::get_inputs);
+
+ ClassDB::bind_method(D_METHOD("set_outputs", "outputs"), &VisualShaderNodeGroupBase::set_outputs);
+ ClassDB::bind_method(D_METHOD("get_outputs"), &VisualShaderNodeGroupBase::get_outputs);
+
+ ClassDB::bind_method(D_METHOD("add_input_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_input_port);
+ ClassDB::bind_method(D_METHOD("remove_input_port", "id"), &VisualShaderNodeGroupBase::remove_input_port);
+ ClassDB::bind_method(D_METHOD("get_input_port_count"), &VisualShaderNodeGroupBase::get_input_port_count);
+ ClassDB::bind_method(D_METHOD("has_input_port", "id"), &VisualShaderNodeGroupBase::has_input_port);
+ ClassDB::bind_method(D_METHOD("clear_input_ports"), &VisualShaderNodeGroupBase::clear_input_ports);
+
+ ClassDB::bind_method(D_METHOD("add_output_port", "id", "type", "name"), &VisualShaderNodeGroupBase::add_output_port);
+ ClassDB::bind_method(D_METHOD("remove_output_port", "id"), &VisualShaderNodeGroupBase::remove_output_port);
+ ClassDB::bind_method(D_METHOD("get_output_port_count"), &VisualShaderNodeGroupBase::get_output_port_count);
+ ClassDB::bind_method(D_METHOD("has_output_port", "id"), &VisualShaderNodeGroupBase::has_output_port);
+ ClassDB::bind_method(D_METHOD("clear_output_ports"), &VisualShaderNodeGroupBase::clear_output_ports);
+
+ ClassDB::bind_method(D_METHOD("set_input_port_name"), &VisualShaderNodeGroupBase::set_input_port_name);
+ ClassDB::bind_method(D_METHOD("set_input_port_type"), &VisualShaderNodeGroupBase::set_input_port_type);
+ ClassDB::bind_method(D_METHOD("set_output_port_name"), &VisualShaderNodeGroupBase::set_output_port_name);
+ ClassDB::bind_method(D_METHOD("set_output_port_type"), &VisualShaderNodeGroupBase::set_output_port_type);
+
+ ClassDB::bind_method(D_METHOD("get_free_input_port_id"), &VisualShaderNodeGroupBase::get_free_input_port_id);
+ ClassDB::bind_method(D_METHOD("get_free_output_port_id"), &VisualShaderNodeGroupBase::get_free_output_port_id);
+
+ ClassDB::bind_method(D_METHOD("set_control", "control", "index"), &VisualShaderNodeGroupBase::set_control);
+ ClassDB::bind_method(D_METHOD("get_control", "index"), &VisualShaderNodeGroupBase::get_control);
+}
+
+String VisualShaderNodeGroupBase::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 {
+ return "";
+}
+
+VisualShaderNodeGroupBase::VisualShaderNodeGroupBase() {
+ size = Size2(0, 0);
+ inputs = "";
+ outputs = "";
+}
+
+////////////// Expression
+
+String VisualShaderNodeExpression::get_caption() const {
+ return "Expression";
+}
+
+void VisualShaderNodeExpression::set_expression(const String &p_expression) {
+ expression = p_expression;
+}
+
+void VisualShaderNodeExpression::build() {
+ emit_changed();
+}
+
+String VisualShaderNodeExpression::get_expression() const {
+ return expression;
+}
+
+String VisualShaderNodeExpression::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 _expression = expression;
+
+ _expression = _expression.insert(0, "\n");
+ _expression = _expression.replace("\n", "\n\t\t");
+
+ static Vector<String> pre_symbols;
+ if (pre_symbols.empty()) {
+ pre_symbols.push_back("\t");
+ pre_symbols.push_back("{");
+ pre_symbols.push_back("[");
+ pre_symbols.push_back("(");
+ pre_symbols.push_back(" ");
+ pre_symbols.push_back("-");
+ pre_symbols.push_back("*");
+ pre_symbols.push_back("/");
+ pre_symbols.push_back("+");
+ pre_symbols.push_back("=");
+ pre_symbols.push_back("&");
+ pre_symbols.push_back("|");
+ pre_symbols.push_back("!");
+ }
+
+ static Vector<String> post_symbols;
+ if (post_symbols.empty()) {
+ post_symbols.push_back("\0");
+ post_symbols.push_back("\t");
+ post_symbols.push_back("\n");
+ post_symbols.push_back(";");
+ post_symbols.push_back("}");
+ post_symbols.push_back("]");
+ post_symbols.push_back(")");
+ post_symbols.push_back(" ");
+ post_symbols.push_back(".");
+ post_symbols.push_back("-");
+ post_symbols.push_back("*");
+ post_symbols.push_back("/");
+ post_symbols.push_back("+");
+ post_symbols.push_back("=");
+ post_symbols.push_back("&");
+ post_symbols.push_back("|");
+ post_symbols.push_back("!");
+ }
+
+ for (int i = 0; i < get_input_port_count(); i++) {
+ for (int j = 0; j < pre_symbols.size(); j++) {
+ for (int k = 0; k < post_symbols.size(); k++) {
+ _expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]);
+ }
+ }
+ }
+ for (int i = 0; i < get_output_port_count(); i++) {
+ for (int j = 0; j < pre_symbols.size(); j++) {
+ for (int k = 0; k < post_symbols.size(); k++) {
+ _expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]);
+ }
+ }
+ }
+
+ String output_initializer;
+
+ for (int i = 0; i < get_output_port_count(); i++) {
+ int port_type = get_output_port_type(i);
+ String tk = "";
+ switch (port_type) {
+ case PORT_TYPE_SCALAR:
+ tk = "0.0";
+ break;
+ case PORT_TYPE_VECTOR:
+ tk = "vec3(0.0, 0.0, 0.0)";
+ break;
+ case PORT_TYPE_BOOLEAN:
+ tk = "false";
+ break;
+ case PORT_TYPE_TRANSFORM:
+ tk = "mat4(1.0)";
+ break;
+ default:
+ continue;
+ }
+ output_initializer += "\t" + p_output_vars[i] + "=" + tk + ";\n";
+ }
+
+ String code;
+ code += output_initializer;
+ code += "\t{";
+ code += _expression;
+ code += "\n\t}";
+
+ return code;
+}
+
+void VisualShaderNodeExpression::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_expression", "expression"), &VisualShaderNodeExpression::set_expression);
+ ClassDB::bind_method(D_METHOD("get_expression"), &VisualShaderNodeExpression::get_expression);
+
+ ClassDB::bind_method(D_METHOD("build"), &VisualShaderNodeExpression::build);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "expression"), "set_expression", "get_expression");
+}
+
+VisualShaderNodeExpression::VisualShaderNodeExpression() {
+ expression = "";
+}
diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h
index cf10de9bf5..838c2c618d 100644
--- a/scene/resources/visual_shader.h
+++ b/scene/resources/visual_shader.h
@@ -32,6 +32,7 @@
#define VISUAL_SHADER_H
#include "core/string_builder.h"
+#include "scene/gui/control.h"
#include "scene/resources/shader.h"
class VisualShaderNodeUniform;
@@ -135,7 +136,9 @@ public:
bool can_connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const;
Error connect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
void disconnect_nodes(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+ void connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
+ void rebuild();
void get_node_connections(Type p_type, List<Connection> *r_connections) const;
void set_mode(Mode p_mode);
@@ -148,6 +151,7 @@ public:
String generate_preview_shader(Type p_type, int p_node, int p_port, Vector<DefaultTextureParam> &r_default_tex_params) const;
+ String validate_port_name(const String &p_name, const List<String> &p_input_ports, const List<String> &p_output_ports) const;
String validate_uniform_name(const String &p_name, const Ref<VisualShaderNodeUniform> &p_uniform) const;
VisualShader();
@@ -314,4 +318,93 @@ public:
VisualShaderNodeUniform();
};
+class VisualShaderNodeGroupBase : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode)
+private:
+ void _apply_port_changes();
+
+protected:
+ Vector2 size;
+ String inputs;
+ String outputs;
+
+ struct Port {
+ PortType type;
+ String name;
+ };
+
+ Map<int, Port> input_ports;
+ Map<int, Port> output_ports;
+ Map<int, Control *> controls;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ void set_size(const Vector2 &p_size);
+ Vector2 get_size() const;
+
+ void set_inputs(const String &p_inputs);
+ String get_inputs() const;
+
+ void set_outputs(const String &p_outputs);
+ String get_outputs() const;
+
+ void add_input_port(int p_id, int p_type, const String &p_name);
+ void remove_input_port(int p_id);
+ virtual int get_input_port_count() const;
+ bool has_input_port(int p_id) const;
+ void clear_input_ports();
+
+ void add_output_port(int p_id, int p_type, const String &p_name);
+ void remove_output_port(int p_id);
+ virtual int get_output_port_count() const;
+ bool has_output_port(int p_id) const;
+ void clear_output_ports();
+
+ void set_input_port_type(int p_id, int p_type);
+ virtual PortType get_input_port_type(int p_id) const;
+ void set_input_port_name(int p_id, const String &p_name);
+ virtual String get_input_port_name(int p_id) const;
+
+ void set_output_port_type(int p_id, int p_type);
+ virtual PortType get_output_port_type(int p_id) const;
+ void set_output_port_name(int p_id, const String &p_name);
+ virtual String get_output_port_name(int p_id) const;
+
+ int get_free_input_port_id() const;
+ int get_free_output_port_id() const;
+
+ void set_control(Control *p_control, int p_index);
+ Control *get_control(int p_index);
+
+ 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;
+
+ VisualShaderNodeGroupBase();
+};
+
+class VisualShaderNodeExpression : public VisualShaderNodeGroupBase {
+ GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase)
+
+private:
+ String expression;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual String get_caption() const;
+
+ void set_expression(const String &p_expression);
+ String get_expression() const;
+
+ void build();
+
+ 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;
+
+ VisualShaderNodeExpression();
+};
+
#endif // VISUAL_SHADER_H
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 9b8037965b..a44471a365 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1192,7 +1192,7 @@ String VisualShaderNodeScalarFunc::get_output_port_name(int p_port) const {
String VisualShaderNodeScalarFunc::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 {
- static const char *scalar_func_id[FUNC_TRUNC + 1] = {
+ static const char *scalar_func_id[FUNC_ONEMINUS + 1] = {
"sin($)",
"cos($)",
"tan($)",
@@ -1223,7 +1223,8 @@ String VisualShaderNodeScalarFunc::generate_code(Shader::Mode p_mode, VisualShad
"radians($)",
"1.0/($)",
"roundEven($)",
- "trunc($)"
+ "trunc($)",
+ "1.0-$"
};
return "\t" + p_output_vars[0] + " = " + String(scalar_func_id[func]).replace("$", p_input_vars[0]) + ";\n";
@@ -1251,7 +1252,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeScalarFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeScalarFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Sin,Cos,Tan,ASin,ACos,ATan,SinH,CosH,TanH,Log,Exp,Sqrt,Abs,Sign,Floor,Round,Ceil,Frac,Saturate,Negate,ACosH,ASinH,ATanH,Degrees,Exp2,InverseSqrt,Log2,Radians,Reciprocal,RoundEven,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_SIN);
BIND_ENUM_CONSTANT(FUNC_COS);
@@ -1284,6 +1285,7 @@ void VisualShaderNodeScalarFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_RECIPROCAL);
BIND_ENUM_CONSTANT(FUNC_ROUNDEVEN);
BIND_ENUM_CONSTANT(FUNC_TRUNC);
+ BIND_ENUM_CONSTANT(FUNC_ONEMINUS);
}
VisualShaderNodeScalarFunc::VisualShaderNodeScalarFunc() {
@@ -1319,7 +1321,7 @@ String VisualShaderNodeVectorFunc::get_output_port_name(int p_port) const {
String VisualShaderNodeVectorFunc::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 {
- static const char *vec_func_id[FUNC_TRUNC + 1] = {
+ static const char *vec_func_id[FUNC_ONEMINUS + 1] = {
"normalize($)",
"max(min($,vec3(1.0)),vec3(0.0))",
"-($)",
@@ -1353,7 +1355,8 @@ String VisualShaderNodeVectorFunc::generate_code(Shader::Mode p_mode, VisualShad
"sqrt($)",
"tan($)",
"tanh($)",
- "trunc($)"
+ "trunc($)",
+ "vec3(1.0, 1.0, 1.0)-$"
};
String code;
@@ -1405,7 +1408,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeVectorFunc::set_function);
ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeVectorFunc::get_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc"), "set_function", "get_function");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Normalize,Saturate,Negate,Reciprocal,RGB2HSV,HSV2RGB,Abs,ACos,ACosH,ASin,ASinH,ATan,ATanH,Ceil,Cos,CosH,Degrees,Exp,Exp2,Floor,Frac,InverseSqrt,Log,Log2,Radians,Round,RoundEven,Sign,Sin,SinH,Sqrt,Tan,TanH,Trunc,OneMinus"), "set_function", "get_function");
BIND_ENUM_CONSTANT(FUNC_NORMALIZE);
BIND_ENUM_CONSTANT(FUNC_SATURATE);
@@ -1441,6 +1444,7 @@ void VisualShaderNodeVectorFunc::_bind_methods() {
BIND_ENUM_CONSTANT(FUNC_TAN);
BIND_ENUM_CONSTANT(FUNC_TANH);
BIND_ENUM_CONSTANT(FUNC_TRUNC);
+ BIND_ENUM_CONSTANT(FUNC_ONEMINUS);
}
VisualShaderNodeVectorFunc::VisualShaderNodeVectorFunc() {
@@ -3085,3 +3089,66 @@ VisualShaderNodeSwitch::VisualShaderNodeSwitch() {
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));
}
+
+////////////// Fresnel
+
+String VisualShaderNodeFresnel::get_caption() const {
+ return "Fresnel";
+}
+
+int VisualShaderNodeFresnel::get_input_port_count() const {
+ return 4;
+}
+
+VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR;
+ case 1:
+ return PORT_TYPE_VECTOR;
+ case 2:
+ return PORT_TYPE_BOOLEAN;
+ case 3:
+ return PORT_TYPE_SCALAR;
+ default:
+ return PORT_TYPE_VECTOR;
+ }
+}
+
+String VisualShaderNodeFresnel::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "normal";
+ case 1:
+ return "view";
+ case 2:
+ return "invert";
+ case 3:
+ return "power";
+ default:
+ return "";
+ }
+}
+
+int VisualShaderNodeFresnel::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeFresnel::PortType VisualShaderNodeFresnel::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeFresnel::get_output_port_name(int p_port) const {
+ return "result";
+}
+
+String VisualShaderNodeFresnel::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 {
+ return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + p_input_vars[0] + ", " + p_input_vars[1] + "), 0.0, 1.0), " + p_input_vars[3] + "));";
+}
+
+VisualShaderNodeFresnel::VisualShaderNodeFresnel() {
+ set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0));
+ set_input_port_default_value(2, false);
+ set_input_port_default_value(3, 1.0);
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 90c479bd48..852248b9b4 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -562,7 +562,8 @@ public:
FUNC_RADIANS,
FUNC_RECIPROCAL,
FUNC_ROUNDEVEN,
- FUNC_TRUNC
+ FUNC_TRUNC,
+ FUNC_ONEMINUS
};
protected:
@@ -635,7 +636,8 @@ public:
FUNC_SQRT,
FUNC_TAN,
FUNC_TANH,
- FUNC_TRUNC
+ FUNC_TRUNC,
+ FUNC_ONEMINUS
};
protected:
@@ -1484,4 +1486,26 @@ public:
VisualShaderNodeSwitch();
};
+///////////////////////////////////////
+/// FRESNEL
+///////////////////////////////////////
+
+class VisualShaderNodeFresnel : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeFresnel, 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;
+
+ VisualShaderNodeFresnel();
+};
+
#endif // VISUAL_SHADER_NODES_H