diff options
Diffstat (limited to 'scene/resources')
-rw-r--r-- | scene/resources/default_theme/default_theme.cpp | 94 | ||||
-rw-r--r-- | scene/resources/default_theme/graph_node_default.png | bin | 0 -> 289 bytes | |||
-rw-r--r-- | scene/resources/default_theme/graph_node_default_focus.png | bin | 0 -> 408 bytes | |||
-rw-r--r-- | scene/resources/default_theme/graph_node_selected.png | bin | 0 -> 738 bytes | |||
-rw-r--r-- | scene/resources/default_theme/theme_data.h | 15 | ||||
-rw-r--r-- | scene/resources/packed_scene.cpp | 1144 | ||||
-rw-r--r-- | scene/resources/packed_scene.h | 112 | ||||
-rw-r--r-- | scene/resources/scene_format_text.cpp | 792 | ||||
-rw-r--r-- | scene/resources/scene_format_text.h | 46 | ||||
-rw-r--r-- | scene/resources/shader_graph.cpp | 287 | ||||
-rw-r--r-- | scene/resources/shader_graph.h | 15 |
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 Binary files differnew file mode 100644 index 0000000000..ea6ec52828 --- /dev/null +++ b/scene/resources/default_theme/graph_node_default.png diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png Binary files differnew file mode 100644 index 0000000000..b7c38ae481 --- /dev/null +++ b/scene/resources/default_theme/graph_node_default_focus.png diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png Binary files differnew file mode 100644 index 0000000000..06a9db4409 --- /dev/null +++ b/scene/resources/default_theme/graph_node_selected.png 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); |