summaryrefslogtreecommitdiff
path: root/scene/resources
diff options
context:
space:
mode:
Diffstat (limited to 'scene/resources')
-rw-r--r--scene/resources/default_theme/default_theme.cpp94
-rw-r--r--scene/resources/default_theme/graph_node_default.pngbin0 -> 289 bytes
-rw-r--r--scene/resources/default_theme/graph_node_default_focus.pngbin0 -> 408 bytes
-rw-r--r--scene/resources/default_theme/graph_node_selected.pngbin0 -> 738 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h15
-rw-r--r--scene/resources/packed_scene.cpp1144
-rw-r--r--scene/resources/packed_scene.h112
-rw-r--r--scene/resources/scene_format_text.cpp792
-rw-r--r--scene/resources/scene_format_text.h46
-rw-r--r--scene/resources/shader_graph.cpp287
-rw-r--r--scene/resources/shader_graph.h15
11 files changed, 2266 insertions, 239 deletions
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index f1e97fd626..5a99538a5f 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -31,7 +31,7 @@ static TexCacheMap *tex_cache;
template<class T>
static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, float p_right, float p_botton,float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1, bool p_draw_center=true) {
-
+
Ref<ImageTexture> texture;
@@ -56,17 +56,17 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, flo
style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
style->set_default_margin( MARGIN_TOP, p_margin_top );
style->set_draw_center(p_draw_center);
-
+
return style;
}
template<class T>
static Ref<Texture> make_icon(T p_src) {
-
-
+
+
Ref<ImageTexture> texture( memnew( ImageTexture ) );
texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
-
+
return texture;
}
@@ -75,7 +75,7 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
Ref<Font> font( memnew( Font ) );
font->add_texture( p_texture );
-
+
for (int i=0;i<p_charcount;i++) {
const int *c = &p_chars[i*8];
@@ -91,9 +91,9 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
font->add_char( chr, 0, frect, align,advance );
-
+
}
-
+
font->set_height( p_height );
font->set_ascent( p_ascent );
@@ -152,12 +152,12 @@ static Ref<Font> make_font2(int p_height,int p_ascent, int p_charcount, const in
static Ref<StyleBox> make_empty_stylebox(float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1) {
Ref<StyleBox> style( memnew( StyleBoxEmpty) );
-
+
style->set_default_margin( MARGIN_LEFT, p_margin_left );
style->set_default_margin( MARGIN_RIGHT, p_margin_right );
style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
style->set_default_margin( MARGIN_TOP, p_margin_top );
-
+
return style;
}
@@ -299,49 +299,49 @@ void make_default_theme() {
t->set_constant("hseparation","MenuButton", 3 );
- // CheckBox
+ // CheckBox
- Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
- cbx_empty->set_default_margin(MARGIN_LEFT,22);
- cbx_empty->set_default_margin(MARGIN_RIGHT,4);
- cbx_empty->set_default_margin(MARGIN_TOP,4);
- cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
- Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin(MARGIN_LEFT,4);
- cbx_focus->set_default_margin(MARGIN_RIGHT,22);
- cbx_focus->set_default_margin(MARGIN_TOP,4);
- cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
+ Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
+ cbx_empty->set_default_margin(MARGIN_LEFT,22);
+ cbx_empty->set_default_margin(MARGIN_RIGHT,4);
+ cbx_empty->set_default_margin(MARGIN_TOP,4);
+ cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
+ Ref<StyleBox> cbx_focus = focus;
+ cbx_focus->set_default_margin(MARGIN_LEFT,4);
+ cbx_focus->set_default_margin(MARGIN_RIGHT,22);
+ cbx_focus->set_default_margin(MARGIN_TOP,4);
+ cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
- t->set_stylebox("normal","CheckBox", cbx_empty );
- t->set_stylebox("pressed","CheckBox", cbx_empty );
- t->set_stylebox("disabled","CheckBox", cbx_empty );
- t->set_stylebox("hover","CheckBox", cbx_empty );
- t->set_stylebox("focus","CheckBox", cbx_focus );
+ t->set_stylebox("normal","CheckBox", cbx_empty );
+ t->set_stylebox("pressed","CheckBox", cbx_empty );
+ t->set_stylebox("disabled","CheckBox", cbx_empty );
+ t->set_stylebox("hover","CheckBox", cbx_empty );
+ t->set_stylebox("focus","CheckBox", cbx_focus );
- t->set_icon("checked", "CheckBox", make_icon(checked_png));
- t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
- t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
- t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
+ t->set_icon("checked", "CheckBox", make_icon(checked_png));
+ t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
+ t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
+ t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
- t->set_font("font","CheckBox", default_font );
+ t->set_font("font","CheckBox", default_font );
- t->set_color("font_color","CheckBox", control_font_color );
- t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
- t->set_color("font_color_hover","CheckBox", control_font_color_hover );
- t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
+ t->set_color("font_color","CheckBox", control_font_color );
+ t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
+ t->set_color("font_color_hover","CheckBox", control_font_color_hover );
+ t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
- t->set_constant("hseparation","CheckBox",4);
- t->set_constant("check_vadjust","CheckBox",0);
+ t->set_constant("hseparation","CheckBox",4);
+ t->set_constant("check_vadjust","CheckBox",0);
// CheckButton
-
+
Ref<StyleBox> cb_empty = memnew( StyleBoxEmpty );
cb_empty->set_default_margin(MARGIN_LEFT,6);
cb_empty->set_default_margin(MARGIN_RIGHT,70);
cb_empty->set_default_margin(MARGIN_TOP,4);
- cb_empty->set_default_margin(MARGIN_BOTTOM,4);
+ cb_empty->set_default_margin(MARGIN_BOTTOM,4);
t->set_stylebox("normal","CheckButton", cb_empty );
t->set_stylebox("pressed","CheckButton", cb_empty );
@@ -365,7 +365,7 @@ void make_default_theme() {
// Label
-
+
t->set_font("font","Label", default_font );
t->set_color("font_color","Label", Color(1,1,1) );
@@ -556,10 +556,16 @@ void make_default_theme() {
// GraphNode
- Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+ Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,3,24,16,5);
+ Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,3,24,16,5);
+ 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);
//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
t->set_stylebox("frame","GraphNode", graphsb );
+ t->set_stylebox("selectedframe","GraphNode", graphsbselected );
+ t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
+ t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
t->set_constant("separation","GraphNode", 1 );
t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
@@ -713,7 +719,7 @@ void make_default_theme() {
// FileDialog
-
+
t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
@@ -877,10 +883,10 @@ void make_default_theme() {
#endif
void clear_default_theme() {
-
+
Theme::set_default( Ref<Theme>() );
Theme::set_default_icon( Ref< Texture >() );
- Theme::set_default_style( Ref< StyleBox >() );
+ Theme::set_default_style( Ref< StyleBox >() );
Theme::set_default_font( Ref< Font >() );
}
diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png
new file mode 100644
index 0000000000..ea6ec52828
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_default.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png
new file mode 100644
index 0000000000..b7c38ae481
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_default_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png
new file mode 100644
index 0000000000..06a9db4409
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_selected.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 03d851e749..ba818d86b2 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -114,6 +114,21 @@ static const unsigned char graph_node_close_png[]={
};
+static const unsigned char graph_node_default_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,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x8,0x1a,0x17,0x2e,0xd,0x4c,0xb7,0x38,0x4,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0x85,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0x31,0xa,0x83,0x40,0x14,0x44,0xdf,0xba,0xa5,0x20,0x41,0x30,0x20,0x4,0xab,0x40,0x20,0x7,0xc9,0x69,0xec,0x72,0x4e,0x9b,0xa0,0x1e,0xc1,0x2a,0x42,0x10,0x82,0xbb,0xc5,0x77,0x6d,0x4c,0x11,0x48,0xe3,0xb7,0x49,0xe1,0x6b,0x6,0xa6,0x78,0xd5,0x8c,0x1,0x6e,0x80,0xe1,0x9b,0xb0,0xe4,0xaf,0xde,0x3,0x4f,0xa0,0x3,0x6,0x93,0x67,0xa7,0xc0,0xa,0x44,0x64,0x72,0x7e,0x6c,0x87,0xf7,0xab,0x4,0x1e,0x68,0x38,0x17,0x97,0x90,0xc4,0x87,0xa,0xb8,0xa2,0xe5,0x98,0xe6,0x1,0xb8,0x47,0x5a,0x81,0xb5,0x16,0xa0,0x56,0xb,0x3e,0xec,0x82,0x3f,0x10,0x4c,0x6a,0x81,0x88,0x78,0xc0,0x45,0xda,0x29,0x3b,0x3f,0x36,0x40,0xbf,0xf9,0x4c,0x66,0xeb,0x9d,0x67,0x5c,0x46,0x37,0x51,0xb6,0x55,0x6d,0xc2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_node_default_focus_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,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x8,0x1b,0x1,0x9,0x1c,0x5c,0xd5,0x12,0x34,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0xfc,0x49,0x44,0x41,0x54,0x38,0xcb,0xbd,0x93,0x41,0x4a,0x4,0x41,0xc,0x45,0x7f,0xca,0x6a,0x14,0x42,0x2f,0xc4,0x85,0x7,0xf0,0x3c,0xde,0xa2,0xbc,0x41,0xd7,0xa2,0xa1,0x60,0xea,0x60,0xae,0x5c,0xea,0x19,0xdc,0xd7,0x42,0x97,0xe5,0xc,0x12,0xeb,0xbb,0x69,0xa5,0x84,0xe9,0x41,0x1d,0xf1,0x43,0x8,0x84,0xe4,0x2d,0x92,0x1f,0xc1,0x22,0x92,0x2,0xc0,0x2d,0x81,0x2e,0x7f,0xa8,0x75,0xb9,0x89,0x8,0x1,0x40,0x48,0x5e,0x76,0xcd,0xad,0x6b,0x74,0x7b,0xea,0x6,0xe0,0x75,0x9,0x13,0x11,0xca,0x34,0x4d,0xc4,0x37,0x35,0xc,0xc3,0xf3,0x38,0x8e,0xb7,0xf3,0x3c,0xdf,0x0,0xd8,0x1,0x30,0x90,0x4,0x49,0xe4,0x9c,0x11,0x42,0x40,0x29,0x65,0x15,0x50,0x4a,0xb9,0x8,0x21,0x30,0xe7,0x7c,0x47,0x52,0x49,0x9e,0x7c,0x2,0x62,0x8c,0x30,0x33,0xa8,0xea,0x2a,0x40,0x55,0xaf,0xcc,0x4c,0x62,0x8c,0x5b,0x92,0xe7,0x24,0x7,0xd7,0x2d,0x11,0xde,0x7b,0xd4,0x5a,0x57,0x1,0xb5,0xd6,0x47,0xef,0x3d,0x49,0x9e,0x1,0xf0,0x0,0x9c,0xc3,0xef,0xe5,0xf6,0x9d,0xea,0x5f,0x1,0x38,0x16,0xd0,0xfe,0x16,0x20,0x22,0x7,0x3d,0xd0,0x7b,0x41,0x44,0xb6,0x8b,0x2b,0x9b,0xeb,0x6e,0x8c,0x94,0x12,0xcc,0x6c,0x75,0xd8,0xcc,0xc6,0x94,0xd2,0x93,0xaa,0xde,0x2f,0x76,0x6e,0x3f,0xb2,0xb2,0x88,0xec,0x54,0xf5,0x61,0xb3,0xd9,0x5c,0x3,0x78,0x1,0x60,0xc7,0x3c,0x53,0x13,0x91,0x37,0xe9,0x9d,0xd8,0xe9,0xf4,0xc0,0xe2,0xbe,0xbc,0xf3,0x3b,0x49,0xa0,0x89,0xbf,0x71,0xc6,0xcd,0x1c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_node_selected_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x7,0x12,0x1,0xc,0x6,0x23,0x98,0xc7,0x50,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x2,0x46,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xcd,0x6a,0x13,0x51,0x14,0xc7,0x7f,0xe7,0xce,0x34,0x49,0xd,0xa6,0xb1,0x2a,0xe2,0x7,0x74,0xa1,0x6e,0x4,0x85,0xe2,0x3,0xb8,0x72,0x21,0xba,0x16,0x5c,0xb9,0x16,0x4,0x7d,0x84,0x3e,0x82,0x82,0xe0,0xda,0x95,0x2f,0x60,0x71,0xe1,0xca,0x7,0xd0,0x82,0xa5,0x6e,0xd4,0x45,0xc1,0x8f,0x4a,0x6c,0x9a,0x46,0x62,0x66,0xa6,0x73,0xef,0x71,0xe1,0x4c,0x92,0x99,0x4c,0x93,0x36,0xdd,0xc9,0xfc,0x37,0x77,0x3e,0xee,0xfd,0xdd,0x73,0xfe,0xf7,0xc,0xcc,0x11,0x86,0x12,0xc0,0x0,0x5e,0x32,0xa,0x59,0x29,0xe0,0x0,0x9b,0x8c,0xca,0xc8,0x24,0x3,0x1c,0x3,0x16,0x81,0xd3,0x40,0x3,0x98,0xcb,0x1,0xf6,0x80,0x2e,0xd0,0x2,0xda,0xc0,0x1f,0xc0,0xa5,0xbb,0xd6,0x81,0x4b,0xb,0xc7,0x9b,0xf,0x6a,0xd5,0xda,0xad,0x4a,0xa5,0x7a,0x81,0x2,0x45,0x51,0xf8,0x35,0x8,0x83,0xd7,0xbb,0xbf,0x3b,0xcf,0x81,0xcf,0x40,0x4f,0x92,0x9d,0x96,0x16,0x9b,0x27,0x9f,0x5c,0x5c,0xba,0x7c,0xfb,0xfe,0xcb,0x3b,0x34,0x2b,0x27,0x8a,0xd6,0xd3,0x89,0x76,0x78,0x71,0xef,0x15,0x5f,0x36,0x3f,0xad,0xb6,0x3b,0xdb,0x8f,0x81,0x4d,0x1,0x6a,0xc0,0xf2,0xd9,0x33,0xe7,0xdf,0xac,0xbc,0x7d,0x54,0xdf,0x73,0x11,0x81,0xed,0x17,0x2,0x6a,0xde,0x3c,0x73,0xa6,0xc2,0xca,0x8d,0xa7,0xbd,0x1f,0x3f,0xbf,0xdd,0x4,0xd6,0xfc,0xc4,0x87,0xba,0xef,0xf9,0xf5,0x6e,0xb4,0xc3,0x24,0xf5,0xe3,0x1e,0x7d,0x7a,0xf8,0x9e,0x5f,0x4f,0xd2,0x96,0x14,0xe0,0x1,0x58,0xb5,0x39,0xdb,0x1d,0x82,0x19,0x5c,0xe7,0xe4,0xa5,0x0,0x4d,0x8f,0x44,0x71,0xa8,0x2a,0x22,0x92,0x81,0x4c,0x92,0x3f,0x7a,0xe3,0xd4,0xe2,0x54,0x41,0xc1,0x13,0xf,0xc5,0xe1,0x54,0x31,0x22,0x8,0xa6,0x10,0x96,0x1,0x58,0x1d,0x4e,0x88,0x35,0x1e,0x79,0x9e,0xd6,0xd0,0x94,0x8,0x54,0xb3,0x93,0x1c,0x8a,0x41,0x6,0x63,0xfa,0x6c,0x5f,0x40,0xe4,0xa2,0xcc,0x4b,0x23,0x32,0xd8,0x37,0x4e,0x52,0x99,0x1c,0x41,0x2e,0x4c,0x9b,0xdd,0x6c,0xec,0xbe,0x20,0x5,0xe5,0xb0,0xca,0x99,0x68,0x93,0x48,0x14,0x41,0x30,0x22,0x3,0x63,0x5,0x41,0x51,0x3c,0x31,0x93,0x8f,0x31,0xf3,0xed,0x6a,0xf6,0x5b,0xfe,0xe7,0x85,0x9b,0x0,0x98,0x52,0x34,0x7,0x2a,0xa4,0xb4,0x74,0x8b,0x4c,0x2d,0x2a,0xa6,0xb1,0x42,0x32,0x8c,0x1b,0x39,0x3c,0x7b,0x37,0xbd,0x90,0xec,0x51,0x52,0x88,0x5d,0x3c,0x36,0x21,0xd,0x39,0x4d,0x4d,0x72,0xc5,0x94,0x1,0xac,0xde,0x7d,0x3f,0xbb,0x89,0xf1,0x9e,0x65,0xf9,0xea,0xf5,0x3,0x2d,0x5a,0x5b,0x7f,0x57,0x1c,0xc1,0x6e,0xb7,0x73,0xe8,0x8,0xc,0x47,0x54,0x9,0x28,0x1,0x25,0xa0,0x4,0x94,0x80,0x12,0x50,0x2,0xfe,0x4b,0x80,0x14,0xf4,0x88,0x87,0x8e,0xc0,0xcd,0xb0,0xd6,0xa5,0x0,0x7,0x4,0xd6,0xda,0xb0,0xe0,0x27,0x6d,0x7c,0x55,0xc,0xd6,0xda,0x10,0x8,0x0,0x67,0x92,0x56,0x76,0x3b,0x8,0xfb,0x1b,0xad,0xf6,0x16,0x93,0x20,0x2e,0x86,0x56,0x7b,0x8b,0x20,0xec,0x6f,0x0,0xdb,0x80,0x4d,0x3b,0xd7,0x5,0xe0,0x5a,0xa3,0xde,0x7c,0x56,0xab,0xce,0x5f,0xf1,0x3c,0xaf,0xd0,0x5c,0x6b,0xad,0xb,0xc2,0xfe,0xc7,0x6e,0xaf,0xf3,0x10,0xf8,0x0,0xec,0xca,0x48,0xb,0xd7,0x0,0xce,0x1,0xa7,0x80,0xea,0x3e,0xcd,0x77,0x8,0xfc,0x2,0xbe,0x27,0x7d,0xb4,0x95,0x9c,0xa1,0x7e,0xda,0xf,0xee,0x93,0x85,0x26,0x29,0xc7,0x33,0x1a,0x3f,0xae,0xbf,0xf0,0x27,0xf6,0x42,0xf6,0xf5,0xfd,0xae,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char graph_port_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index b6082c3a76..fdf1692495 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -32,13 +32,30 @@
#include "scene/3d/spatial.h"
#include "scene/gui/control.h"
#include "scene/2d/node_2d.h"
+#include "scene/main/instance_placeholder.h"
-bool PackedScene::can_instance() const {
+#define PACK_VERSION 2
+
+bool SceneState::can_instance() const {
return nodes.size()>0;
}
-Node *PackedScene::instance(bool p_gen_edit_state) const {
+
+Node *SceneState::instance(bool p_gen_edit_state) const {
+
+ // nodes where instancing failed (because something is missing)
+ List<Node*> stray_instances;
+
+#define NODE_FROM_ID(p_name,p_id)\
+ Node *p_name;\
+ if (p_id&FLAG_ID_IS_PATH) {\
+ NodePath np=node_paths[p_id&FLAG_MASK];\
+ p_name=ret_nodes[0]->_get_node(np);\
+ } else {\
+ ERR_FAIL_INDEX_V(p_id&FLAG_MASK,nc,NULL);\
+ p_name=ret_nodes[p_id&FLAG_MASK];\
+ }
int nc = nodes.size();
ERR_FAIL_COND_V(nc==0,NULL);
@@ -59,29 +76,80 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
+ bool gen_node_path_cache=p_gen_edit_state && node_path_cache.empty();
for(int i=0;i<nc;i++) {
const NodeData &n=nd[i];
- if (!ObjectTypeDB::is_type_enabled(snames[n.type])) {
- ret_nodes[i]=NULL;
- continue;
+ Node *parent=NULL;
+
+ if (i>0) {
+
+ NODE_FROM_ID(nparent,n.parent);
+#ifdef DEBUG_ENABLED
+ if (!nparent && n.parent&FLAG_ID_IS_PATH) {
+
+ WARN_PRINT(String("Parent path '"+String(node_paths[n.parent&FLAG_MASK])+"' for node '"+String(snames[n.name])+"' has vanished when instancing: '"+get_path()+"'.").ascii().get_data());
+
+ }
+#endif
+ parent=nparent;
}
Node *node=NULL;
- if (n.instance>=0) {
- //instance existing
- Ref<PackedScene> sdata = props[ n.instance ];
+ if (i==0 && base_scene_idx>=0) {
+ //scene inheritance on root node
+ //print_line("scene inherit");
+ Ref<PackedScene> sdata = props[ base_scene_idx ];
ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
- node = sdata->instance();
+ node = sdata->instance(p_gen_edit_state);
ERR_FAIL_COND_V(!node,NULL);
- if (p_gen_edit_state)
- node->generate_instance_state();
+ if (p_gen_edit_state) {
+ node->set_scene_inherited_state(sdata->get_state());
+ }
- } else {
- //create anew
+ } else if (n.instance>=0) {
+ //instance a scene into this node
+ //print_line("instance");
+ if (n.instance&FLAG_INSTANCE_IS_PLACEHOLDER) {
+
+ String path = props[n.instance&FLAG_MASK];
+ if (disable_placeholders) {
+
+ Ref<PackedScene> sdata = ResourceLoader::load(path,"PackedScene");
+ ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
+ node = sdata->instance(p_gen_edit_state);
+ ERR_FAIL_COND_V(!node,NULL);
+ } else {
+ InstancePlaceholder *ip = memnew( InstancePlaceholder );
+ ip->set_path(path);
+ node=ip;
+ }
+ node->set_scene_instance_load_placeholder(true);
+ } else {
+ Ref<PackedScene> sdata = props[ n.instance&FLAG_MASK ];
+ ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
+ node = sdata->instance(p_gen_edit_state);
+ ERR_FAIL_COND_V(!node,NULL);
+
+ }
+
+ } else if (n.type==TYPE_INSTANCED) {
+ //print_line("instanced");
+ //get the node from somewhere, it likely already exists from another instance
+ if (parent) {
+ node=parent->_get_child_by_name(snames[n.name]);
+#ifdef DEBUG_ENABLED
+ if (!node) {
+ WARN_PRINT(String("Node '"+String(ret_nodes[0]->get_path_to(parent))+"/"+String(snames[n.name])+"' was modified from inside a instance, but it has vanished.").ascii().get_data());
+ }
+#endif
+ }
+ } else if (ObjectTypeDB::is_type_enabled(snames[n.type])) {
+ //print_line("created");
+ //node belongs to this scene and must be created
Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
if (!obj || !obj->cast_to<Node>()) {
if (obj) {
@@ -109,49 +177,68 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
}
- //properties
- int nprop_count=n.properties.size();
- if (nprop_count) {
+ if (node) {
+ // may not have found the node (part of instanced scene and removed)
+ // if found all is good, otherwise ignore
+
+ //properties
+ int nprop_count=n.properties.size();
+ if (nprop_count) {
- const NodeData::Property* nprops=&n.properties[0];
+ const NodeData::Property* nprops=&n.properties[0];
- for(int j=0;j<nprop_count;j++) {
+ for(int j=0;j<nprop_count;j++) {
- bool valid;
- ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
- ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
+ bool valid;
+ ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
+ ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ }
}
- }
- //name
+ //name
- //groups
- for(int j=0;j<n.groups.size();j++) {
+ //groups
+ for(int j=0;j<n.groups.size();j++) {
- ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
- node->add_to_group( snames[ n.groups[j] ], true );
- }
+ ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
+ node->add_to_group( snames[ n.groups[j] ], true );
+ }
+ if (n.instance>=0 || n.type!=TYPE_INSTANCED) {
+ //if node was not part of instance, must set it's name, parenthood and ownership
+ if (i>0) {
+ if (parent) {
+ parent->_add_child_nocheck(node,snames[n.name]);
+ } else {
+ //it may be possible that an instanced scene has changed
+ //and the node has nowhere to go anymore
+ stray_instances.push_back(node); //can't be added, go to stray list
+ }
+ } else {
+ node->_set_name_nocheck( snames[ n.name ] );
+ }
- ret_nodes[i]=node;
+ }
- if (i>0) {
- ERR_FAIL_INDEX_V(n.parent,i,NULL);
- ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL);
- ret_nodes[n.parent]->_add_child_nocheck(node,snames[n.name]);
- } else {
- node->_set_name_nocheck( snames[ n.name ] );
- }
+ if (n.owner>=0) {
+ NODE_FROM_ID(owner,n.owner);
+ if (owner)
+ node->_set_owner_nocheck(owner);
+ }
- if (n.owner>=0) {
- ERR_FAIL_INDEX_V(n.owner,i,NULL);
- node->_set_owner_nocheck(ret_nodes[n.owner]);
}
+
+ ret_nodes[i]=node;
+
+ if (node && gen_node_path_cache && ret_nodes[0]) {
+ NodePath n = ret_nodes[0]->get_path_to(node);
+ node_path_cache[n]=i;
+ }
}
@@ -163,8 +250,14 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
for(int i=0;i<cc;i++) {
const ConnectionData &c=cdata[i];
- ERR_FAIL_INDEX_V( c.from, nc, NULL );
- ERR_FAIL_INDEX_V( c.to, nc, NULL );
+ //ERR_FAIL_INDEX_V( c.from, nc, NULL );
+ //ERR_FAIL_INDEX_V( c.to, nc, NULL );
+
+ NODE_FROM_ID(cfrom,c.from);
+ NODE_FROM_ID(cto,c.to);
+
+ if (!cfrom || !cto)
+ continue;
Vector<Variant> binds;
if (c.binds.size()) {
@@ -173,17 +266,25 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
binds[j]=props[ c.binds[j] ];
}
- if (!ret_nodes[c.from] || !ret_nodes[c.to])
- continue;
- ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST|c.flags );
+
+ cfrom->connect( snames[ c.signal], cto, snames[ c.method], binds,CONNECT_PERSIST|c.flags );
}
- Node *s = ret_nodes[0];
+ //Node *s = ret_nodes[0];
- if (get_path()!="" && get_path().find("::")==-1)
- s->set_filename(get_path());
+ //remove nodes that could not be added, likely as a result that
+ while(stray_instances.size()) {
+ memdelete(stray_instances.front()->get());
+ stray_instances.pop_front();;
+ }
+
+ for(int i=0;i<editable_instances.size();i++) {
+ Node *ei = ret_nodes[0]->_get_node(editable_instances[i]);
+ if (ei) {
+ ret_nodes[0]->set_editable_instance(ei,true);
+ }
+ }
- s->notification(Node::NOTIFICATION_INSTANCED);
return ret_nodes[0];
}
@@ -209,44 +310,157 @@ static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,Variant
return idx;
}
-Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
+Error SceneState::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) {
+
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
+ // this function handles all the work related to properly packing scenes, be it
+ // instanced or inherited.
+ // given the complexity of this process, an attempt will be made to properly
+ // document it. if you fail to understand something, please ask!
+
+ //discard nodes that do not belong to be processed
+ if (p_node!=p_owner && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner()))
+ return OK;
+
+ // save the child instanced scenes that are chosen as editable, so they can be restored
+ // upon load back
+ if (p_node!=p_owner && p_node->get_filename()!=String() && p_owner->is_editable_instance(p_node))
+ editable_instances.push_back(p_owner->get_path_to(p_node));
NodeData nd;
nd.name=_nm_get_string(p_node->get_name(),name_map);
- nd.type=_nm_get_string(p_node->get_type(),name_map);
- nd.parent=p_parent_idx;
+ nd.instance=-1; //not instanced by default
+
+ // if this node is part of an instanced scene or sub-instanced scene
+ // we need to get the corresponding instance states.
+ // with the instance states, we can query for identical properties/groups
+ // and only save what has changed
+
+ List<PackState> pack_state_stack;
+
+ bool instanced_by_owner=true;
+
+ {
+ Node *n=p_node;
+
+ while(n) {
+
+ if (n==p_owner) {
+
+ Ref<SceneState> state = n->get_scene_inherited_state();
+ if (state.is_valid()) {
+ int node = state->find_node_by_path(n->get_path_to(p_node));
+ if (node>=0) {
+ //this one has state for this node, save
+ PackState ps;
+ ps.node=node;
+ ps.state=state;
+ pack_state_stack.push_front(ps);
+ instanced_by_owner=false;
+ }
+ }
+
+ if (p_node->get_filename()!=String() && p_node->get_owner()==p_owner && instanced_by_owner) {
+
+ if (p_node->get_scene_instance_load_placeholder()) {
+ //it's a placeholder, use the placeholder path
+ nd.instance=_vm_get_variant(p_node->get_filename(),variant_map);
+ nd.instance|=FLAG_INSTANCE_IS_PLACEHOLDER;
+ } else {
+ //must instance ourselves
+ Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename());
+ if (!instance.is_valid()) {
+ return ERR_CANT_OPEN;
+ }
+ nd.instance=_vm_get_variant(instance,variant_map);
+ }
+ }
+ n=NULL;
+ } else {
+ if (n->get_filename()!=String()) {
+ //is an instance
+ Ref<SceneState> state = n->get_scene_instance_state();
+ if (state.is_valid()) {
+ int node = state->find_node_by_path(n->get_path_to(p_node));
+ if (node>=0) {
+ //this one has state for this node, save
+ PackState ps;
+ ps.node=node;
+ ps.state=state;
+ pack_state_stack.push_back(ps);
+ }
+ }
+
+ }
+ n=n->get_owner();
+ }
+ }
+ }
+
+#if 0
+
+ Ref<SceneState> base_scene = p_node->get_scene_inherited_state(); //for inheritance
+ Ref<SceneState> instance_state;
+ int instance_state_node=-1;
+
+ if (base_scene.is_valid() && (p_node==p_owner || p_node->get_owner()==p_owner)) {
+ //scene inheritance in use, see if this node is actually inherited
+ NodePath path = p_owner->get_path_to(p_node);
+ instance_state_node = base_scene->find_node_by_path(path);
+ if (instance_state_node>=0) {
+ instance_state=base_scene;
+ }
+ }
- Dictionary instance_state;
- Set<StringName> instance_groups;
+ // check that this is a directly instanced scene from the scene being packed, if so
+ // this information must be saved. Of course, if using scene instancing and this node
+ // does belong to base scene, ignore.
+ if (instance_state.is_null() && p_node!=p_owner && p_node->get_owner()==p_owner && p_node->get_filename()!="") {
- if (p_node!=p_owner && p_node->get_filename()!="") {
- //instanced
+ //instanced, only direct sub-scnes are supported of course
Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename());
if (!instance.is_valid()) {
return ERR_CANT_OPEN;
}
nd.instance=_vm_get_variant(instance,variant_map);
- instance_state = p_node->get_instance_state();
- Vector<StringName> ig = p_node->get_instance_groups();
- for(int i=0;i<ig.size();i++)
- instance_groups.insert(ig[i]);
+
} else {
nd.instance=-1;
}
+ // finally, if this does not belong to scene inheritance, check
+ // if it belongs to scene instancing
+
+ if (instance_state.is_null() && p_node!=p_owner) {
+ //if not affected by scene inheritance, this may be
+ if (p_node->get_owner()==p_owner && p_node->get_filename()!=String()) {
+ instance_state=p_node->get_scene_instance_state();
+ if (instance_state.is_valid()) {
+ instance_state_node=instance_state->find_node_by_path(p_node->get_path_to(p_node));
+ }
- //instance state makes sure that only changes to instance are saved
+ } else if (p_node->get_owner()!=p_owner && p_owner->is_editable_instance(p_node->get_owner())) {
+ instance_state=p_node->get_owner()->get_scene_instance_state();
+ if (instance_state.is_valid()) {
+ instance_state_node=instance_state->find_node_by_path(p_node->get_owner()->get_path_to(p_node));
+ }
+ }
+ }
+#endif
+ int subscene_prop_search_from=0;
+
+ // all setup, we then proceed to check all properties for the node
+ // and save the ones that are worth saving
List<PropertyInfo> plist;
p_node->get_property_list(&plist);
+
+
for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
@@ -257,34 +471,63 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
String name = E->get().name;
Variant value = p_node->get( E->get().name );
- if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
- continue;
- }
- print_line("PASSED!");
- print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
- print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
+ bool isdefault = ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one());
+
+// if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
+// continue;
+// }
- if (nd.instance>=0) {
- //only save changed properties in instance
- /*
- // this was commented because it would not save properties created from within script
- // done with _get_property_list, that are not in the original node.
- // if some property is not saved, check again
- if (!instance_state.has(name)) {
- print_line("skip not in instance");
+
+ //print_line("PASSED!");
+ //print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
+ //print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
+
+ if (pack_state_stack.size()) {
+ // we are on part of an instanced subscene
+ // or part of instanced scene.
+ // only save what has been changed
+ // only save changed properties in instance
+
+ if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE || E->get().name=="__meta__") {
+ //property has requested that no instance state is saved, sorry
+ //also, meta won't be overriden or saved
continue;
- }*/
+ }
+
+ bool exists=false;
+ Variant original;
+
+ for (List<PackState>::Element *F=pack_state_stack.back();F;F=F->prev()) {
+ //check all levels of pack to see if the property exists somewhere
+ const PackState &ps=F->get();
- if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE) {
+ original = ps.state->get_property_value(ps.node,E->get().name,exists);
+ if (exists) {
+ break;
+ }
+ }
+
+
+ if (exists && bool(Variant::evaluate(Variant::OP_EQUAL,value,original))) {
+ //exists and did not change
continue;
}
- if (instance_state.has(name) && instance_state[name]==value) {
+ if (!exists && isdefault) {
+ //does not exist in original node, but it's the default value
+ //so safe to skip too.
continue;
}
+
+ } else {
+
+ if (isdefault) {
+ //it's the default value, no point in saving it
+ continue;
+ }
}
NodeData::Property prop;
@@ -295,6 +538,9 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
}
+ // save the groups this node is into
+ // discard groups that come from the original scene
+
List<Node::GroupInfo> groups;
p_node->get_groups(&groups);
for(List<Node::GroupInfo>::Element *E=groups.front();E;E=E->next()) {
@@ -302,27 +548,123 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
if (!gi.persistent)
continue;
- if (nd.instance>=0 && instance_groups.has(gi.name))
- continue; //group was instanced, don't add here
+// if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name))
+// continue; //group was instanced, don't add here
+
+ bool skip=false;
+ for (List<PackState>::Element *F=pack_state_stack.front();F;F=F->next()) {
+ //check all levels of pack to see if the group was added somewhere
+ const PackState &ps=F->get();
+ if (ps.state->is_node_in_group(ps.node,gi.name)) {
+ skip=true;
+ break;
+ }
+ }
+
+ if (skip)
+ continue;
nd.groups.push_back(_nm_get_string(gi.name,name_map));
}
- if (node_map.has(p_node->get_owner()))
- nd.owner=node_map[p_node->get_owner()];
- else
+
+ // save the right owner
+ // for the saved scene root this is -1
+ // for nodes of the saved scene this is 0
+ // for nodes of instanced scenes this is >0
+
+ if (p_node==p_owner) {
+ //saved scene root
+ nd.owner=-1;
+ } else if (p_node->get_owner()==p_owner) {
+ //part of saved scene
+ nd.owner=0;
+ } else {
+
nd.owner=-1;
+#if 0
+ // this is pointless, if this was instanced by something else,
+ // the owner will already be set.
+
+ if (node_map.has(p_node->get_owner())) {
+ //maybe an existing saved node
+ nd.owner=node_map[p_node->get_owner()];
+ } else {
+ //not saved, use nodepath map
+ int sidx;
+ if (nodepath_map.has(p_node->get_owner())) {
+ sidx=nodepath_map[p_node->get_owner()];
+ } else {
+ sidx=nodepath_map.size();
+ nodepath_map[p_node->get_owner()]=sidx;
+ }
+
+ nd.owner=FLAG_ID_IS_PATH|sidx;
+
+ }
+#endif
+
+
+ }
+
+ // Save the right type. If this node was created by an instance
+ // then flag that the node should not be created but reused
+ if (pack_state_stack.empty()) {
+ //this node is not part of an instancing process, so save the type
+ nd.type=_nm_get_string(p_node->get_type(),name_map);
+ } else {
+ // this node is part of an instanced process, so do not save the type.
+ // instead, save that it was instanced
+ nd.type=TYPE_INSTANCED;
+ }
+
+
+ // determine whether to save this node or not
+ // if this node is part of an instanced sub-scene, we can skip storing it if basically
+ // no properties changed and no groups were added to it.
+ // below condition is true for all nodes of the scene being saved, and ones in subscenes
+ // that hold changes
+
+ bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist
+ save_node = save_node || p_node==p_owner; // owner is always saved
+ save_node = save_node || (p_node->get_owner()==p_owner && instanced_by_owner); //part of scene and not instanced
+
int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
+ int parent_node=NO_PARENT_SAVED;
+
+ if (save_node) {
+ //don't save the node if nothing and subscene
+
+ node_map[p_node]=idx;
+
+ //ok validate parent node
+ if (p_parent_idx==NO_PARENT_SAVED) {
+
+ int sidx;
+ if (nodepath_map.has(p_node->get_parent())) {
+ sidx=nodepath_map[p_node->get_parent()];
+ } else {
+ sidx=nodepath_map.size();
+ nodepath_map[p_node->get_parent()]=sidx;
+ }
+
+ nd.parent=FLAG_ID_IS_PATH|sidx;
+ } else {
+ nd.parent=p_parent_idx;
+ }
+
+ parent_node=idx;
+ nodes.push_back(nd);
+
+ }
for(int i=0;i<p_node->get_child_count();i++) {
Node *c=p_node->get_child(i);
- Error err = _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
+ Error err = _parse_node(p_owner,c,parent_node,name_map,variant_map,node_map,nodepath_map);
if (err)
return err;
}
@@ -331,53 +673,135 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
}
-Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
-
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
+Error SceneState::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) {
- ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
- NodeData &nd = nodes[node_map[p_node]];
- Set<Connection> instance_connections;
+ if (p_node!=p_owner && p_node->get_owner() && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner()))
+ return OK;
- if (nd.instance>=0) {
- Vector<Connection> iconns = p_node->get_instance_connections();
- for(int i=0;i<iconns.size();i++) {
+ List<MethodInfo> _signals;
+ p_node->get_signal_list(&_signals);
- instance_connections.insert(iconns[i]);
- }
- }
+ //ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
+ //NodeData &nd = nodes[node_map[p_node]];
- for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) {
+ for(List<MethodInfo>::Element *E=_signals.front();E;E=E->next()) {
List<Node::Connection> conns;
p_node->get_signal_connection_list(E->get().name,&conns);
for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) {
const Node::Connection &c = F->get();
- if (!(c.flags&CONNECT_PERSIST))
+
+ if (!(c.flags&CONNECT_PERSIST)) //only persistent connections get saved
continue;
- if (nd.instance>=0 && instance_connections.has(c))
- continue; //came from instance, don't save!
+ // only connections that originate or end into main saved scene are saved
+ // everything else is discarded
Node *n=c.target->cast_to<Node>();
- if (!n)
+ if (!n) {
continue;
+ }
+
+ //source node is outside saved scene?
+ bool src_is_out = p_node!=p_owner && (p_node->get_filename()!=String() || p_node->get_owner()!=p_owner);
+ //target node is outside saved scene?
+ bool dst_is_out = n!=p_owner && (n->get_filename()!=String() || n->get_owner()!=p_owner);
- if (!node_map.has(n)) {
- WARN_PRINT("Connection to node outside scene??")
+ //if both are out, ignore connection
+ if (src_is_out && dst_is_out) {
continue;
}
+
+ {
+ Node *nl=p_node;
+
+ bool exists=false;
+
+ while(nl) {
+
+ if (nl==p_owner) {
+
+ Ref<SceneState> state = nl->get_scene_inherited_state();
+ if (state.is_valid()) {
+ int from_node = state->find_node_by_path(nl->get_path_to(p_node));
+ int to_node = state->find_node_by_path(nl->get_path_to(n));
+
+ if (from_node>=0 && to_node>=0) {
+ //this one has state for this node, save
+ if (state->is_connection(from_node,c.signal,to_node,c.method)) {
+ exists=true;
+ break;
+ }
+ }
+ }
+
+ nl=NULL;
+ } else {
+ if (nl->get_filename()!=String()) {
+ //is an instance
+ Ref<SceneState> state = nl->get_scene_instance_state();
+ if (state.is_valid()) {
+ int from_node = state->find_node_by_path(nl->get_path_to(p_node));
+ int to_node = state->find_node_by_path(nl->get_path_to(n));
+
+ if (from_node>=0 && to_node>=0) {
+ //this one has state for this node, save
+ if (state->is_connection(from_node,c.signal,to_node,c.method)) {
+ exists=true;
+ break;
+ }
+ }
+ }
+
+ }
+ nl=nl->get_owner();
+ }
+ }
+
+ if (exists) {
+ continue;
+ }
+
+ }
+
+
+ int src_id;
+
+ if (node_map.has(p_node)) {
+ src_id=node_map[p_node];
+ } else {
+ if (nodepath_map.has(p_node)) {
+ src_id=FLAG_ID_IS_PATH|nodepath_map[p_node];
+ } else {
+ int sidx=nodepath_map.size();
+ nodepath_map[p_node]=sidx;
+ src_id=FLAG_ID_IS_PATH|sidx;
+ }
+ }
+
+
+
+ int target_id;
+
+ if (node_map.has(n)) {
+ target_id=node_map[n];
+ } else {
+ if (nodepath_map.has(n)) {
+ target_id=FLAG_ID_IS_PATH|nodepath_map[n];
+ } else {
+ int sidx=nodepath_map.size();
+ nodepath_map[n]=sidx;
+ target_id=FLAG_ID_IS_PATH|sidx;
+ }
+ }
+
ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
+ cd.from=src_id;
+ cd.to=target_id;
cd.method=_nm_get_string(c.method,name_map);
cd.signal=_nm_get_string(c.signal,name_map);
cd.flags=c.flags;
@@ -392,7 +816,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName
for(int i=0;i<p_node->get_child_count();i++) {
Node *c=p_node->get_child(i);
- Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map);
+ Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map,nodepath_map);
if (err)
return err;
}
@@ -401,7 +825,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName
}
-Error PackedScene::pack(Node *p_scene) {
+Error SceneState::pack(Node *p_scene) {
ERR_FAIL_NULL_V( p_scene, ERR_INVALID_PARAMETER );
@@ -412,14 +836,27 @@ Error PackedScene::pack(Node *p_scene) {
Map<StringName,int> name_map;
HashMap<Variant,int,VariantHasher> variant_map;
Map<Node*,int> node_map;
+ Map<Node*,int> nodepath_map;
+
+ //if using scene inheritance, pack the scene it inherits from
+ if (scene->get_scene_inherited_state().is_valid()) {
+ String path = scene->get_scene_inherited_state()->get_path();
+ Ref<PackedScene> instance = ResourceLoader::load(path);
+ if (instance.is_valid()) {
+
+ base_scene_idx=_vm_get_variant(instance,variant_map);
+ }
+ }
+ //instanced, only direct sub-scnes are supported of course
+
- Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map);
+ Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map,nodepath_map);
if (err) {
clear();
ERR_FAIL_V(err);
}
- err = _parse_connections(scene,scene,name_map,variant_map,node_map);
+ err = _parse_connections(scene,scene,name_map,variant_map,node_map,nodepath_map);
if (err) {
clear();
ERR_FAIL_V(err);
@@ -440,19 +877,177 @@ Error PackedScene::pack(Node *p_scene) {
variants[idx]=*K;
}
+ node_paths.resize(nodepath_map.size());
+ for(Map<Node*,int>::Element *E=nodepath_map.front();E;E=E->next()) {
+
+ node_paths[E->get()]=scene->get_path_to(E->key());
+ }
+
+
return OK;
}
-void PackedScene::clear() {
+void SceneState::set_path(const String &p_path) {
+
+ path=p_path;
+}
+
+String SceneState::get_path() const{
+
+ return path;
+}
+
+void SceneState::clear() {
names.clear();
variants.clear();
nodes.clear();
connections.clear();
+ node_path_cache.clear();
+ node_paths.clear();
+ editable_instances.clear();
+ base_scene_idx=-1;
}
-void PackedScene::_set_bundled_scene(const Dictionary& d) {
+Ref<SceneState> SceneState::_get_base_scene_state() const {
+
+ if (base_scene_idx>=0) {
+
+ Ref<PackedScene> ps = variants[base_scene_idx];
+ if (ps.is_valid()) {
+ return ps->get_state();
+ }
+ }
+
+ return Ref<SceneState>();
+}
+
+int SceneState::find_node_by_path(const NodePath& p_node) const {
+
+ if (!node_path_cache.has(p_node)) {
+ if (_get_base_scene_state().is_valid()) {
+ int idx = _get_base_scene_state()->find_node_by_path(p_node);
+ if (idx>=0) {
+ if (!base_scene_node_remap.has(idx)) {
+ int ridx = nodes.size() + base_scene_node_remap.size();
+ base_scene_node_remap[ridx]=idx;
+ }
+
+ return base_scene_node_remap[idx];
+ }
+ }
+ return -1;
+ }
+
+ int nid = node_path_cache[p_node];
+
+ if (_get_base_scene_state().is_valid() && !base_scene_node_remap.has(nid)) {
+ //for nodes that _do_ exist in current scene, still try to look for
+ //the node in the instanced scene, as a property may be missing
+ //from the local one
+ int idx = _get_base_scene_state()->find_node_by_path(p_node);
+ base_scene_node_remap[nid]=idx;
+
+ }
+
+ return nid;
+}
+Variant SceneState::get_property_value(int p_node, const StringName& p_property, bool &found) const {
+
+ found=false;
+
+ ERR_FAIL_COND_V(p_node<0,Variant());
+
+ if (p_node<nodes.size()) {
+ //find in built-in nodes
+ int pc = nodes[p_node].properties.size();
+ const StringName* namep = names.ptr();
+
+ const NodeData::Property *p=nodes[p_node].properties.ptr();
+ for(int i=0;i<pc;i++) {
+ if (p_property==namep[p[i].name]) {
+ found=true;
+ return variants[p[i].value];
+ }
+ }
+ }
+
+ //property not found, try on instance
+
+ if (base_scene_node_remap.has(p_node)) {
+ return _get_base_scene_state()->get_property_value(base_scene_node_remap[p_node],p_property,found);
+ }
+
+ return Variant();
+}
+
+bool SceneState::is_node_in_group(int p_node,const StringName& p_group) const {
+
+ ERR_FAIL_COND_V(p_node<0,false);
+
+ if (p_node<nodes.size()) {
+ const StringName* namep = names.ptr();
+ for(int i=0;i<nodes[p_node].groups.size();i++) {
+ if (namep[nodes[p_node].groups[i]]==p_group)
+ return true;
+ }
+ }
+
+ if (base_scene_node_remap.has(p_node)) {
+ return _get_base_scene_state()->is_node_in_group(base_scene_node_remap[p_node],p_group);
+ }
+
+ return false;
+}
+
+bool SceneState::disable_placeholders=false;
+
+void SceneState::set_disable_placeholders(bool p_disable) {
+
+ disable_placeholders=p_disable;
+}
+
+bool SceneState::is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const {
+
+ ERR_FAIL_COND_V(p_node<0,false);
+ ERR_FAIL_COND_V(p_to_node<0,false);
+
+ if (p_node<nodes.size() && p_to_node<nodes.size()) {
+
+ int signal_idx=-1;
+ int method_idx=-1;
+ for(int i=0;i<names.size();i++) {
+ if (names[i]==p_signal) {
+ signal_idx=i;
+ } else if (names[i]==p_to_method) {
+ method_idx=i;
+ }
+ }
+
+ if (signal_idx>=0 && method_idx>=0) {
+ //signal and method strings are stored..
+
+ for(int i=0;i<connections.size();i++) {
+
+ if (connections[i].from==p_node && connections[i].to==p_to_node && connections[i].signal==signal_idx && connections[i].method==method_idx) {
+
+ return true;
+ }
+ }
+ }
+ }
+
+ if (base_scene_node_remap.has(p_node) && base_scene_node_remap.has(p_to_node)) {
+ return _get_base_scene_state()->is_connection(base_scene_node_remap[p_node],p_signal,base_scene_node_remap[p_to_node],p_to_method);
+ }
+
+ return false;
+
+}
+
+
+void SceneState::set_bundled_scene(const Dictionary& d) {
ERR_FAIL_COND( !d.has("names"));
@@ -463,6 +1058,15 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) {
ERR_FAIL_COND( !d.has("conns"));
// ERR_FAIL_COND( !d.has("path"));
+ int version=1;
+ if (d.has("version"))
+ version=d["version"];
+
+ if (version>PACK_VERSION) {
+ ERR_EXPLAIN("Save format version too new!");
+ ERR_FAIL();
+ }
+
DVector<String> snames = d["names"];
if (snames.size()) {
@@ -540,11 +1144,34 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) {
}
+ Array np;
+ if (d.has("node_paths")) {
+ np=d["node_paths"];
+ }
+ node_paths.resize(np.size());
+ for(int i=0;i<np.size();i++) {
+ node_paths[i]=np[i];
+ }
+
+ Array ei;
+ if (d.has("editable_instances")) {
+ ei=d["editable_instances"];
+ }
+
+ if (d.has("base_scene")) {
+ base_scene_idx=d["base_scene"];
+ }
+
+ editable_instances.resize(ei.size());
+ for(int i=0;i<editable_instances.size();i++) {
+ editable_instances[i]=ei[i];
+ }
+
// path=d["path"];
}
-Dictionary PackedScene::_get_bundled_scene() const {
+Dictionary SceneState::get_bundled_scene() const {
DVector<String> rnames;
rnames.resize(names.size());
@@ -605,7 +1232,25 @@ Dictionary PackedScene::_get_bundled_scene() const {
}
d["conns"]=rconns;
- d["version"]=1;
+
+ Array rnode_paths;
+ rnode_paths.resize(node_paths.size());
+ for(int i=0;i<node_paths.size();i++) {
+ rnode_paths[i]=node_paths[i];
+ }
+ d["node_paths"]=rnode_paths;
+
+ Array reditable_instances;
+ reditable_instances.resize(editable_instances.size());
+ for(int i=0;i<editable_instances.size();i++) {
+ reditable_instances[i]=editable_instances[i];
+ }
+ d["editable_instances"]=reditable_instances;
+ if (base_scene_idx>=0) {
+ d["base_scene"]=base_scene_idx;
+ }
+
+ d["version"]=PACK_VERSION;
// d["path"]=path;
@@ -614,10 +1259,264 @@ Dictionary PackedScene::_get_bundled_scene() const {
}
+int SceneState::get_node_count() const {
+
+ return nodes.size();
+}
+
+StringName SceneState::get_node_type(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ if (nodes[p_idx].type==TYPE_INSTANCED)
+ return StringName();
+ return names[nodes[p_idx].type];
+}
+
+StringName SceneState::get_node_name(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ return names[nodes[p_idx].name];
+}
+
+Ref<PackedScene> SceneState::get_node_instance(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Ref<PackedScene>());
+ if (nodes[p_idx].instance>=0) {
+ return variants[nodes[p_idx].instance];
+ } else if (nodes[p_idx].parent<=0 || nodes[p_idx].parent==NO_PARENT_SAVED) {
+
+ if (base_scene_idx>=0) {
+ return variants[base_scene_idx];
+ }
+ }
+
+ return Ref<PackedScene>();
+
+
+}
+Vector<StringName> SceneState::get_node_groups(int p_idx) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Vector<StringName>());
+ Vector<StringName> groups;
+ for(int i=0;i<nodes[p_idx].groups.size();i++) {
+ groups.push_back(names[nodes[p_idx].groups[i]]);
+ }
+ return groups;
+}
+
+
+NodePath SceneState::get_node_path(int p_idx,bool p_for_parent) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath());
+
+ if (nodes[p_idx].parent<0 || nodes[p_idx].parent==NO_PARENT_SAVED) {
+ if (p_for_parent) {
+ return NodePath();
+ } else {
+ return NodePath(".");
+ }
+ }
+
+ Vector<StringName> sub_path;
+ NodePath base_path;
+ int nidx=p_idx;
+ while(true) {
+ if (nodes[nidx].parent==NO_PARENT_SAVED || nodes[nidx].parent<0) {
+
+ sub_path.insert(0,".");
+ break;
+ }
+
+ if (!p_for_parent || p_idx!=nidx) {
+ sub_path.insert(0,names[nodes[nidx].name]);
+ }
+
+ if (nodes[nidx].parent&FLAG_ID_IS_PATH) {
+ base_path=node_paths[nodes[nidx].parent&FLAG_MASK];
+ break;
+ } else {
+ nidx=nodes[nidx].parent&FLAG_MASK;
+ }
+ }
+
+ for(int i=0;i<base_path.get_name_count();i++) {
+ StringName sn = base_path.get_name(i);
+ sub_path.insert(0,base_path.get_name(i));
+ }
+
+ if (sub_path.empty()) {
+ return NodePath(".");
+ }
+
+ return NodePath(sub_path,false);
+
+}
+
+int SceneState::get_node_property_count(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),-1);
+ return nodes[p_idx].properties.size();
+
+}
+StringName SceneState::get_node_property_name(int p_idx,int p_prop) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),StringName());
+ return names[nodes[p_idx].properties[p_prop].name];
+
+}
+Variant SceneState::get_node_property_value(int p_idx,int p_prop) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Variant());
+ ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),Variant());
+
+ return variants[nodes[p_idx].properties[p_prop].value];
+}
+
+
+NodePath SceneState::get_node_owner_path(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath());
+ if (nodes[p_idx].owner<0 || nodes[p_idx].owner==NO_PARENT_SAVED)
+ return NodePath(); //root likely
+ if (nodes[p_idx].owner&FLAG_ID_IS_PATH) {
+ return node_paths[nodes[p_idx].owner&FLAG_MASK];
+ } else {
+ return get_node_path(nodes[p_idx].owner&FLAG_MASK);
+ }
+}
+
+int SceneState::get_connection_count() const {
+
+ return connections.size();
+}
+NodePath SceneState::get_connection_source(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath());
+ if (connections[p_idx].from&FLAG_ID_IS_PATH) {
+ return node_paths[connections[p_idx].from&FLAG_MASK];
+ } else {
+ return get_node_path(connections[p_idx].from&FLAG_MASK);
+ }
+
+}
+
+StringName SceneState::get_connection_signal(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName());
+ return names[connections[p_idx].signal];
+
+}
+NodePath SceneState::get_connection_target(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath());
+ if (connections[p_idx].to&FLAG_ID_IS_PATH) {
+ return node_paths[connections[p_idx].to&FLAG_MASK];
+ } else {
+ return get_node_path(connections[p_idx].to&FLAG_MASK);
+ }
+
+}
+StringName SceneState::get_connection_method(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName());
+ return names[connections[p_idx].method];
+
+}
+int SceneState::get_connection_flags(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),-1);
+ return connections[p_idx].flags;
+}
+
+Array SceneState::get_connection_binds(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),-1);
+ Array binds;
+ for(int i=0;i<connections[p_idx].binds.size();i++) {
+ binds.push_back(variants[connections[p_idx].binds[i]]);
+ }
+ return binds;
+}
+
+Vector<NodePath> SceneState::get_editable_instances() const {
+ return editable_instances;
+}
+
+
+SceneState::SceneState() {
+
+ base_scene_idx=-1;
+}
+
+
+////////////////
+
+
+
+void PackedScene::_set_bundled_scene(const Dictionary& d) {
+
+ state->set_bundled_scene(d);
+}
+
+Dictionary PackedScene::_get_bundled_scene() const {
+
+ return state->get_bundled_scene();
+}
+
+
+Error PackedScene::pack(Node *p_scene) {
+
+ return state->pack(p_scene);
+}
+
+void PackedScene::clear() {
+
+ state->clear();
+}
+
+bool PackedScene::can_instance() const {
+
+ return state->can_instance();
+}
+
+Node *PackedScene::instance(bool p_gen_edit_state) const {
+
+#ifndef TOOLS_ENABLED
+ if (p_gen_edit_state) {
+ ERR_EXPLAIN("Edit state is only for editors, does not work without tools compiled");
+ ERR_FAIL_COND_V(p_gen_edit_state,NULL);
+ }
+#endif
+
+ Node *s = state->instance(p_gen_edit_state);
+ if (!s)
+ return NULL;
+
+ if (p_gen_edit_state) {
+ s->set_scene_instance_state(state);
+ }
+
+ if (get_path()!="" && get_path().find("::")==-1)
+ s->set_filename(get_path());
+
+
+ s->notification(Node::NOTIFICATION_INSTANCED);
+
+ return s;
+}
+
+Ref<SceneState> PackedScene::get_state() {
+
+ return state;
+}
+
+void PackedScene::set_path(const String& p_path,bool p_take_over) {
+
+ state->set_path(p_path);
+ Resource::set_path(p_path,p_take_over);
+}
+
void PackedScene::_bind_methods() {
ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&PackedScene::instance,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("instance:Node","gen_edit_state"),&PackedScene::instance,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("can_instance"),&PackedScene::can_instance);
ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&PackedScene::_set_bundled_scene);
ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&PackedScene::_get_bundled_scene);
@@ -628,5 +1527,6 @@ void PackedScene::_bind_methods() {
PackedScene::PackedScene() {
+ state = Ref<SceneState>( memnew( SceneState ));
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 0546addd3e..3956d2abe4 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -32,26 +32,27 @@
#include "resource.h"
#include "scene/main/node.h"
-//changes:
-//1-make the InstanceState a reference inside the resource that can be shared
-//2-make the instance "editable" with a flag, save here and load here, no need for property
-//3-properly save modifications in sub-scene
-//4-add scene inheritance
-//5-chain of instance states in editor? (to check what was modified)
-//6-saving will be hell
+class SceneState : public Reference {
-class PackedScene : public Resource {
-
- OBJ_TYPE( PackedScene, Resource );
- RES_BASE_EXTENSION("scn");
+ OBJ_TYPE( SceneState, Reference );
Vector<StringName> names;
Vector<Variant> variants;
+ Vector<NodePath> node_paths;
+ Vector<NodePath> editable_instances;
+ mutable HashMap<NodePath,int> node_path_cache;
+ mutable Map<int,int> base_scene_node_remap;
- //missing - instances
- //missing groups
- //missing - owner
- //missing - override names and values
+ int base_scene_idx;
+
+ enum {
+ FLAG_ID_IS_PATH=(1<<30),
+ FLAG_INSTANCE_IS_PLACEHOLDER=(1<<30),
+ FLAG_MASK=(1<<24)-1,
+ NO_PARENT_SAVED=0x7FFFFFFF,
+ TYPE_INSTANCED=0x7FFFFFFF,
+
+ };
struct NodeData {
@@ -68,9 +69,15 @@ class PackedScene : public Resource {
};
Vector<Property> properties;
- Vector<int> groups;
+ Vector<int> groups;
+
};
+ struct PackState {
+ Ref<SceneState> state;
+ int node;
+ PackState() { node=-1; }
+ };
Vector<NodeData> nodes;
@@ -86,16 +93,78 @@ class PackedScene : public Resource {
Vector<ConnectionData> connections;
- Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
- Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
+ Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
+ Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
+
+ String path;
+
+ _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
+
+ static bool disable_placeholders;
+public:
+
+ static void set_disable_placeholders(bool p_disable);
+
+ int find_node_by_path(const NodePath& p_node) const;
+ Variant get_property_value(int p_node,const StringName& p_property,bool &found) const;
+ bool is_node_in_group(int p_node,const StringName& p_group) const;
+ bool is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const;
+
+
+ void set_bundled_scene(const Dictionary& p_dictionary);
+ Dictionary get_bundled_scene() const;
+
+ Error pack(Node *p_scene);
+
+ void set_path(const String &p_path);
+ String get_path() const;
+
+ void clear();
+
+ bool can_instance() const;
+ Node *instance(bool p_gen_edit_state=false) const;
+
+
+ //build-unbuild API
+
+ int get_node_count() const;
+ StringName get_node_type(int p_idx) const;
+ StringName get_node_name(int p_idx) const;
+ NodePath get_node_path(int p_idx,bool p_for_parent=false) const;
+ NodePath get_node_owner_path(int p_idx) const;
+ Ref<PackedScene> get_node_instance(int p_idx) const;
+ Vector<StringName> get_node_groups(int p_idx) const;
+
+ int get_node_property_count(int p_idx) const;
+ StringName get_node_property_name(int p_idx,int p_prop) const;
+ Variant get_node_property_value(int p_idx,int p_prop) const;
+
+ int get_connection_count() const;
+ NodePath get_connection_source(int p_idx) const;
+ StringName get_connection_signal(int p_idx) const;
+ NodePath get_connection_target(int p_idx) const;
+ StringName get_connection_method(int p_idx) const;
+ int get_connection_flags(int p_idx) const;
+ Array get_connection_binds(int p_idx) const;
+
+ Vector<NodePath> get_editable_instances() const;
+
+ SceneState();
+};
+
+class PackedScene : public Resource {
+
+ OBJ_TYPE(PackedScene, Resource );
+ RES_BASE_EXTENSION("scn");
+
+ Ref<SceneState> state;
void _set_bundled_scene(const Dictionary& p_scene);
Dictionary _get_bundled_scene() const;
protected:
-
static void _bind_methods();
public:
@@ -107,7 +176,12 @@ public:
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
+ virtual void set_path(const String& p_path,bool p_take_over=false);
+
+ Ref<SceneState> get_state();
+
PackedScene();
+
};
#endif // SCENE_PRELOADER_H
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
new file mode 100644
index 0000000000..8403c06ad1
--- /dev/null
+++ b/scene/resources/scene_format_text.cpp
@@ -0,0 +1,792 @@
+#include "scene_format_text.h"
+
+#include "globals.h"
+#include "version.h"
+#include "os/dir_access.h"
+
+#define FORMAT_VERSION 1
+
+void ResourceFormatSaverTextInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) {
+
+ if (r_ok)
+ *r_ok=false;
+
+ if (p_name!=String()) {
+ f->store_string(p_name+" = ");
+ }
+
+ switch( p_property.get_type() ) {
+
+ case Variant::NIL: {
+ f->store_string("null");
+ } break;
+ case Variant::BOOL: {
+
+ f->store_string(p_property.operator bool() ? "true":"false" );
+ } break;
+ case Variant::INT: {
+
+ f->store_string( itos(p_property.operator int()) );
+ } break;
+ case Variant::REAL: {
+
+ f->store_string( rtoss(p_property.operator real_t()) );
+ } break;
+ case Variant::STRING: {
+
+ String str=p_property;
+
+ str="\""+str.c_escape()+"\"";
+ f->store_string( str );
+ } break;
+ case Variant::VECTOR2: {
+
+ Vector2 v = p_property;
+ f->store_string("Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" );
+ } break;
+ case Variant::RECT2: {
+
+ Rect2 aabb = p_property;
+ f->store_string("Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" );
+
+ } break;
+ case Variant::VECTOR3: {
+
+ Vector3 v = p_property;
+ f->store_string("Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )");
+ } break;
+ case Variant::PLANE: {
+
+ Plane p = p_property;
+ f->store_string("Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" );
+
+ } break;
+ case Variant::_AABB: {
+
+ AABB aabb = p_property;
+ f->store_string("AABB( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z)+" )" );
+
+ } break;
+ case Variant::QUAT: {
+
+ Quat quat = p_property;
+ f->store_string("Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )");
+
+ } break;
+ case Variant::MATRIX32: {
+
+ String s="Matrix32( ";
+ Matrix32 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ f->store_string(s+" )");
+
+ } break;
+ case Variant::MATRIX3: {
+
+ String s="Matrix3( ";
+ Matrix3 m3 = p_property;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ f->store_string(s+" )");
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ String s="Transform( ";
+ Transform t = p_property;
+ Matrix3 &m3 = t.basis;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
+
+ f->store_string(s+" )");
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ Color c = p_property;
+ f->store_string("Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )");
+
+ } break;
+ case Variant::IMAGE: {
+
+
+ Image img=p_property;
+
+ if (img.empty()) {
+ f->store_string("RawImage()");
+ break;
+ }
+
+ String imgstr="RawImage( ";
+ imgstr+=itos(img.get_width());
+ imgstr+=", "+itos(img.get_height());
+ imgstr+=", "+itos(img.get_mipmaps());
+ imgstr+=", ";
+
+ switch(img.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: imgstr+="GRAYSCALE"; break;
+ case Image::FORMAT_INTENSITY: imgstr+="INTENSITY"; break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: imgstr+="GRAYSCALE_ALPHA"; break;
+ case Image::FORMAT_RGB: imgstr+="RGB"; break;
+ case Image::FORMAT_RGBA: imgstr+="RGBA"; break;
+ case Image::FORMAT_INDEXED : imgstr+="INDEXED"; break;
+ case Image::FORMAT_INDEXED_ALPHA: imgstr+="INDEXED_ALPHA"; break;
+ case Image::FORMAT_BC1: imgstr+="BC1"; break;
+ case Image::FORMAT_BC2: imgstr+="BC2"; break;
+ case Image::FORMAT_BC3: imgstr+="BC3"; break;
+ case Image::FORMAT_BC4: imgstr+="BC4"; break;
+ case Image::FORMAT_BC5: imgstr+="BC5"; break;
+ case Image::FORMAT_PVRTC2: imgstr+="PVRTC2"; break;
+ case Image::FORMAT_PVRTC2_ALPHA: imgstr+="PVRTC2_ALPHA"; break;
+ case Image::FORMAT_PVRTC4: imgstr+="PVRTC4"; break;
+ case Image::FORMAT_PVRTC4_ALPHA: imgstr+="PVRTC4_ALPHA"; break;
+ case Image::FORMAT_ETC: imgstr+="ETC"; break;
+ case Image::FORMAT_ATC: imgstr+="ATC"; break;
+ case Image::FORMAT_ATC_ALPHA_EXPLICIT: imgstr+="ATC_ALPHA_EXPLICIT"; break;
+ case Image::FORMAT_ATC_ALPHA_INTERPOLATED: imgstr+="ATC_ALPHA_INTERPOLATED"; break;
+ case Image::FORMAT_CUSTOM: imgstr+="CUSTOM"; break;
+ default: {}
+ }
+
+
+ String s;
+
+ DVector<uint8_t> data = img.get_data();
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ s+=str;
+ }
+
+ imgstr+=", ";
+ f->store_string(imgstr);
+ f->store_string(s);
+ f->store_string(" )");
+ } break;
+ case Variant::NODE_PATH: {
+
+ String str=p_property;
+
+ str="NodePath(\""+str.c_escape()+"\")";
+ f->store_string(str);
+
+ } break;
+
+ case Variant::OBJECT: {
+
+ RES res = p_property;
+ if (res.is_null()) {
+ f->store_string("null");
+ if (r_ok)
+ *r_ok=true;
+
+ break; // don't save it
+ }
+
+ if (external_resources.has(res)) {
+
+ f->store_string("ExtResource( "+itos(external_resources[res]+1)+" )");
+ } else {
+
+ if (internal_resources.has(res)) {
+ f->store_string("SubResource( "+itos(internal_resources[res])+" )");
+ } else if (res->get_path().length() && res->get_path().find("::")==-1) {
+
+ //external resource
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ f->store_string("Resource( \""+path+"\" )");
+ } else {
+ f->store_string("null");
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_BREAK(true);
+ //internal resource
+ }
+ }
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ f->store_string("InputEvent()"); //will be added later
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = p_property;
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+ keys.sort();
+
+ f->store_string("{ ");
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+ bool ok;
+ write_property("",E->get(),&ok);
+ ERR_CONTINUE(!ok);
+
+ f->store_string(":");
+ write_property("",dict[E->get()],&ok);
+ if (!ok)
+ write_property("",Variant()); //at least make the file consistent..
+ if (E->next())
+ f->store_string(", ");
+ }
+
+
+ f->store_string(" }");
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ f->store_string("[ ");
+ Array array = p_property;
+ int len=array.size();
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ write_property("",array[i]);
+
+
+ }
+ f->store_string(" ]");
+
+ } break;
+
+ case Variant::RAW_ARRAY: {
+
+ f->store_string("RawArray( ");
+ String s;
+ DVector<uint8_t> data = p_property;
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ uint8_t byte = ptr[i];
+ const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ char str[3]={ hex[byte>>4], hex[byte&0xF], 0};
+ f->store_string(str);
+
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ f->store_string("IntArray( ");
+ DVector<int> data = p_property;
+ int len = data.size();
+ DVector<int>::Read r = data.read();
+ const int *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+
+ f->store_string(itos(ptr[i]));
+ }
+
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ f->store_string("FloatArray( ");
+ DVector<real_t> data = p_property;
+ int len = data.size();
+ DVector<real_t>::Read r = data.read();
+ const real_t *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i]));
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ f->store_string("StringArray( ");
+ DVector<String> data = p_property;
+ int len = data.size();
+ DVector<String>::Read r = data.read();
+ const String *ptr=r.ptr();;
+ String s;
+ //write_string("\n");
+
+
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ String str=ptr[i];
+ f->store_string(""+str.c_escape()+"\"");
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ f->store_string("Vector2Array( ");
+ DVector<Vector2> data = p_property;
+ int len = data.size();
+ DVector<Vector2>::Read r = data.read();
+ const Vector2 *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) );
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ f->store_string("Vector3Array( ");
+ DVector<Vector3> data = p_property;
+ int len = data.size();
+ DVector<Vector3>::Read r = data.read();
+ const Vector3 *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+ f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) );
+ }
+
+ f->store_string(" )");
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ f->store_string("ColorArray( ");
+
+ DVector<Color> data = p_property;
+ int len = data.size();
+ DVector<Color>::Read r = data.read();
+ const Color *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ f->store_string(", ");
+
+ f->store_string(rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) );
+
+ }
+ f->store_string(" )");
+
+ } break;
+ default: {}
+
+ }
+
+ if (r_ok)
+ *r_ok=true;
+
+}
+
+
+void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null() || external_resources.has(res))
+ return;
+
+ if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
+ int index = external_resources.size();
+ external_resources[res]=index;
+ return;
+ }
+
+ if (resource_set.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list( &property_list );
+ property_list.sort();
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ PropertyInfo pi=I->get();
+
+ if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
+
+ Variant v=res->get(I->get().name);
+ _find_resources(v);
+ }
+
+ I=I->next();
+ }
+
+ resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
+ saved_resources.push_back(res);
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+
+
+
+Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ if (p_path.ends_with(".tscn")) {
+ packed_scene=p_resource;
+ }
+
+ Error err;
+ f = FileAccess::open(p_path, FileAccess::WRITE,&err);
+ ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
+ FileAccessRef _fref(f);
+
+ local_path = Globals::get_singleton()->localize_path(p_path);
+
+ relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
+ takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
+ if (!p_path.begins_with("res://")) {
+ takeover_paths=false;
+ }
+
+ // save resources
+ _find_resources(p_resource,true);
+
+ if (packed_scene.is_valid()) {
+ //add instances to external resources if saving a packed scene
+ for(int i=0;i<packed_scene->get_state()->get_node_count();i++) {
+ Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i);
+ if (instance.is_valid() && !external_resources.has(instance)) {
+ int index = external_resources.size();
+ external_resources[instance]=index;
+ }
+ }
+ }
+
+
+ ERR_FAIL_COND_V(err!=OK,err);
+
+ {
+ String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource ";
+ if (packed_scene.is_null())
+ title+="type=\""+p_resource->get_type()+"\" ";
+ int load_steps=saved_resources.size()+external_resources.size();
+ //if (packed_scene.is_valid()) {
+ // load_steps+=packed_scene->get_node_count();
+ //}
+ //no, better to not use load steps from nodes, no point to that
+
+ if (load_steps>1) {
+ title+="load_steps="+itos(load_steps)+" ";
+ }
+ title+="format="+itos(FORMAT_VERSION)+"";
+ //title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";
+
+ f->store_string(title);
+ f->store_line("]\n"); //one empty line
+ }
+
+
+ for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
+
+ String p = E->key()->get_path();
+
+ f->store_string("[ext_resource path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" id="+itos(E->get()+1)+"]\n"); //bundled
+ }
+
+ if (external_resources.size())
+ f->store_line(String()); //separate
+
+ Set<int> used_indices;
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) {
+
+ if (res->get_subindex()!=0) {
+ if (used_indices.has(res->get_subindex())) {
+ res->set_subindex(0); //repeated
+ } else {
+ used_indices.insert(res->get_subindex());
+ }
+ }
+ }
+ }
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ ERR_CONTINUE(!resource_set.has(res));
+ bool main = (E->next()==NULL);
+
+ if (main && packed_scene.is_valid())
+ break; //save as a scene
+
+ if (main) {
+ f->store_line("[resource]\n");
+ } else {
+ String line="[sub_resource ";
+ if (res->get_subindex()==0) {
+ int new_subindex=1;
+ if (used_indices.size()) {
+ new_subindex=used_indices.back()->get()+1;
+ }
+
+ res->set_subindex(new_subindex);
+ used_indices.insert(new_subindex);
+ }
+
+ int idx = res->get_subindex();
+ line+="type=\""+res->get_type()+"\" id="+itos(idx);
+ f->store_line(line+"]\n");
+ if (takeover_paths) {
+ res->set_path(p_path+"::"+itos(idx),true);
+ }
+
+ internal_resources[res]=idx;
+
+ }
+
+
+ List<PropertyInfo> property_list;
+ res->get_property_list(&property_list);
+// property_list.sort();
+ for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
+
+
+ if (skip_editor && PE->get().name.begins_with("__editor"))
+ continue;
+
+ if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ String name = PE->get().name;
+ Variant value = res->get(name);
+
+
+ if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
+ continue;
+
+ if (PE->get().type==Variant::OBJECT && value.is_zero())
+ continue;
+
+ write_property(name,value);
+ f->store_string("\n");
+ }
+
+
+ }
+
+ f->store_string("\n");
+
+ }
+
+ if (packed_scene.is_valid()) {
+ //if this is a scene, save nodes and connections!
+ Ref<SceneState> state = packed_scene->get_state();
+ for(int i=0;i<state->get_node_count();i++) {
+
+ StringName type = state->get_node_type(i);
+ StringName name = state->get_node_name(i);
+ NodePath path = state->get_node_path(i,true);
+ NodePath owner = state->get_node_owner_path(i);
+ Ref<PackedScene> instance = state->get_node_instance(i);
+ Vector<StringName> groups = state->get_node_groups(i);
+
+ String header="[node";
+ header+=" name=\""+String(name)+"\"";
+ if (type!=StringName()) {
+ header+=" type=\""+String(type)+"\"";
+ }
+ if (path!=NodePath()) {
+ header+=" parent=\""+String(path.simplified())+"\"";
+ }
+ if (owner!=NodePath() && owner!=NodePath(".")) {
+ header+=" owner=\""+String(owner.simplified())+"\"";
+ }
+
+ if (groups.size()) {
+ String sgroups=" groups=[ ";
+ for(int j=0;j<groups.size();j++) {
+ if (j>0)
+ sgroups+=", ";
+ sgroups+="\""+groups[i].operator String().c_escape()+"\"";
+ }
+ sgroups+=" ]";
+ header+=sgroups;
+ }
+
+ f->store_string(header);
+
+ if (instance.is_valid()) {
+ f->store_string(" instance=");
+ write_property("",instance);
+ }
+
+ f->store_line("]\n");
+
+ for(int j=0;j<state->get_node_property_count(i);j++) {
+
+ write_property(state->get_node_property_name(i,j),state->get_node_property_value(i,j));
+ f->store_line(String());
+
+ }
+
+ if (state->get_node_property_count(i)) {
+ //add space
+ f->store_line(String());
+ }
+
+ }
+
+ for(int i=0;i<state->get_connection_count();i++) {
+
+ String connstr="[connection";
+ connstr+=" signal=\""+String(state->get_connection_signal(i))+"\"";
+ connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\"";
+ connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\"";
+ connstr+=" method=\""+String(state->get_connection_method(i))+"\"";
+ int flags = state->get_connection_flags(i);
+ if (flags!=Object::CONNECT_PERSIST) {
+ connstr+=" flags="+itos(flags);
+ }
+
+ Array binds=state->get_connection_binds(i);
+ f->store_string(connstr);
+ if (binds.size()) {
+ f->store_string(" binds=");
+ write_property("",binds);
+ }
+
+ f->store_line("]\n");
+ }
+
+ f->store_line(String());
+
+ Vector<NodePath> editable_instances = state->get_editable_instances();
+ for(int i=0;i<editable_instances.size();i++) {
+ f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]");
+ }
+ }
+
+ if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+ f->close();
+ return ERR_CANT_CREATE;
+ }
+
+ f->close();
+ //memdelete(f);
+
+ return OK;
+}
+
+
+
+Error ResourceFormatSaverText::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ if (p_path.ends_with(".sct") && p_resource->get_type()!="PackedScene") {
+ return ERR_FILE_UNRECOGNIZED;
+ }
+
+ ResourceFormatSaverTextInstance saver;
+ return saver.save(p_path,p_resource,p_flags);
+
+}
+
+bool ResourceFormatSaverText::recognize(const RES& p_resource) const {
+
+
+ return true; // all recognized!
+}
+void ResourceFormatSaverText::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
+
+ p_extensions->push_back("tres"); //text resource
+ if (p_resource->get_type()=="PackedScene")
+ p_extensions->push_back("tscn"); //text scene
+
+}
+
+ResourceFormatSaverText* ResourceFormatSaverText::singleton=NULL;
+ResourceFormatSaverText::ResourceFormatSaverText() {
+ singleton=this;
+}
diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h
new file mode 100644
index 0000000000..576a78d183
--- /dev/null
+++ b/scene/resources/scene_format_text.h
@@ -0,0 +1,46 @@
+#ifndef SCENE_FORMAT_TEXT_H
+#define SCENE_FORMAT_TEXT_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+#include "scene/resources/packed_scene.h"
+
+class ResourceFormatSaverTextInstance {
+
+ String local_path;
+
+ Ref<PackedScene> packed_scene;
+
+ bool takeover_paths;
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ FileAccess *f;
+ Set<RES> resource_set;
+ List<RES> saved_resources;
+ Map<RES,int> external_resources;
+ Map<RES,int> internal_resources;
+
+ void _find_resources(const Variant& p_variant,bool p_main=false);
+ void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL);
+
+public:
+
+ Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+
+
+};
+
+class ResourceFormatSaverText : public ResourceFormatSaver {
+public:
+ static ResourceFormatSaverText* singleton;
+ virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+ virtual bool recognize(const RES& p_resource) const;
+ virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
+
+ ResourceFormatSaverText();
+};
+
+
+#endif // SCENE_FORMAT_TEXT_H
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
index a0766ff317..49a1bdccb1 100644
--- a/scene/resources/shader_graph.cpp
+++ b/scene/resources/shader_graph.cpp
@@ -80,12 +80,15 @@ void ShaderGraph::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND((conns.size()%3)!=0);
for(int j=0;j<conns.size();j+=3) {
-
SourceSlot ss;
int ls=conns[j+0];
- ss.id=conns[j+1];
- ss.slot=conns[j+2];
- n.connections[ls]=ss;
+ if (ls == SLOT_DEFAULT_VALUE) {
+ n.defaults[conns[j+1]]=conns[j+2];
+ } else {
+ ss.id=conns[j+1];
+ ss.slot=conns[j+2];
+ n.connections[ls]=ss;
+ }
}
shader[t].node_map[n.id]=n;
@@ -114,7 +117,7 @@ Dictionary ShaderGraph::_get_data() const {
data[idx+4]=E->get().param2;
Array conns;
- conns.resize(E->get().connections.size()*3);
+ conns.resize(E->get().connections.size()*3+E->get().defaults.size()*3);
int idx2=0;
for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
@@ -123,6 +126,14 @@ Dictionary ShaderGraph::_get_data() const {
conns[idx2+2]=F->get().slot;
idx2+=3;
}
+ for(Map<int,Variant>::Element*F=E->get().defaults.front();F;F=F->next()) {
+
+ conns[idx2+0]=SLOT_DEFAULT_VALUE;
+ conns[idx2+1]=F->key();
+ conns[idx2+2]=F->get();
+ idx2+=3;
+ }
+
data[idx+5]=conns;
idx+=6;
}
@@ -142,6 +153,15 @@ ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
return shader[p_type].error;
}
+int ShaderGraph::node_count(ShaderType p_which, int p_type)
+{
+ int count=0;
+ for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next())
+ if (E->get().type==p_type)
+ count++;
+ return count;
+}
+
void ShaderGraph::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
@@ -155,6 +175,9 @@ void ShaderGraph::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
+ ObjectTypeDB::bind_method(_MD("default_set_value","shader_type","id","param_id","value"), &ShaderGraph::default_set_value);
+ ObjectTypeDB::bind_method(_MD("default_get_value","shader_type","id","param_id"), &ShaderGraph::default_get_value);
+
ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value);
@@ -537,7 +560,7 @@ void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
- case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
+ case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
case NODE_DEFAULT_TEXTURE: {}; break;
case NODE_OUTPUT: {} break; // output (shader type dependent)
case NODE_COMMENT: {} break; // comment
@@ -683,6 +706,18 @@ void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_con
}
}
+bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id)
+{
+ for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+ if (p_dst_id == E->key() && slot_id==F->key())
+ return true;
+ }
+ }
+ return false;
+}
+
void ShaderGraph::clear(ShaderType p_type) {
@@ -824,6 +859,47 @@ float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id
return arr[1];
}
+void ShaderGraph::duplicate_nodes(ShaderType p_which, List<int> &p_nodes)
+{
+ //Create new node IDs
+ Map<int,int> duplicates = Map<int,int>();
+ int i=1;
+ for(List<int>::Element *E=p_nodes.front();E; E=E->next()) {
+ while (shader[p_which].node_map.has(i))
+ i++;
+ duplicates.insert(E->get(), i);
+ i++;
+ }
+
+ for(List<int>::Element *E = p_nodes.front();E; E=E->next()) {
+
+ const Node &n=shader[p_which].node_map[E->get()];
+ Node nn=n;
+ nn.id=duplicates.find(n.id)->get();
+ nn.pos += Vector2(0,100);
+ for (Map<int,SourceSlot>::Element *C=nn.connections.front();C;C=C->next()) {
+ SourceSlot &c=C->get();
+ if (p_nodes.find(c.id))
+ c.id=duplicates.find(c.id)->get();
+ }
+ shader[p_which].node_map[nn.id]=nn;
+ }
+ _request_update();
+}
+
+List<int> ShaderGraph::generate_ids(ShaderType p_type, int count)
+{
+ List<int> ids = List<int>();
+ int i=1;
+ while (ids.size() < count) {
+ while (shader[p_type].node_map.has(i))
+ i++;
+ ids.push_back(i);
+ i++;
+ }
+ return ids;
+}
+
void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
@@ -955,6 +1031,33 @@ ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_
return ScalarFunc(func);
}
+void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value)
+{
+ ERR_FAIL_INDEX(p_which,3);
+ ERR_FAIL_COND(!shader[p_which].node_map.has(p_id));
+ Node& n = shader[p_which].node_map[p_id];
+ if(p_value.get_type()==Variant::NIL)
+ n.defaults.erase(n.defaults.find(p_param));
+ else
+ n.defaults[p_param]=p_value;
+
+ _request_update();
+
+}
+
+Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param)
+{
+ ERR_FAIL_INDEX_V(p_which,3,Variant());
+ ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id),Variant());
+ const Node& n = shader[p_which].node_map[p_id];
+
+ if (!n.defaults.has(p_param))
+ return Variant();
+ return n.defaults[p_param];
+}
+
+
+
void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
ERR_FAIL_INDEX(p_type,3);
@@ -980,52 +1083,52 @@ ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type,
void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets){
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_colors;
- n.param2=p_offsets;
- _request_update();
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
+ Node& n = shader[p_type].node_map[p_id];
+ n.param1=p_colors;
+ n.param2=p_offsets;
+ _request_update();
}
DVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param1;
}
DVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param2;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param2;
}
void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const DVector<Vector2>& p_points) {
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_points;
- _request_update();
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ n.param1=p_points;
+ _request_update();
}
DVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param1;
}
@@ -1215,6 +1318,12 @@ Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
s["pos"]=n.pos;
s["param1"]=n.param1;
s["param2"]=n.param2;
+ Array keys;
+ for (Map<int,Variant>::Element *E=n.defaults.front();E;E=E->next()) {
+ keys.append(E->key());
+ s[E->key()]=E->get();
+ }
+ s["default_keys"]=keys;
return s;
}
@@ -1227,10 +1336,15 @@ void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_sta
ERR_FAIL_COND(!d.has("pos"));
ERR_FAIL_COND(!d.has("param1"));
ERR_FAIL_COND(!d.has("param2"));
+ ERR_FAIL_COND(!d.has("default_keys"));
+
n.pos=d["pos"];
n.param1=d["param1"];
n.param2=d["param2"];
-
+ Array keys = d["default_keys"];
+ for(int i=0;i<keys.size();i++) {
+ n.defaults[keys[i]]=d[keys[i]];
+ }
}
ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
@@ -1735,17 +1849,17 @@ void ShaderGraph::_update_shader() {
Vector<String> inputs;
int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
for(int k=0;k<max;k++) {
+ String iname;
if (!n->connections.has(k)) {
- shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS;
- failed=true;
- break;
+ iname="nd"+itos(n->id)+"sl"+itos(k)+"def";
+ } else {
+ iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
+ if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
+ inputs_used.insert(iname);
+ }
+
}
- String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
inputs.push_back(iname);
- if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
- inputs_used.insert(iname);
- }
-
}
if (failed)
@@ -1874,27 +1988,27 @@ void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector
};
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
+ CR_basis[i][1] * geometry[1][j] +
+ CR_basis[i][2] * geometry[2][j] +
+ CR_basis[i][3] * geometry[3][j]);
+ }
}
- }
/* compose the above results to get the deltas matrix */
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
+ tmp2[i][1] * tmp1[1][j] +
+ tmp2[i][2] * tmp1[2][j] +
+ tmp2[i][3] * tmp1[3][j]);
+ }
}
- }
/* extract the x deltas */
@@ -1951,6 +2065,31 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
const char *typestr[4]={"float","vec3","mat4","texture"};
#define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
+#define DEF_VEC(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ Vector3 v = p_node->defaults[slot];\
+ code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+v+");\n";\
+ }
+#define DEF_SCALAR(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ double v = p_node->defaults[slot];\
+ code+=String(typestr[0])+" "+p_inputs[slot]+"="+rtos(v)+";\n";\
+ }
+#define DEF_COLOR(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ Color col = p_node->defaults[slot];\
+ code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";\
+ }
+#define DEF_MATRIX(slot) \
+ if (p_inputs[slot].ends_with("def")){\
+ Transform xf = p_node->defaults[slot]; \
+ code+=String(typestr[3])+" "+p_inputs[slot]+"=mat4(\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";\
+ code+=");\n";\
+ }
switch(p_node->type) {
@@ -1987,9 +2126,12 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
code+=OUTNAME(p_node->id,0)+"=TIME;\n";
}break;
case NODE_SCREEN_TEX: {
+ DEF_VEC(0);
code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
}break;
case NODE_SCALAR_OP: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2009,6 +2151,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_VEC_OP: {
+ DEF_VEC(0);
+ DEF_VEC(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2026,6 +2170,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_VEC_SCALAR_OP: {
+ DEF_VEC(0);
+ DEF_SCALAR(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2037,6 +2183,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_RGB_OP: {
+ DEF_COLOR(0);
+ DEF_COLOR(1);
int op = p_node->param1;
static const char*axisn[3]={"x","y","z"};
@@ -2048,7 +2196,6 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
case RGB_OP_DIFFERENCE: {
code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
-
} break;
case RGB_OP_DARKEN: {
@@ -2119,11 +2266,15 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_XFORM_MULT: {
+ DEF_MATRIX(0);
+ DEF_MATRIX(1);
code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
}break;
case NODE_XFORM_VEC_MULT: {
+ DEF_MATRIX(0);
+ DEF_VEC(1);
bool no_translation = p_node->param1;
if (no_translation) {
@@ -2134,6 +2285,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_XFORM_VEC_INV_MULT: {
+ DEF_VEC(0);
+ DEF_MATRIX(1);
bool no_translation = p_node->param1;
if (no_translation) {
code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
@@ -2142,6 +2295,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_SCALAR_FUNC: {
+ DEF_SCALAR(0);
static const char*scalar_func_id[SCALAR_MAX_FUNC]={
"sin($)",
"cos($)",
@@ -2171,6 +2325,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
} break;
case NODE_VEC_FUNC: {
+ DEF_VEC(0);
static const char*vec_func_id[VEC_MAX_FUNC]={
"normalize($)",
"max(min($,vec3(1,1,1)),vec3(0,0,0))",
@@ -2208,44 +2363,63 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_VEC_LEN: {
+ DEF_VEC(0);
code += OUTNAME(p_node->id,0)+"=length("+p_inputs[0]+");\n";
}break;
case NODE_DOT_PROD: {
+ DEF_VEC(0);
+ DEF_VEC(1);
code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
}break;
case NODE_VEC_TO_SCALAR: {
+ DEF_VEC(0);
code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
}break;
case NODE_SCALAR_TO_VEC: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
}break;
case NODE_VEC_TO_XFORM: {
+ DEF_VEC(0);
+ DEF_VEC(1);
+ DEF_VEC(2);
+ DEF_VEC(3);
code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n";
}break;
case NODE_XFORM_TO_VEC: {
+ DEF_MATRIX(0);
code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n";
}break;
case NODE_SCALAR_INTERP: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
}break;
case NODE_VEC_INTERP: {
+ DEF_VEC(0);
+ DEF_VEC(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
}break;
case NODE_COLOR_RAMP: {
+ DEF_SCALAR(0);
static const int color_ramp_len=512;
DVector<uint8_t> cramp;
@@ -2302,6 +2476,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_CURVE_MAP: {
+ DEF_SCALAR(0);
static const int curve_map_len=256;
bool mapped[256];
zeromem(mapped,sizeof(mapped));
@@ -2406,6 +2581,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_TEXTURE_INPUT: {
+ DEF_VEC(0);
String name = p_node->param1;
String rname="rt_read_tex"+itos(p_node->id);
code +="uniform texture "+name+";";
@@ -2415,7 +2591,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_CUBEMAP_INPUT: {
-
+ DEF_VEC(0);
String name = p_node->param1;
code +="uniform cubemap "+name+";";
String rname="rt_read_tex"+itos(p_node->id);
@@ -2424,6 +2600,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
}break;
case NODE_DEFAULT_TEXTURE: {
+ DEF_VEC(0);
if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
@@ -2450,4 +2627,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}
+#undef DEF_SCALAR
+#undef DEF_COLOR
+#undef DEF_MATRIX
+#undef DEF_VEC
}
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
index fd6540a747..f867ae0388 100644
--- a/scene/resources/shader_graph.h
+++ b/scene/resources/shader_graph.h
@@ -68,7 +68,7 @@ public:
NODE_VEC_INTERP, // vec3 interpolation (with optional curve)
NODE_COLOR_RAMP, //take scalar, output vec3
NODE_CURVE_MAP, //take scalar, otput scalar
- NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
+ NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
NODE_VEC_INPUT, // vec3 uniform (assignable in material)
NODE_RGB_INPUT, // color uniform (assignable in material)
NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
@@ -120,6 +120,7 @@ private:
String _find_unique_name(const String& p_base);
+ enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
struct SourceSlot {
int id;
@@ -135,6 +136,7 @@ private:
NodeType type;
Variant param1;
Variant param2;
+ Map<int, Variant> defaults;
int id;
mutable int order; // used for sorting
int sort_order;
@@ -216,6 +218,10 @@ public:
void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
+ void duplicate_nodes(ShaderType p_which, List<int> &p_nodes);
+
+ List<int> generate_ids(ShaderType p_type, int count);
+
enum ScalarOp {
SCALAR_OP_ADD,
SCALAR_OP_SUB,
@@ -314,6 +320,9 @@ public:
VEC_MAX_FUNC
};
+ void default_set_value(ShaderType p_which,int p_id,int p_param, const Variant& p_value);
+ Variant default_get_value(ShaderType p_which,int p_id,int p_param);
+
void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
@@ -354,6 +363,8 @@ public:
void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
+ bool is_slot_connected(ShaderType p_which,int p_dst_id,int slot_id);
+
void clear(ShaderType p_which);
Variant node_get_state(ShaderType p_type, int p_node) const;
@@ -361,6 +372,8 @@ public:
GraphError get_graph_error(ShaderType p_type) const;
+ int node_count(ShaderType p_which, int p_type);
+
static int get_type_input_count(NodeType p_type);
static int get_type_output_count(NodeType p_type);
static SlotType get_type_input_type(NodeType p_type,int p_idx);