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
This commit is contained in:
parent
afbb0ca8d7
commit
422929e87f
19 changed files with 2313 additions and 223 deletions
|
@ -286,6 +286,37 @@ NodePath::NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_
|
|||
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) {
|
||||
|
||||
data=NULL;
|
||||
|
|
|
@ -84,7 +84,10 @@ public:
|
|||
bool operator==(const NodePath& p_path) const;
|
||||
bool operator!=(const NodePath& p_path) const;
|
||||
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,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
|
||||
NodePath(const NodePath& p_path);
|
||||
|
|
|
@ -130,7 +130,7 @@ public:
|
|||
void set_name(const String& p_name);
|
||||
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;
|
||||
|
||||
void set_subindex(int p_sub_index);
|
||||
|
|
|
@ -18,3 +18,11 @@ func _ready():
|
|||
# Initalization here
|
||||
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
|
||||
|
|
|
@ -841,6 +841,20 @@ Node *Node::get_child(int p_index) const {
|
|||
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 {
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
|
@ -1332,7 +1348,29 @@ String Node::get_filename() const {
|
|||
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() {
|
||||
|
||||
|
@ -1383,6 +1421,28 @@ Dictionary Node::get_instance_state() const {
|
|||
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 {
|
||||
|
||||
return data.instance_groups;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
|
||||
class Viewport;
|
||||
class SceneState;
|
||||
class Node : public Object {
|
||||
|
||||
OBJ_TYPE( Node, Object );
|
||||
|
@ -69,7 +70,11 @@ private:
|
|||
struct Data {
|
||||
|
||||
String filename;
|
||||
Dictionary instance_state;
|
||||
Ref<SceneState> instance_state;
|
||||
Ref<SceneState> inherited_state;
|
||||
|
||||
HashMap<NodePath,int> editable_instances;
|
||||
|
||||
Vector<StringName> instance_groups;
|
||||
Vector<Connection> instance_connections;
|
||||
|
||||
|
@ -96,6 +101,7 @@ private:
|
|||
PauseMode pause_mode;
|
||||
Node *pause_owner;
|
||||
// variables used to properly sort the node when processing, ignored otherwise
|
||||
//should move all the stuff below to bits
|
||||
bool fixed_process;
|
||||
bool idle_process;
|
||||
|
||||
|
@ -105,6 +111,7 @@ private:
|
|||
|
||||
bool parent_owned;
|
||||
bool in_constructor;
|
||||
|
||||
} data;
|
||||
|
||||
|
||||
|
@ -112,6 +119,7 @@ private:
|
|||
|
||||
virtual bool _use_builtin_script() const { return true; }
|
||||
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();
|
||||
|
||||
friend class PackedScene;
|
||||
friend class SceneState;
|
||||
|
||||
void _add_child_nocheck(Node* p_child,const StringName& p_name);
|
||||
void _set_owner_nocheck(Node* p_owner);
|
||||
|
@ -208,7 +216,7 @@ public:
|
|||
|
||||
struct GroupInfo {
|
||||
|
||||
String name;
|
||||
StringName name;
|
||||
bool persistent;
|
||||
};
|
||||
|
||||
|
@ -229,7 +237,10 @@ public:
|
|||
|
||||
void set_filename(const String& p_filename);
|
||||
String get_filename() const;
|
||||
|
||||
|
||||
void set_editable_instance(Node* p_node,bool p_editable);
|
||||
bool is_editable_instance(Node* p_node) const;
|
||||
|
||||
/* NOTIFICATIONS */
|
||||
|
||||
void propagate_notification(int p_notification);
|
||||
|
@ -261,8 +272,12 @@ public:
|
|||
//Node *clone_tree() const;
|
||||
|
||||
// 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<Connection> get_instance_connections() const;
|
||||
|
||||
|
|
|
@ -216,7 +216,7 @@
|
|||
#include "scene/3d/collision_polygon.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "scene/resources/scene_format_text.h"
|
||||
|
||||
static ResourceFormatLoaderImage *resource_loader_image=NULL;
|
||||
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
|
||||
|
@ -229,6 +229,8 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
|
|||
static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
|
||||
static ResourceFormatLoaderShader *resource_loader_shader=NULL;
|
||||
|
||||
static ResourceFormatSaverText *resource_saver_text=NULL;
|
||||
|
||||
//static SceneStringNames *string_names;
|
||||
|
||||
void register_scene_types() {
|
||||
|
@ -612,6 +614,9 @@ void register_scene_types() {
|
|||
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() {
|
||||
|
@ -629,5 +634,9 @@ void unregister_scene_types() {
|
|||
|
||||
memdelete( resource_loader_theme );
|
||||
memdelete( resource_loader_shader );
|
||||
|
||||
if (resource_saver_text) {
|
||||
memdelete(resource_saver_text);
|
||||
}
|
||||
SceneStringNames::free();
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -32,18 +32,32 @@
|
|||
#include "resource.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<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 groups
|
||||
//missing - owner
|
||||
//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 {
|
||||
|
||||
int parent;
|
||||
|
@ -59,9 +73,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;
|
||||
|
||||
|
@ -77,16 +97,75 @@ 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;
|
||||
|
||||
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);
|
||||
Dictionary _get_bundled_scene() const;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
|
@ -98,7 +177,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
|
||||
|
|
792
scene/resources/scene_format_text.cpp
Normal file
792
scene/resources/scene_format_text.cpp
Normal file
|
@ -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
scene/resources/scene_format_text.h
Normal file
46
scene/resources/scene_format_text.h
Normal file
|
@ -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
|
|
@ -1107,6 +1107,11 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
|
||||
push_item(res.operator->() );
|
||||
} break;
|
||||
case FILE_NEW_INHERITED_SCENE: {
|
||||
|
||||
|
||||
load_scene(p_file,false,true);
|
||||
} break;
|
||||
case FILE_OPEN_SCENE: {
|
||||
|
||||
|
||||
|
@ -1930,6 +1935,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
|
||||
|
||||
} break;
|
||||
case FILE_NEW_INHERITED_SCENE:
|
||||
case FILE_OPEN_SCENE: {
|
||||
|
||||
|
||||
|
@ -1950,7 +1956,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
if (scene) {
|
||||
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();
|
||||
|
||||
} break;
|
||||
|
@ -3311,7 +3317,7 @@ void EditorNode::fix_dependencies(const String& 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()) {
|
||||
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);
|
||||
_get_scene_metadata();
|
||||
/*
|
||||
|
@ -4793,6 +4806,7 @@ EditorNode::EditorNode() {
|
|||
file_menu->set_tooltip("Operations with scene files.");
|
||||
p=file_menu->get_popup();
|
||||
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_separator();
|
||||
p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);
|
||||
|
|
|
@ -107,6 +107,7 @@ class EditorNode : public Node {
|
|||
enum MenuOptions {
|
||||
|
||||
FILE_NEW_SCENE,
|
||||
FILE_NEW_INHERITED_SCENE,
|
||||
FILE_OPEN_SCENE,
|
||||
FILE_SAVE_SCENE,
|
||||
FILE_SAVE_AS_SCENE,
|
||||
|
@ -565,7 +566,7 @@ public:
|
|||
|
||||
void fix_dependencies(const String& p_for_file);
|
||||
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);
|
||||
|
||||
bool is_scene_open(const String& p_path);
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
#include "multi_node_edit.h"
|
||||
#include "array_property_edit.h"
|
||||
#include "editor_help.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
|
||||
|
||||
void CustomPropertyEditor::_notification(int p_what) {
|
||||
|
||||
|
@ -1655,25 +1657,101 @@ CustomPropertyEditor::CustomPropertyEditor() {
|
|||
menu->connect("item_pressed",this,"_menu_option");
|
||||
}
|
||||
|
||||
bool PropertyEditor::_might_be_in_instance() {
|
||||
|
||||
|
||||
Node *PropertyEditor::get_instanced_node() {
|
||||
|
||||
//this sucks badly
|
||||
if (!obj)
|
||||
return NULL;
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
if (node->get_filename()=="")
|
||||
return NULL;
|
||||
Node *orig=node;
|
||||
|
||||
if (!node->get_owner())
|
||||
return NULL; //scene root i guess
|
||||
Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
|
||||
|
||||
return node;
|
||||
bool found=false;
|
||||
|
||||
// print_line("for prop - "+String(p_prop));
|
||||
|
||||
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) {
|
||||
|
@ -1910,6 +1988,8 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PropertyEditor::_notification(int p_what) {
|
||||
|
||||
if (p_what==NOTIFICATION_ENTER_TREE) {
|
||||
|
@ -1950,12 +2030,16 @@ void PropertyEditor::_notification(int p_what) {
|
|||
if (!item)
|
||||
continue;
|
||||
|
||||
if (get_instanced_node()) {
|
||||
if (_might_be_in_instance()) {
|
||||
|
||||
Dictionary d = get_instanced_node()->get_instance_state();
|
||||
if (d.has(*k)) {
|
||||
|
||||
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(*k,vorig) || usage) {
|
||||
Variant v = obj->get(*k);
|
||||
Variant vorig = d[*k];
|
||||
|
||||
int found=-1;
|
||||
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) {
|
||||
|
||||
|
@ -2049,12 +2133,14 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
|
|||
|
||||
if (name!=String()) {
|
||||
|
||||
if (get_instanced_node()) {
|
||||
if (_might_be_in_instance()) {
|
||||
|
||||
Dictionary d = get_instanced_node()->get_instance_state();
|
||||
if (d.has(name)) {
|
||||
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;
|
||||
|
||||
if (_get_instanced_node_original_property(name,vorig) || usage) {
|
||||
Variant v = obj->get(name);
|
||||
Variant vorig = d[name];
|
||||
|
||||
int found=-1;
|
||||
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) {
|
||||
|
||||
|
@ -2326,7 +2412,8 @@ void PropertyEditor::update_tree() {
|
|||
d["type"]=(int)p.type;
|
||||
d["hint"]=(int)p.hint;
|
||||
d["hint_text"]=p.hint_string;
|
||||
|
||||
d["usage"]=(int)p.usage;
|
||||
|
||||
item->set_metadata( 0, d );
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
} else if (p_button==3) {
|
||||
|
||||
if (!get_instanced_node())
|
||||
if (!_might_be_in_instance())
|
||||
return;
|
||||
if (!d.has("name"))
|
||||
return;
|
||||
|
||||
String prop=d["name"];
|
||||
|
||||
Dictionary d2 = get_instanced_node()->get_instance_state();
|
||||
if (d2.has(prop)) {
|
||||
Variant vorig;
|
||||
|
||||
_edit_set(prop,d2[prop]);
|
||||
if (_get_instanced_node_original_property(prop,vorig)) {
|
||||
|
||||
_edit_set(prop,vorig);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
@ -121,6 +121,7 @@ class CustomPropertyEditor : public Popup {
|
|||
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_action_buttons(const List<String>& p_strings);
|
||||
|
||||
protected:
|
||||
|
||||
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_callbacks(Object *p_changed,const String& p_callback);
|
||||
|
||||
|
||||
void _edit_button(Object *p_item, int p_column, int p_button);
|
||||
|
||||
void _node_removed(Node *p_node);
|
||||
void _edit_set(const String& p_name, const Variant& p_value);
|
||||
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 _set_range_def(Object *p_item, String prop, float p_frame);
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ ReparentDialog::ReparentDialog() {
|
|||
add_child(node_only);
|
||||
node_only->hide();
|
||||
|
||||
tree->set_show_enabled_subscene(true);
|
||||
//vbc->add_margin_child("Options:",node_only);;
|
||||
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
#include "script_editor_debugger.h"
|
||||
#include "tools/editor/plugins/script_editor_plugin.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();
|
||||
if (!p_event.key.pressed || p_event.key.echo)
|
||||
|
@ -71,7 +71,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
|
|||
Node*instanced_scene=NULL;
|
||||
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
|
||||
if (sdata.is_valid())
|
||||
instanced_scene=sdata->instance();
|
||||
instanced_scene=sdata->instance(true);
|
||||
|
||||
|
||||
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) );
|
||||
|
||||
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: {
|
||||
|
||||
|
||||
if (!_validate_no_foreign())
|
||||
break;
|
||||
//if (!_validate_no_foreign())
|
||||
// break;
|
||||
create_dialog->popup_centered_ratio();
|
||||
} break;
|
||||
case TOOL_INSTANCE: {
|
||||
|
@ -176,8 +176,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
break;
|
||||
}
|
||||
|
||||
if (!_validate_no_foreign())
|
||||
break;
|
||||
//if (!_validate_no_foreign())
|
||||
// break;
|
||||
|
||||
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
|
||||
List<String> extensions;
|
||||
|
@ -202,8 +202,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
if (!current)
|
||||
break;
|
||||
|
||||
if (!_validate_no_foreign())
|
||||
break;
|
||||
//if (!_validate_no_foreign())
|
||||
// break;
|
||||
connect_dialog->popup_centered_ratio();
|
||||
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();
|
||||
if (!current)
|
||||
break;
|
||||
if (!_validate_no_foreign())
|
||||
break;
|
||||
//if (!_validate_no_foreign())
|
||||
// break;
|
||||
groups_editor->set_current(current);
|
||||
groups_editor->popup_centered_ratio();
|
||||
} break;
|
||||
|
@ -224,8 +224,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
|
|||
if (!selected)
|
||||
break;
|
||||
|
||||
if (!_validate_no_foreign())
|
||||
break;
|
||||
//if (!_validate_no_foreign())
|
||||
// break;
|
||||
|
||||
Ref<Script> existing = selected->get_script();
|
||||
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() );
|
||||
ERR_FAIL_COND_V(!sd.is_valid(),NULL);
|
||||
node = sd->instance();
|
||||
node = sd->instance(true);
|
||||
ERR_FAIL_COND_V(!node,NULL);
|
||||
node->generate_instance_state();
|
||||
//node->generate_instance_state();
|
||||
} else {
|
||||
Object *obj = ObjectTypeDB::instance(p_node->get_type());
|
||||
ERR_FAIL_COND_V(!obj,NULL);
|
||||
|
@ -874,6 +874,16 @@ bool SceneTreeDock::_validate_no_foreign() {
|
|||
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;
|
||||
|
@ -1078,14 +1088,15 @@ void SceneTreeDock::_delete_confirm() {
|
|||
void SceneTreeDock::_update_tool_buttons() {
|
||||
|
||||
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_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_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_DOWN]->set_disabled(disable_root);
|
||||
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "scene/main/viewport.h"
|
||||
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
|
||||
|
||||
#include "scene/resources/packed_scene.h"
|
||||
|
||||
Node *SceneTreeEditor::get_scene_node() {
|
||||
|
||||
ERR_FAIL_COND_V(!is_inside_tree(),NULL);
|
||||
|
@ -57,22 +59,38 @@ void SceneTreeEditor::_subscene_option(int 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;
|
||||
case SCENE_MENU_OPEN: {
|
||||
|
||||
emit_signal("open",node->get_filename());
|
||||
} 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);
|
||||
item_rect.pos.y-=tree->get_scroll().y;
|
||||
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());
|
||||
} else if (p_id==BUTTON_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;
|
||||
|
||||
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;
|
||||
//allow
|
||||
} else {
|
||||
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);
|
||||
|
@ -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");
|
||||
item->set_icon(0, icon );
|
||||
item->set_metadata( 0,p_node->get_path() );
|
||||
|
||||
if (part_of_subscene) {
|
||||
|
||||
//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->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");
|
||||
instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
|
||||
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("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("node_removed",this,"_node_removed");
|
||||
tree->disconnect("item_collapsed",this,"_cell_collapsed");
|
||||
clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
|
||||
_update_tree();
|
||||
}
|
||||
|
||||
|
@ -788,12 +825,26 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
|
|||
blocked=0;
|
||||
|
||||
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_item("Open in Editor",SCENE_MENU_OPEN);
|
||||
instance_menu->connect("item_pressed",this,"_subscene_option");
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -52,16 +52,21 @@ class SceneTreeEditor : public Control {
|
|||
};
|
||||
|
||||
enum {
|
||||
SCENE_MENU_SHOW_CHILDREN,
|
||||
SCENE_MENU_EDITABLE_CHILDREN,
|
||||
SCENE_MENU_OPEN,
|
||||
SCENE_MENU_CLEAR_INHERITANCE,
|
||||
SCENE_MENU_OPEN_INHERITED,
|
||||
SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
|
||||
};
|
||||
|
||||
Tree *tree;
|
||||
Node *selected;
|
||||
PopupMenu *instance_menu;
|
||||
PopupMenu *inheritance_menu;
|
||||
ObjectID instance_node;
|
||||
|
||||
AcceptDialog *error;
|
||||
ConfirmationDialog *clear_inherit_confirm;
|
||||
|
||||
int blocked;
|
||||
|
||||
|
|
Loading…
Reference in a new issue