Browse Source

Large improvements on scene packing and management
-Ability to edit and keep changes of instanced scenes and sub-scenes
-Ability to inherit from other scenes

reduz 10 years ago
parent
commit
422929e87f

+ 31 - 0
core/path_db.cpp

@@ -286,6 +286,37 @@ NodePath::NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_
 	data->property=p_property;
 	data->property=p_property;
 }
 }
 
 
+
+void NodePath::simplify() {
+
+	if (!data)
+		return;
+	for(int i=0;i<data->path.size();i++) {
+		if (data->path.size()==1)
+			break;
+		if (data->path[i].operator String()==".") {
+			data->path.remove(i);
+			i--;
+		} else if (data->path[i].operator String()==".." && i>0 && data->path[i-1].operator String()!="." && data->path[i-1].operator String()!="..") {
+			//remove both
+			data->path.remove(i-1);
+			data->path.remove(i-1);
+			i-=2;
+			if (data->path.size()==0) {
+				data->path.push_back(".");
+				break;
+			}
+		}
+	}
+}
+
+NodePath NodePath::simplified() const {
+
+	NodePath np=*this;
+	np.simplify();
+	return np;
+}
+
 NodePath::NodePath(const String& p_path) {
 NodePath::NodePath(const String& p_path) {
 
 
 	data=NULL;
 	data=NULL;

+ 4 - 1
core/path_db.h

@@ -84,7 +84,10 @@ public:
 	bool operator==(const NodePath& p_path) const;
 	bool operator==(const NodePath& p_path) const;
 	bool operator!=(const NodePath& p_path) const;
 	bool operator!=(const NodePath& p_path) const;
 	void operator=(const NodePath& p_path);
 	void operator=(const NodePath& p_path);
-	
+
+	void simplify();
+	NodePath simplified() const;
+
 	NodePath(const Vector<StringName>& p_path,bool p_absolute,const String& p_property="");	
 	NodePath(const Vector<StringName>& p_path,bool p_absolute,const String& p_property="");	
 	NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
 	NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
 	NodePath(const NodePath& p_path);
 	NodePath(const NodePath& p_path);

+ 1 - 1
core/resource.h

@@ -130,7 +130,7 @@ public:
 	void set_name(const String& p_name);
 	void set_name(const String& p_name);
 	String get_name() const;
 	String get_name() const;
 
 
-	void set_path(const String& p_path,bool p_take_over=false);
+	virtual void set_path(const String& p_path,bool p_take_over=false);
 	String get_path() const;
 	String get_path() const;
 
 
 	void set_subindex(int p_sub_index);
 	void set_subindex(int p_sub_index);

+ 8 - 0
demos/2d/platformer/coin.gd

@@ -18,3 +18,11 @@ func _ready():
 	# Initalization here
 	# Initalization here
 	pass
 	pass
 
 
+
+
+func _on_coin_area_enter( area ):
+	pass # replace with function body
+
+
+func _on_coin_area_enter_shape( area_id, area, area_shape, area_shape ):
+	pass # replace with function body

+ 62 - 2
scene/main/node.cpp

@@ -841,6 +841,20 @@ Node *Node::get_child(int p_index) const {
 	return data.children[p_index];
 	return data.children[p_index];
 }
 }
 
 
+
+Node *Node::_get_child_by_name(const StringName& p_name) const {
+
+	int cc=data.children.size();
+	Node* const* cd=data.children.ptr();
+
+	for(int i=0;i<cc;i++){
+		if (cd[i]->data.name==p_name)
+			return cd[i];
+	}
+
+	return NULL;
+}
+
 Node *Node::_get_node(const NodePath& p_path) const {
 Node *Node::_get_node(const NodePath& p_path) const {
 
 
 	ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
 	ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
@@ -906,8 +920,10 @@ Node *Node::_get_node(const NodePath& p_path) const {
 Node *Node::get_node(const NodePath& p_path) const {
 Node *Node::get_node(const NodePath& p_path) const {
 
 
 	Node *node = _get_node(p_path);
 	Node *node = _get_node(p_path);
-	ERR_EXPLAIN("Node not found: "+p_path);
-	ERR_FAIL_COND_V(!node,NULL);
+	if (!node) {
+		ERR_EXPLAIN("Node not found: "+p_path);
+		ERR_FAIL_COND_V(!node,NULL);
+	}
 	return node;
 	return node;
 }
 }
 
 
@@ -1332,7 +1348,29 @@ String Node::get_filename() const {
 	return data.filename;
 	return data.filename;
 }
 }
 
 
+void Node::set_editable_instance(Node* p_node,bool p_editable) {
+
+	ERR_FAIL_NULL(p_node);
+	ERR_FAIL_COND(!is_a_parent_of(p_node));
+	NodePath p = get_path_to(p_node);
+	if (!p_editable)
+		data.editable_instances.erase(p);
+	else
+		data.editable_instances[p]=true;
 
 
+}
+
+bool Node::is_editable_instance(Node *p_node) const {
+
+	if (!p_node)
+		return false; //easier, null is never editable :)
+	ERR_FAIL_COND_V(!is_a_parent_of(p_node),false);
+	NodePath p = get_path_to(p_node);
+	return data.editable_instances.has(p);
+}
+
+
+#if 0
 
 
 void Node::generate_instance_state() {
 void Node::generate_instance_state() {
 
 
@@ -1383,6 +1421,28 @@ Dictionary Node::get_instance_state() const {
 	return data.instance_state;
 	return data.instance_state;
 }
 }
 
 
+#endif
+
+void Node::set_scene_instance_state(const Ref<SceneState>& p_state) {
+
+	data.instance_state=p_state;
+}
+
+Ref<SceneState> Node::get_scene_instance_state() const{
+
+	return data.instance_state;
+}
+
+void Node::set_scene_inherited_state(const Ref<SceneState>& p_state) {
+
+	data.inherited_state=p_state;
+}
+
+Ref<SceneState> Node::get_scene_inherited_state() const{
+
+	return data.inherited_state;
+}
+
 Vector<StringName> Node::get_instance_groups() const {
 Vector<StringName> Node::get_instance_groups() const {
 
 
 	return data.instance_groups;
 	return data.instance_groups;

+ 21 - 6
scene/main/node.h

@@ -38,6 +38,7 @@
 
 
 
 
 class Viewport;
 class Viewport;
+class SceneState;
 class Node : public Object {
 class Node : public Object {
 
 
 	OBJ_TYPE( Node, Object );
 	OBJ_TYPE( Node, Object );
@@ -69,7 +70,11 @@ private:
 	struct Data {
 	struct Data {
 	
 	
 		String filename;
 		String filename;
-		Dictionary instance_state;
+		Ref<SceneState> instance_state;
+		Ref<SceneState> inherited_state;
+
+		HashMap<NodePath,int> editable_instances;
+
 		Vector<StringName> instance_groups;
 		Vector<StringName> instance_groups;
 		Vector<Connection> instance_connections;
 		Vector<Connection> instance_connections;
 
 
@@ -96,6 +101,7 @@ private:
 		PauseMode pause_mode;
 		PauseMode pause_mode;
 		Node *pause_owner;
 		Node *pause_owner;
 		// variables used to properly sort the node when processing, ignored otherwise
 		// variables used to properly sort the node when processing, ignored otherwise
+		//should move all the stuff below to bits
 		bool fixed_process;
 		bool fixed_process;
 		bool idle_process;
 		bool idle_process;
 
 
@@ -105,6 +111,7 @@ private:
 
 
 		bool parent_owned;
 		bool parent_owned;
 		bool in_constructor;
 		bool in_constructor;
+
 	} data;
 	} data;
 	
 	
 
 
@@ -112,6 +119,7 @@ private:
 	
 	
 	virtual bool _use_builtin_script() const { return true; }
 	virtual bool _use_builtin_script() const { return true; }
 	Node *_get_node(const NodePath& p_path) const;
 	Node *_get_node(const NodePath& p_path) const;
+	Node *_get_child_by_name(const StringName& p_name) const;
 
 
 
 
 
 
@@ -151,7 +159,7 @@ protected:
 	
 	
 	static void _bind_methods();
 	static void _bind_methods();
 
 
-friend class PackedScene;
+friend class SceneState;
 
 
 	void _add_child_nocheck(Node* p_child,const StringName& p_name);
 	void _add_child_nocheck(Node* p_child,const StringName& p_name);
 	void _set_owner_nocheck(Node* p_owner);
 	void _set_owner_nocheck(Node* p_owner);
@@ -208,7 +216,7 @@ public:
 	
 	
 	struct GroupInfo {
 	struct GroupInfo {
 	
 	
-		String name;
+		StringName name;
 		bool persistent;
 		bool persistent;
 	};
 	};
 	
 	
@@ -229,7 +237,10 @@ public:
 	
 	
 	void set_filename(const String& p_filename);
 	void set_filename(const String& p_filename);
 	String get_filename() const;
 	String get_filename() const;
-	
+
+	void set_editable_instance(Node* p_node,bool p_editable);
+	bool is_editable_instance(Node* p_node) const;
+
 	/* NOTIFICATIONS */
 	/* NOTIFICATIONS */
 	
 	
 	void propagate_notification(int p_notification);
 	void propagate_notification(int p_notification);
@@ -261,8 +272,12 @@ public:
 	//Node *clone_tree() const;
 	//Node *clone_tree() const;
 
 
 	// used by editors, to save what has changed only
 	// used by editors, to save what has changed only
-	void generate_instance_state();
-	Dictionary get_instance_state() const;
+	void set_scene_instance_state(const Ref<SceneState>& p_state);
+	Ref<SceneState> get_scene_instance_state() const;
+
+	void set_scene_inherited_state(const Ref<SceneState>& p_state);
+	Ref<SceneState> get_scene_inherited_state() const;
+
 	Vector<StringName> get_instance_groups() const;
 	Vector<StringName> get_instance_groups() const;
 	Vector<Connection> get_instance_connections() const;
 	Vector<Connection> get_instance_connections() const;
 
 

+ 10 - 1
scene/register_scene_types.cpp

@@ -216,7 +216,7 @@
 #include "scene/3d/collision_polygon.h"
 #include "scene/3d/collision_polygon.h"
 #endif
 #endif
 
 
-
+#include "scene/resources/scene_format_text.h"
 
 
 static ResourceFormatLoaderImage *resource_loader_image=NULL;
 static ResourceFormatLoaderImage *resource_loader_image=NULL;
 static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
 static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
@@ -229,6 +229,8 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
 static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
 static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
 static ResourceFormatLoaderShader *resource_loader_shader=NULL;
 static ResourceFormatLoaderShader *resource_loader_shader=NULL;
 
 
+static ResourceFormatSaverText *resource_saver_text=NULL;
+
 //static SceneStringNames *string_names;
 //static SceneStringNames *string_names;
 
 
 void register_scene_types() {
 void register_scene_types() {
@@ -612,6 +614,9 @@ void register_scene_types() {
 	OS::get_singleton()->yield(); //may take time to init
 	OS::get_singleton()->yield(); //may take time to init
 
 
 
 
+	resource_saver_text = memnew( ResourceFormatSaverText );
+	ResourceSaver::add_resource_format_saver(resource_saver_text);
+
 }
 }
 
 
 void unregister_scene_types() {
 void unregister_scene_types() {
@@ -629,5 +634,9 @@ void unregister_scene_types() {
 
 
 	memdelete( resource_loader_theme );
 	memdelete( resource_loader_theme );
 	memdelete( resource_loader_shader );
 	memdelete( resource_loader_shader );
+
+	if (resource_saver_text) {
+		memdelete(resource_saver_text);
+	}
 	SceneStringNames::free();
 	SceneStringNames::free();
 }
 }

File diff suppressed because it is too large
+ 676 - 118
scene/resources/packed_scene.cpp


+ 91 - 7
scene/resources/packed_scene.h

@@ -32,18 +32,32 @@
 #include "resource.h"
 #include "resource.h"
 #include "scene/main/node.h"
 #include "scene/main/node.h"
 
 
-class PackedScene : public Resource {
 
 
-	OBJ_TYPE( PackedScene, Resource );
-	RES_BASE_EXTENSION("scn");
+class SceneState : public Reference {
+
+	OBJ_TYPE( SceneState, Reference );
 	Vector<StringName> names;
 	Vector<StringName> names;
 	Vector<Variant> variants;
 	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;
+
+	int base_scene_idx;
 
 
 	//missing - instances
 	//missing - instances
 	//missing groups
 	//missing groups
 	//missing - owner
 	//missing - owner
 	//missing - override names and values
 	//missing - override names and values
 
 
+	enum {
+		FLAG_ID_IS_PATH=(1<<30),
+		FLAG_MASK=(1<<24)-1,
+		NO_PARENT_SAVED=0x7FFFFFFF,
+		TYPE_INSTANCED=0x7FFFFFFF,
+
+	};
+
 	struct NodeData {
 	struct NodeData {
 
 
 		int parent;
 		int parent;
@@ -59,9 +73,15 @@ class PackedScene : public Resource {
 		};
 		};
 
 
 		Vector<Property> properties;
 		Vector<Property> properties;
-		Vector<int> groups;
+		Vector<int> groups;		
+
 	};
 	};
 
 
+	struct PackState {
+		Ref<SceneState> state;
+		int node;
+		PackState() { node=-1; }
+	};
 
 
 	Vector<NodeData> nodes;
 	Vector<NodeData> nodes;
 
 
@@ -77,16 +97,75 @@ class PackedScene : public Resource {
 
 
 	Vector<ConnectionData> connections;
 	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;
+
+public:
+
+	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);
 	void _set_bundled_scene(const Dictionary& p_scene);
 	Dictionary _get_bundled_scene() const;
 	Dictionary _get_bundled_scene() const;
 
 
 protected:
 protected:
 
 
-
 	static void _bind_methods();
 	static void _bind_methods();
 public:
 public:
 
 
@@ -98,7 +177,12 @@ public:
 	bool can_instance() const;
 	bool can_instance() const;
 	Node *instance(bool p_gen_edit_state=false) 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();
 	PackedScene();
+
 };
 };
 
 
 #endif // SCENE_PRELOADER_H
 #endif // SCENE_PRELOADER_H

+ 792 - 0
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;
+}

+ 46 - 0
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

+ 16 - 2
tools/editor/editor_node.cpp

@@ -1107,6 +1107,11 @@ void EditorNode::_dialog_action(String p_file) {
 
 
 			push_item(res.operator->() );
 			push_item(res.operator->() );
 		} break;			
 		} break;			
+		case FILE_NEW_INHERITED_SCENE: {
+
+
+			load_scene(p_file,false,true);
+		} break;
 		case FILE_OPEN_SCENE: {
 		case FILE_OPEN_SCENE: {
 
 
 
 
@@ -1930,6 +1935,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
 
 
 			
 			
 		} break;
 		} break;
+		case FILE_NEW_INHERITED_SCENE:
 		case FILE_OPEN_SCENE: {
 		case FILE_OPEN_SCENE: {
 			
 			
 			
 			
@@ -1950,7 +1956,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
 			if (scene) {
 			if (scene) {
 				file->set_current_path(scene->get_filename());
 				file->set_current_path(scene->get_filename());
 			};
 			};
-			file->set_title("Open Scene");
+			file->set_title(p_option==FILE_OPEN_SCENE?"Open Scene":"Open Base Scene");
 			file->popup_centered_ratio();
 			file->popup_centered_ratio();
 			
 			
 		} break;
 		} break;
@@ -3311,7 +3317,7 @@ void EditorNode::fix_dependencies(const String& p_for_file) {
 	dependency_fixer->edit(p_for_file);
 	dependency_fixer->edit(p_for_file);
 }
 }
 
 
-Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
+Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bool p_set_inherited) {
 
 
 	if (!is_inside_tree()) {
 	if (!is_inside_tree()) {
 		defer_load_scene = p_scene;
 		defer_load_scene = p_scene;
@@ -3441,6 +3447,13 @@ Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) {
 	}
 	}
 */
 */
 
 
+	if (p_set_inherited) {
+		Ref<SceneState> state = sdata->get_state();
+		state->set_path(lpath);
+		new_scene->set_scene_inherited_state(state);
+	}
+
+
 	set_edited_scene(new_scene);
 	set_edited_scene(new_scene);
 	_get_scene_metadata();
 	_get_scene_metadata();
 	/*
 	/*
@@ -4793,6 +4806,7 @@ EditorNode::EditorNode() {
 	file_menu->set_tooltip("Operations with scene files.");
 	file_menu->set_tooltip("Operations with scene files.");
 	p=file_menu->get_popup();
 	p=file_menu->get_popup();
 	p->add_item("New Scene",FILE_NEW_SCENE);
 	p->add_item("New Scene",FILE_NEW_SCENE);
+	p->add_item("New Inherited Scene..",FILE_NEW_INHERITED_SCENE);
 	p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
 	p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
 	p->add_separator();
 	p->add_separator();
 	p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);
 	p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);

+ 2 - 1
tools/editor/editor_node.h

@@ -107,6 +107,7 @@ class EditorNode : public Node {
 	enum MenuOptions {
 	enum MenuOptions {
 	
 	
 		FILE_NEW_SCENE,
 		FILE_NEW_SCENE,
+		FILE_NEW_INHERITED_SCENE,
 		FILE_OPEN_SCENE,
 		FILE_OPEN_SCENE,
 		FILE_SAVE_SCENE,
 		FILE_SAVE_SCENE,
 		FILE_SAVE_AS_SCENE,
 		FILE_SAVE_AS_SCENE,
@@ -565,7 +566,7 @@ public:
 
 
 	void fix_dependencies(const String& p_for_file);
 	void fix_dependencies(const String& p_for_file);
 	void clear_scene() { _cleanup_scene(); }
 	void clear_scene() { _cleanup_scene(); }
-	Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false);
+	Error load_scene(const String& p_scene, bool p_ignore_broken_deps=false, bool p_set_inherited=false);
 	Error load_resource(const String& p_scene);
 	Error load_resource(const String& p_scene);
 
 
 	bool is_scene_open(const String& p_path);
 	bool is_scene_open(const String& p_path);

+ 121 - 30
tools/editor/property_editor.cpp

@@ -42,6 +42,8 @@
 #include "multi_node_edit.h"
 #include "multi_node_edit.h"
 #include "array_property_edit.h"
 #include "array_property_edit.h"
 #include "editor_help.h"
 #include "editor_help.h"
+#include "scene/resources/packed_scene.h"
+
 
 
 void CustomPropertyEditor::_notification(int p_what) {
 void CustomPropertyEditor::_notification(int p_what) {
 	
 	
@@ -1655,25 +1657,101 @@ CustomPropertyEditor::CustomPropertyEditor() {
 	menu->connect("item_pressed",this,"_menu_option");
 	menu->connect("item_pressed",this,"_menu_option");
 }
 }
 
 
+bool PropertyEditor::_might_be_in_instance() {
 
 
-
-Node *PropertyEditor::get_instanced_node() {
-
-	//this sucks badly
 	if (!obj)
 	if (!obj)
 		return NULL;
 		return NULL;
 
 
 	Node *node = obj->cast_to<Node>();
 	Node *node = obj->cast_to<Node>();
+
+	Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
+
+	bool might_be=false;
+
+	while(node) {
+
+		if (node->get_scene_instance_state().is_valid()) {
+			might_be=true;
+			break;
+		}
+		if (node==edited_scene) {
+			if (node->get_scene_inherited_state().is_valid()) {
+				might_be=true;
+				break;
+			}
+			might_be=false;
+			break;
+		}
+		node=node->get_owner();
+	}
+
+	return might_be;
+
+}
+
+bool PropertyEditor::_get_instanced_node_original_property(const StringName& p_prop,Variant& value) {
+
+	Node *node = obj->cast_to<Node>();
+
 	if (!node)
 	if (!node)
-		return NULL;
+		return false;
 
 
-	if (node->get_filename()=="")
-		return NULL;
+	Node *orig=node;
+
+	Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
+
+	bool found=false;
 
 
-	if (!node->get_owner())
-		return NULL; //scene root i guess
+//	print_line("for prop - "+String(p_prop));
 
 
-	return node;
+	while(node) {
+
+		Ref<SceneState> ss;
+
+		if (node==edited_scene) {
+			ss=node->get_scene_inherited_state();
+		} else {
+			ss=node->get_scene_instance_state();
+		}
+//		print_line("at - "+String(edited_scene->get_path_to(node)));
+
+		if (ss.is_valid()) {
+			NodePath np = node->get_path_to(orig);
+			int node_idx = ss->find_node_by_path(np);
+//			print_line("\t valid, nodeidx "+itos(node_idx));
+			if (node_idx>=0) {
+				bool lfound=false;
+				Variant lvar;
+				lvar=ss->get_property_value(node_idx,p_prop,lfound);
+				if (lfound) {
+					found=true;
+					value=lvar;
+//					print_line("\t found value "+String(value));
+				}
+			}
+		}
+		if (node==edited_scene) {
+			//just in case
+			break;
+		}
+		node=node->get_owner();
+
+	}
+
+	return found;
+}
+
+bool PropertyEditor::_is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage) {
+
+	if (p_orig.get_type()==Variant::NIL) {
+		//special cases
+		if (p_current.is_zero() && p_usage&PROPERTY_USAGE_STORE_IF_NONZERO)
+			return false;
+		if (p_current.is_one() && p_usage&PROPERTY_USAGE_STORE_IF_NONONE)
+			return false;
+	}
+
+	return bool(Variant::evaluate(Variant::OP_NOT_EQUAL,p_current,p_orig));
 }
 }
 
 
 TreeItem *PropertyEditor::find_item(TreeItem *p_item,const String& p_name) {
 TreeItem *PropertyEditor::find_item(TreeItem *p_item,const String& p_name) {
@@ -1910,6 +1988,8 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
 	
 	
 }
 }
 
 
+
+
 void PropertyEditor::_notification(int p_what) {
 void PropertyEditor::_notification(int p_what) {
 
 
 	if (p_what==NOTIFICATION_ENTER_TREE) {
 	if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -1950,12 +2030,16 @@ void PropertyEditor::_notification(int p_what) {
 				if (!item)
 				if (!item)
 					continue;
 					continue;
 				
 				
-				if (get_instanced_node()) {
+				if (_might_be_in_instance()) {
+
+
+					Variant vorig;
+					Dictionary d=item->get_metadata(0);
+					int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
 
 
-					Dictionary d = get_instanced_node()->get_instance_state();
-					if (d.has(*k)) {
+
+					if (_get_instanced_node_original_property(*k,vorig) || usage) {
 						Variant v = obj->get(*k);
 						Variant v = obj->get(*k);
-						Variant vorig = d[*k];
 
 
 						int found=-1;
 						int found=-1;
 						for(int i=0;i<item->get_button_count(1);i++) {
 						for(int i=0;i<item->get_button_count(1);i++) {
@@ -1966,7 +2050,7 @@ void PropertyEditor::_notification(int p_what) {
 							}
 							}
 						}
 						}
 
 
-						bool changed = ! (v==vorig);
+						bool changed = _is_property_different(v,vorig,usage);
 
 
 						if ((found!=-1)!=changed) {
 						if ((found!=-1)!=changed) {
 
 
@@ -2049,12 +2133,14 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
 
 
 	if (name!=String()) {
 	if (name!=String()) {
 
 
-		if (get_instanced_node()) {
+		if (_might_be_in_instance()) {
+
+			Variant vorig;
+			Dictionary d=p_item->get_metadata(0);
+			int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
 
 
-			Dictionary d = get_instanced_node()->get_instance_state();
-			if (d.has(name)) {
+			if (_get_instanced_node_original_property(name,vorig) || usage) {
 				Variant v = obj->get(name);
 				Variant v = obj->get(name);
-				Variant vorig = d[name];
 
 
 				int found=-1;
 				int found=-1;
 				for(int i=0;i<p_item->get_button_count(1);i++) {
 				for(int i=0;i<p_item->get_button_count(1);i++) {
@@ -2065,7 +2151,7 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
 					}
 					}
 				}
 				}
 
 
-				bool changed = ! (v==vorig);
+				bool changed = _is_property_different(v,vorig,usage);
 
 
 				if ((found!=-1)!=changed) {
 				if ((found!=-1)!=changed) {
 
 
@@ -2326,7 +2412,8 @@ void PropertyEditor::update_tree() {
 		d["type"]=(int)p.type;
 		d["type"]=(int)p.type;
 		d["hint"]=(int)p.hint;
 		d["hint"]=(int)p.hint;
 		d["hint_text"]=p.hint_string;
 		d["hint_text"]=p.hint_string;
-					
+		d["usage"]=(int)p.usage;
+
 		item->set_metadata( 0, d );
 		item->set_metadata( 0, d );
 		item->set_metadata( 1, p.name );
 		item->set_metadata( 1, p.name );
 
 
@@ -2777,14 +2864,17 @@ void PropertyEditor::update_tree() {
 			}
 			}
 		}
 		}
 
 
-		if (get_instanced_node()) {
+		if (_might_be_in_instance()) {
 
 
-			Dictionary d = get_instanced_node()->get_instance_state();
-			if (d.has(p.name)) {
+			Variant vorig;
+			Dictionary d=item->get_metadata(0);
+			int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
+			if (_get_instanced_node_original_property(p.name,vorig) || usage) {
 				Variant v = obj->get(p.name);
 				Variant v = obj->get(p.name);
-				Variant vorig = d[p.name];
-				if (! (v==vorig)) {
+				
 
 
+				if (_is_property_different(v,vorig,usage)) {
+					//print_line("FOR "+String(p.name)+" RELOAD WITH: "+String(v)+"("+Variant::get_type_name(v.get_type())+")=="+String(vorig)+"("+Variant::get_type_name(vorig.get_type())+")");
 					item->add_button(1,get_icon("Reload","EditorIcons"),3);
 					item->add_button(1,get_icon("Reload","EditorIcons"),3);
 				}
 				}
 			}
 			}
@@ -3081,17 +3171,18 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
 		call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
 		call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
 	} else if (p_button==3) {
 	} else if (p_button==3) {
 
 
-		if (!get_instanced_node())
+		if (!_might_be_in_instance())
 			return;
 			return;
 		if (!d.has("name"))
 		if (!d.has("name"))
 			return;
 			return;
 
 
 		String prop=d["name"];
 		String prop=d["name"];
 
 
-		Dictionary d2 = get_instanced_node()->get_instance_state();
-		if (d2.has(prop)) {
+		Variant vorig;
+
+		if (_get_instanced_node_original_property(prop,vorig)) {
 
 
-			_edit_set(prop,d2[prop]);
+			_edit_set(prop,vorig);
 		}
 		}
 
 
 	} else {
 	} else {

+ 6 - 1
tools/editor/property_editor.h

@@ -121,6 +121,7 @@ class CustomPropertyEditor : public Popup {
 	void show_value_editors(int p_amount);
 	void show_value_editors(int p_amount);
 	void config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings);
 	void config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings);
 	void config_action_buttons(const List<String>& p_strings);
 	void config_action_buttons(const List<String>& p_strings);
+
 protected:
 protected:
 
 
 	void _notification(int p_what);
 	void _notification(int p_what);
@@ -184,13 +185,17 @@ class PropertyEditor : public Control {
 	virtual void _changed_callback(Object *p_changed,const char * p_what);
 	virtual void _changed_callback(Object *p_changed,const char * p_what);
 	virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
 	virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
 
 
+
 	void _edit_button(Object *p_item, int p_column, int p_button);
 	void _edit_button(Object *p_item, int p_column, int p_button);
 	
 	
 	void _node_removed(Node *p_node);
 	void _node_removed(Node *p_node);
 	void _edit_set(const String& p_name, const Variant& p_value);
 	void _edit_set(const String& p_name, const Variant& p_value);
 	void _draw_flags(Object *ti,const Rect2& p_rect);
 	void _draw_flags(Object *ti,const Rect2& p_rect);
 
 
-	Node *get_instanced_node();
+	bool _might_be_in_instance();
+	bool _get_instanced_node_original_property(const StringName& p_prop,Variant& value);
+	bool _is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage=0);
+
 	void _refresh_item(TreeItem *p_item);
 	void _refresh_item(TreeItem *p_item);
 	void _set_range_def(Object *p_item, String prop, float p_frame);
 	void _set_range_def(Object *p_item, String prop, float p_frame);
 
 

+ 1 - 0
tools/editor/reparent_dialog.cpp

@@ -103,6 +103,7 @@ ReparentDialog::ReparentDialog() {
 	add_child(node_only);
 	add_child(node_only);
 	node_only->hide();
 	node_only->hide();
 
 
+	tree->set_show_enabled_subscene(true);
 	//vbc->add_margin_child("Options:",node_only);;
 	//vbc->add_margin_child("Options:",node_only);;
 	
 	
 
 

+ 31 - 20
tools/editor/scene_tree_dock.cpp

@@ -36,8 +36,8 @@
 #include "script_editor_debugger.h"
 #include "script_editor_debugger.h"
 #include "tools/editor/plugins/script_editor_plugin.h"
 #include "tools/editor/plugins/script_editor_plugin.h"
 #include "multi_node_edit.h"
 #include "multi_node_edit.h"
-void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
 
 
+void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
 
 
 	uint32_t sc = p_event.key.get_scancode_with_modifiers();
 	uint32_t sc = p_event.key.get_scancode_with_modifiers();
 	if (!p_event.key.pressed || p_event.key.echo)
 	if (!p_event.key.pressed || p_event.key.echo)
@@ -71,7 +71,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
 	Node*instanced_scene=NULL;
 	Node*instanced_scene=NULL;
 	Ref<PackedScene> sdata = ResourceLoader::load(p_file);
 	Ref<PackedScene> sdata = ResourceLoader::load(p_file);
 	if (sdata.is_valid())
 	if (sdata.is_valid())
-		instanced_scene=sdata->instance();
+		instanced_scene=sdata->instance(true);
 
 
 
 
 	if (!instanced_scene) {
 	if (!instanced_scene) {
@@ -96,7 +96,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
 		}
 		}
 	}
 	}
 
 
-	instanced_scene->generate_instance_state();
+	//instanced_scene->generate_instance_state();
 	instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
 	instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
 
 
 	editor_data->get_undo_redo().create_action("Instance Scene");
 	editor_data->get_undo_redo().create_action("Instance Scene");
@@ -158,8 +158,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 		case TOOL_NEW: {
 		case TOOL_NEW: {
 
 
 
 
-			if (!_validate_no_foreign())
-				break;
+			//if (!_validate_no_foreign())
+			//	break;
 			create_dialog->popup_centered_ratio();
 			create_dialog->popup_centered_ratio();
 		} break;
 		} break;
 		case TOOL_INSTANCE: {
 		case TOOL_INSTANCE: {
@@ -176,8 +176,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 				break;
 				break;
 			}
 			}
 
 
-			if (!_validate_no_foreign())
-				break;
+			//if (!_validate_no_foreign())
+			//	break;
 
 
 			file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
 			file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
 			List<String> extensions;
 			List<String> extensions;
@@ -202,8 +202,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 			if (!current)
 			if (!current)
 				break;
 				break;
 
 
-			if (!_validate_no_foreign())
-				break;
+			//if (!_validate_no_foreign())
+			//	break;
 			connect_dialog->popup_centered_ratio();
 			connect_dialog->popup_centered_ratio();
 			connect_dialog->set_node(current);
 			connect_dialog->set_node(current);
 
 
@@ -213,8 +213,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 			Node *current = scene_tree->get_selected();
 			Node *current = scene_tree->get_selected();
 			if (!current)
 			if (!current)
 				break;
 				break;
-			if (!_validate_no_foreign())
-				break;
+			//if (!_validate_no_foreign())
+			//	break;
 			groups_editor->set_current(current);
 			groups_editor->set_current(current);
 			groups_editor->popup_centered_ratio();
 			groups_editor->popup_centered_ratio();
 		} break;
 		} break;
@@ -224,8 +224,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
 			if (!selected)
 			if (!selected)
 				break;
 				break;
 
 
-			if (!_validate_no_foreign())
-				break;
+			//if (!_validate_no_foreign())
+			//	break;
 
 
 			Ref<Script> existing = selected->get_script();
 			Ref<Script> existing = selected->get_script();
 			if (existing.is_valid())
 			if (existing.is_valid())
@@ -573,9 +573,9 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
 
 
 		Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
 		Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
 		ERR_FAIL_COND_V(!sd.is_valid(),NULL);
 		ERR_FAIL_COND_V(!sd.is_valid(),NULL);
-		node = sd->instance();
+		node = sd->instance(true);
 		ERR_FAIL_COND_V(!node,NULL);
 		ERR_FAIL_COND_V(!node,NULL);
-		node->generate_instance_state();
+		//node->generate_instance_state();
 	} else {
 	} else {
 		Object *obj = ObjectTypeDB::instance(p_node->get_type());
 		Object *obj = ObjectTypeDB::instance(p_node->get_type());
 		ERR_FAIL_COND_V(!obj,NULL);
 		ERR_FAIL_COND_V(!obj,NULL);
@@ -874,6 +874,16 @@ bool SceneTreeDock::_validate_no_foreign() {
 			return false;
 			return false;
 
 
 		}
 		}
+
+		if (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(E->get()))>=0) {
+
+			accept->get_ok()->set_text("Makes Sense!");
+			accept->set_text("Can't operate on nodes the current scene inherits from!");
+			accept->popup_centered_minsize();
+			return false;
+
+		}
+
 	}
 	}
 
 
 	return true;
 	return true;
@@ -1078,14 +1088,15 @@ void SceneTreeDock::_delete_confirm() {
 void SceneTreeDock::_update_tool_buttons() {
 void SceneTreeDock::_update_tool_buttons() {
 
 
 	Node *sel = scene_tree->get_selected();
 	Node *sel = scene_tree->get_selected();
-	bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene);
+	bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene) || (edited_scene->get_scene_instance_state().is_valid() && edited_scene->get_scene_instance_state()->find_node_by_path(edited_scene->get_path_to(sel))>=0);
 	bool disable_root = disable || sel->get_parent()==scene_root;
 	bool disable_root = disable || sel->get_parent()==scene_root;
+	bool disable_edit = !sel;
 
 
-	tool_buttons[TOOL_INSTANCE]->set_disabled(disable);
+	tool_buttons[TOOL_INSTANCE]->set_disabled(disable_edit);
 	tool_buttons[TOOL_REPLACE]->set_disabled(disable);
 	tool_buttons[TOOL_REPLACE]->set_disabled(disable);
-	tool_buttons[TOOL_CONNECT]->set_disabled(disable);
-	tool_buttons[TOOL_GROUP]->set_disabled(disable);
-	tool_buttons[TOOL_SCRIPT]->set_disabled(disable);
+	tool_buttons[TOOL_CONNECT]->set_disabled(disable_edit);
+	tool_buttons[TOOL_GROUP]->set_disabled(disable_edit);
+	tool_buttons[TOOL_SCRIPT]->set_disabled(disable_edit);
 	tool_buttons[TOOL_MOVE_UP]->set_disabled(disable_root);
 	tool_buttons[TOOL_MOVE_UP]->set_disabled(disable_root);
 	tool_buttons[TOOL_MOVE_DOWN]->set_disabled(disable_root);
 	tool_buttons[TOOL_MOVE_DOWN]->set_disabled(disable_root);
 	tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
 	tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);

+ 73 - 22
tools/editor/scene_tree_editor.cpp

@@ -34,6 +34,8 @@
 #include "scene/main/viewport.h"
 #include "scene/main/viewport.h"
 #include "tools/editor/plugins/canvas_item_editor_plugin.h"
 #include "tools/editor/plugins/canvas_item_editor_plugin.h"
 
 
+#include "scene/resources/packed_scene.h"
+
 Node *SceneTreeEditor::get_scene_node() {
 Node *SceneTreeEditor::get_scene_node() {
 
 
 	ERR_FAIL_COND_V(!is_inside_tree(),NULL);
 	ERR_FAIL_COND_V(!is_inside_tree(),NULL);
@@ -57,22 +59,38 @@ void SceneTreeEditor::_subscene_option(int p_idx) {
 
 
 	switch(p_idx) {
 	switch(p_idx) {
 
 
-		case SCENE_MENU_SHOW_CHILDREN: {
+		case SCENE_MENU_EDITABLE_CHILDREN: {
 
 
-			if (node->has_meta("__editor_show_subtree")) {
-				instance_menu->set_item_checked(0,true);
-				node->set_meta("__editor_show_subtree",Variant());
-				_update_tree();
-			} else {
-				node->set_meta("__editor_show_subtree",true);
-				_update_tree();
-			}
+			bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
+			editable = !editable;
+
+			//node->set_instance_children_editable(editable);
+			EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,editable);
+			instance_menu->set_item_checked(0,editable);
+
+			_update_tree();
 
 
 		} break;
 		} break;
 		case SCENE_MENU_OPEN: {
 		case SCENE_MENU_OPEN: {
 
 
 			emit_signal("open",node->get_filename());
 			emit_signal("open",node->get_filename());
 		} break;
 		} break;
+		case SCENE_MENU_CLEAR_INHERITANCE: {
+			clear_inherit_confirm->popup_centered_minsize();
+		} break;
+		case SCENE_MENU_OPEN_INHERITED: {
+			if (node && node->get_scene_inherited_state().is_valid()) {
+				emit_signal("open",node->get_scene_inherited_state()->get_path());
+			}
+		} break;
+		case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: {
+			if (node && node->get_scene_inherited_state().is_valid()) {
+				node->set_scene_inherited_state(Ref<SceneState>());
+				update_tree();
+				EditorNode::get_singleton()->get_property_editor()->update_tree();
+			}
+
+		} break;
 
 
 	}
 	}
 
 
@@ -94,15 +112,24 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
 		Rect2 item_rect = tree->get_item_rect(item,0);
 		Rect2 item_rect = tree->get_item_rect(item,0);
 		item_rect.pos.y-=tree->get_scroll().y;
 		item_rect.pos.y-=tree->get_scroll().y;
 		item_rect.pos+=tree->get_global_pos();
 		item_rect.pos+=tree->get_global_pos();
-		instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
-		instance_menu->set_size(Vector2(item_rect.size.x,0));
-		if (n->has_meta("__editor_show_subtree"))
-			instance_menu->set_item_checked(0,true);
-		else
-			instance_menu->set_item_checked(0,false);
-
-		instance_menu->popup();
-		instance_node=n->get_instance_ID();
+
+		if (n==get_scene_node()) {
+			inheritance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
+			inheritance_menu->set_size(Vector2(item_rect.size.x,0));
+			inheritance_menu->popup();
+			instance_node=n->get_instance_ID();
+
+		} else {
+			instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
+			instance_menu->set_size(Vector2(item_rect.size.x,0));
+			if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n))
+				instance_menu->set_item_checked(0,true);
+			else
+				instance_menu->set_item_checked(0,false);
+
+			instance_menu->popup();
+			instance_node=n->get_instance_ID();
+		}
 		//emit_signal("open",n->get_filename());
 		//emit_signal("open",n->get_filename());
 	} else if (p_id==BUTTON_SCRIPT) {
 	} else if (p_id==BUTTON_SCRIPT) {
 		RefPtr script=n->get_script();
 		RefPtr script=n->get_script();
@@ -168,15 +195,17 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
 
 
 	bool part_of_subscene=false;
 	bool part_of_subscene=false;
 
 
-	if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
+	if (!display_foreign && p_node->get_owner()!=get_scene_node()  && p_node!=get_scene_node()) {
 
 
-		if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && p_node->get_owner()->get_owner()==get_scene_node() && p_node->get_owner()->has_meta("__editor_show_subtree")) {
+		if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && (get_scene_node()->is_editable_instance(p_node->get_owner()))) {
 
 
 			part_of_subscene=true;
 			part_of_subscene=true;
 			//allow
 			//allow
 		} else {
 		} else {
 			return;
 			return;
 		}
 		}
+	} else {
+		part_of_subscene = get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node))>=0;
 	}
 	}
 
 
 	TreeItem *item = tree->create_item(p_parent);
 	TreeItem *item = tree->create_item(p_parent);
@@ -199,6 +228,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
 		icon=get_icon( (has_icon(p_node->get_type(),"EditorIcons")?p_node->get_type():String("Object")),"EditorIcons");
 		icon=get_icon( (has_icon(p_node->get_type(),"EditorIcons")?p_node->get_type():String("Object")),"EditorIcons");
 	item->set_icon(0, icon );
 	item->set_icon(0, icon );
 	item->set_metadata( 0,p_node->get_path() );	
 	item->set_metadata( 0,p_node->get_path() );	
+
 	if (part_of_subscene) {
 	if (part_of_subscene) {
 
 
 		//item->set_selectable(0,marked_selectable);
 		//item->set_selectable(0,marked_selectable);
@@ -221,7 +251,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
 		}
 		}
 	}
 	}
 
 
-	if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
+	if (p_node==get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
+		item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
+		item->set_tooltip(0,"Inherits: "+p_node->get_scene_inherited_state()->get_path()+"\nType: "+p_node->get_type());
+	} else if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
 
 
 		item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
 		item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
 		item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
 		item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
@@ -489,6 +522,9 @@ void SceneTreeEditor::_notification(int p_what) {
 		get_tree()->connect("node_removed",this,"_node_removed");
 		get_tree()->connect("node_removed",this,"_node_removed");
 		instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
 		instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
 		tree->connect("item_collapsed",this,"_cell_collapsed");
 		tree->connect("item_collapsed",this,"_cell_collapsed");
+		inheritance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
+		clear_inherit_confirm->connect("confirmed",this,"_subscene_option",varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM));
+
 
 
 //		get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED);
 //		get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED);
 //		get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED);
 //		get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED);
@@ -499,6 +535,7 @@ void SceneTreeEditor::_notification(int p_what) {
 		get_tree()->disconnect("tree_changed",this,"_tree_changed");
 		get_tree()->disconnect("tree_changed",this,"_tree_changed");
 		get_tree()->disconnect("node_removed",this,"_node_removed");
 		get_tree()->disconnect("node_removed",this,"_node_removed");
 		tree->disconnect("item_collapsed",this,"_cell_collapsed");
 		tree->disconnect("item_collapsed",this,"_cell_collapsed");
+		clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
 		_update_tree();
 		_update_tree();
 	}
 	}
 
 
@@ -788,12 +825,26 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
 	blocked=0;
 	blocked=0;
 
 
 	instance_menu = memnew( PopupMenu );
 	instance_menu = memnew( PopupMenu );
-	instance_menu->add_check_item("Show Children",SCENE_MENU_SHOW_CHILDREN);
+	instance_menu->add_check_item("Editable Children",SCENE_MENU_EDITABLE_CHILDREN);
 	instance_menu->add_separator();
 	instance_menu->add_separator();
 	instance_menu->add_item("Open in Editor",SCENE_MENU_OPEN);
 	instance_menu->add_item("Open in Editor",SCENE_MENU_OPEN);
 	instance_menu->connect("item_pressed",this,"_subscene_option");
 	instance_menu->connect("item_pressed",this,"_subscene_option");
 	add_child(instance_menu);
 	add_child(instance_menu);
 
 
+	inheritance_menu = memnew( PopupMenu );
+	inheritance_menu->add_item("Clear Inheritance",SCENE_MENU_CLEAR_INHERITANCE);
+	inheritance_menu->add_separator();
+	inheritance_menu->add_item("Open in Editor",SCENE_MENU_OPEN_INHERITED);
+	inheritance_menu->connect("item_pressed",this,"_subscene_option");
+
+	add_child(inheritance_menu);
+
+	clear_inherit_confirm = memnew( ConfirmationDialog );
+	clear_inherit_confirm->set_text("Clear Inheritance? (No Undo!)");
+	clear_inherit_confirm->get_ok()->set_text("Clear!");
+	add_child(clear_inherit_confirm);
+
+
 }
 }
 
 
 
 

+ 6 - 1
tools/editor/scene_tree_editor.h

@@ -52,16 +52,21 @@ class SceneTreeEditor : public Control {
 	};
 	};
 
 
 	enum {
 	enum {
-		SCENE_MENU_SHOW_CHILDREN,
+		SCENE_MENU_EDITABLE_CHILDREN,
 		SCENE_MENU_OPEN,
 		SCENE_MENU_OPEN,
+		SCENE_MENU_CLEAR_INHERITANCE,
+		SCENE_MENU_OPEN_INHERITED,
+		SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
 	};
 	};
 
 
 	Tree *tree;
 	Tree *tree;
 	Node *selected;
 	Node *selected;
 	PopupMenu *instance_menu;
 	PopupMenu *instance_menu;
+	PopupMenu *inheritance_menu;
 	ObjectID instance_node;
 	ObjectID instance_node;
 
 
 	AcceptDialog *error;
 	AcceptDialog *error;
+	ConfirmationDialog *clear_inherit_confirm;
 
 
 	int blocked;
 	int blocked;
 	
 	

Some files were not shown because too many files changed in this diff