summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/navigation2d.cpp4
-rw-r--r--scene/2d/navigation2d.h2
-rw-r--r--scene/2d/navigation_polygon.cpp6
-rw-r--r--scene/2d/tile_map.cpp25
-rw-r--r--scene/2d/tile_map.h1
-rw-r--r--scene/3d/baked_lightmap.cpp7
-rw-r--r--scene/3d/camera.cpp198
-rw-r--r--scene/3d/camera.h13
-rw-r--r--scene/3d/navigation.cpp4
-rw-r--r--scene/3d/navigation.h2
-rw-r--r--scene/3d/navigation_mesh.cpp6
-rw-r--r--scene/3d/particles.cpp34
-rw-r--r--scene/3d/voxel_light_baker.cpp8
-rw-r--r--scene/gui/dialogs.cpp13
-rw-r--r--scene/gui/popup_menu.cpp37
-rw-r--r--scene/gui/rich_text_label.cpp11
-rw-r--r--scene/gui/slider.cpp8
-rw-r--r--scene/gui/text_edit.cpp74
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/gui/tree.cpp14
-rw-r--r--scene/main/http_request.cpp72
-rw-r--r--scene/main/http_request.h1
-rw-r--r--scene/main/node.cpp38
-rw-r--r--scene/main/viewport.cpp2
-rw-r--r--scene/resources/packed_scene.cpp23
-rw-r--r--scene/resources/packed_scene.h6
-rw-r--r--scene/resources/scene_format_text.cpp783
-rw-r--r--scene/resources/scene_format_text.h26
28 files changed, 942 insertions, 480 deletions
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 9eff107827..40013814f8 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -205,7 +205,7 @@ void Navigation2D::_navpoly_unlink(int p_id) {
nm.linked = false;
}
-int Navigation2D::navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) {
+int Navigation2D::navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) {
int id = last_id++;
NavMesh nm;
@@ -708,7 +708,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) {
void Navigation2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("navpoly_create", "mesh", "xform", "owner"), &Navigation2D::navpoly_create, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform);
ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove);
diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h
index bb97e1a9a9..02dbcb0f96 100644
--- a/scene/2d/navigation2d.h
+++ b/scene/2d/navigation2d.h
@@ -159,7 +159,7 @@ protected:
public:
//API should be as dynamic as possible
- int navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL);
+ int navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL);
void navpoly_set_transform(int p_id, const Transform2D &p_xform);
void navpoly_remove(int p_id);
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index c53241e985..5a6a5128e6 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -293,7 +293,7 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) {
if (navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
}
}
@@ -324,7 +324,7 @@ void NavigationPolygonInstance::_notification(int p_what) {
if (enabled && navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
break;
}
@@ -419,7 +419,7 @@ void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolyg
}
if (navigation && navpoly.is_valid() && enabled) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
//update_gizmo();
_change_notify("navpoly");
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 1e34372d1e..7b30ddaa56 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -486,7 +486,7 @@ void TileMap::_update_dirty_quadrants() {
xform.set_origin(offset.floor() + q.pos);
_fix_cell_transform(xform, c, npoly_ofs + center_ofs, s);
- int pid = navigation->navpoly_create(navpoly, nav_rel * xform);
+ int pid = navigation->navpoly_add(navpoly, nav_rel * xform);
Quadrant::NavPoly np;
np.id = pid;
@@ -739,6 +739,26 @@ void TileMap::update_bitmask_area(const Vector2 &p_pos) {
}
}
+void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end) {
+
+ if ((p_end.x < p_start.x || p_end.y < p_start.y) || (p_end.x == p_start.x && p_end.y == p_start.y)) {
+ int i;
+ Array a = get_used_cells();
+ for (i = 0; i < a.size(); i++) {
+ // update_bitmask_area() in order to update cells adjacent to the
+ // current cell, since ordering in array may not be reliable
+ Vector2 vector = (Vector2)a[i];
+ update_bitmask_area(Vector2(vector.x, vector.y));
+ }
+ return;
+ }
+ for (int x = p_start.x - 1; x <= p_end.x + 1; x++) {
+ for (int y = p_start.y - 1; y <= p_end.y + 1; y++) {
+ update_cell_bitmask(x, y);
+ }
+ }
+}
+
void TileMap::update_cell_bitmask(int p_x, int p_y) {
PosKey p(p_x, p_y);
@@ -1507,6 +1527,9 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants);
ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
+ ClassDB::bind_method(D_METHOD("update_bitmask_area"), &TileMap::update_bitmask_area);
+ ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2()));
+
ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data);
ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index e5608884c4..8f0b2e6e4c 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -245,6 +245,7 @@ public:
void make_bitmask_area_dirty(const Vector2 &p_pos);
void update_bitmask_area(const Vector2 &p_pos);
+ void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2());
void update_cell_bitmask(int p_x, int p_y);
void update_dirty_bitmask();
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 8af8c2f7da..99d14e7f74 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -175,6 +175,7 @@ BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const {
void BakedLightmap::set_extents(const Vector3 &p_extents) {
extents = p_extents;
+ update_gizmo();
}
Vector3 BakedLightmap::get_extents() const {
@@ -701,6 +702,12 @@ void BakedLightmap::_bind_methods() {
BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH);
BIND_ENUM_CONSTANT(BAKE_MODE_CONE_TRACE);
BIND_ENUM_CONSTANT(BAKE_MODE_RAY_TRACE);
+
+ BIND_ENUM_CONSTANT(BAKE_ERROR_OK);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED);
}
BakedLightmap::BakedLightmap() {
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index af210fff1c..72c0b979af 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -56,126 +56,16 @@ void Camera::_update_camera_mode() {
}
}
-bool Camera::_set(const StringName &p_name, const Variant &p_value) {
-
- bool changed_all = false;
- if (p_name == "projection") {
-
- int proj = p_value;
- if (proj == PROJECTION_PERSPECTIVE)
- mode = PROJECTION_PERSPECTIVE;
- if (proj == PROJECTION_ORTHOGONAL)
- mode = PROJECTION_ORTHOGONAL;
-
- changed_all = true;
- } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx")
- fov = p_value;
- else if (p_name == "size" || p_name == "sizex" || p_name == "sizey")
- size = p_value;
- else if (p_name == "near")
- near = p_value;
- else if (p_name == "far")
- far = p_value;
- else if (p_name == "keep_aspect")
- set_keep_aspect_mode(KeepAspect(int(p_value)));
- else if (p_name == "vaspect")
- set_keep_aspect_mode(p_value ? KEEP_WIDTH : KEEP_HEIGHT);
- else if (p_name == "h_offset")
- h_offset = p_value;
- else if (p_name == "v_offset")
- v_offset = p_value;
- else if (p_name == "current") {
- if (p_value.operator bool()) {
- make_current();
- } else {
- clear_current();
+void Camera::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "fov") {
+ if (mode == PROJECTION_ORTHOGONAL) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
- } else if (p_name == "cull_mask") {
- set_cull_mask(p_value);
- } else if (p_name == "environment") {
- set_environment(p_value);
- } else if (p_name == "doppler/tracking") {
- set_doppler_tracking(DopplerTracking(int(p_value)));
- } else
- return false;
-
- _update_camera_mode();
- if (changed_all)
- _change_notify();
- return true;
-}
-bool Camera::_get(const StringName &p_name, Variant &r_ret) const {
-
- if (p_name == "projection") {
- r_ret = mode;
- } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx")
- r_ret = fov;
- else if (p_name == "size" || p_name == "sizex" || p_name == "sizey")
- r_ret = size;
- else if (p_name == "near")
- r_ret = near;
- else if (p_name == "far")
- r_ret = far;
- else if (p_name == "keep_aspect")
- r_ret = int(keep_aspect);
- else if (p_name == "current") {
-
- if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
- r_ret = current;
- } else {
- r_ret = is_current();
+ } else if (p_property.name == "size") {
+ if (mode == PROJECTION_PERSPECTIVE) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
- } else if (p_name == "cull_mask") {
- r_ret = get_cull_mask();
- } else if (p_name == "h_offset") {
- r_ret = get_h_offset();
- } else if (p_name == "v_offset") {
- r_ret = get_v_offset();
- } else if (p_name == "environment") {
- r_ret = get_environment();
- } else if (p_name == "doppler/tracking") {
- r_ret = get_doppler_tracking();
- } else
- return false;
-
- return true;
-}
-
-void Camera::_get_property_list(List<PropertyInfo> *p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"));
-
- switch (mode) {
-
- case PROJECTION_PERSPECTIVE: {
-
- p_list->push_back(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_NOEDITOR));
- if (keep_aspect == KEEP_WIDTH)
- p_list->push_back(PropertyInfo(Variant::REAL, "fovx", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR));
- else
- p_list->push_back(PropertyInfo(Variant::REAL, "fovy", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR));
-
- } break;
- case PROJECTION_ORTHOGONAL: {
-
- p_list->push_back(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "1,16384,0.01", PROPERTY_USAGE_NOEDITOR));
- if (keep_aspect == KEEP_WIDTH)
- p_list->push_back(PropertyInfo(Variant::REAL, "sizex", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR));
- else
- p_list->push_back(PropertyInfo(Variant::REAL, "sizey", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR));
-
- } break;
}
-
- p_list->push_back(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
- p_list->push_back(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER));
- p_list->push_back(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"));
- p_list->push_back(PropertyInfo(Variant::REAL, "h_offset"));
- p_list->push_back(PropertyInfo(Variant::REAL, "v_offset"));
- p_list->push_back(PropertyInfo(Variant::INT, "doppler/tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"));
}
void Camera::_update_camera() {
@@ -282,6 +172,14 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
update_gizmo();
}
+void Camera::set_projection(Camera::Projection p_mode) {
+ if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) {
+ mode = p_mode;
+ _update_camera_mode();
+ _change_notify();
+ }
+}
+
RID Camera::get_camera() const {
return camera;
@@ -311,6 +209,14 @@ void Camera::clear_current() {
}
}
+void Camera::set_current(bool p_current) {
+ if (p_current) {
+ make_current();
+ } else {
+ clear_current();
+ }
+}
+
bool Camera::is_current() const {
if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
@@ -481,6 +387,7 @@ void Camera::set_environment(const Ref<Environment> &p_environment) {
VS::get_singleton()->camera_set_environment(camera, environment->get_rid());
else
VS::get_singleton()->camera_set_environment(camera, RID());
+ _update_camera_mode();
}
Ref<Environment> Camera::get_environment() const {
@@ -489,10 +396,9 @@ Ref<Environment> Camera::get_environment() const {
}
void Camera::set_keep_aspect_mode(KeepAspect p_aspect) {
-
keep_aspect = p_aspect;
VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH);
-
+ _update_camera_mode();
_change_notify();
}
@@ -501,6 +407,15 @@ Camera::KeepAspect Camera::get_keep_aspect_mode() const {
return keep_aspect;
}
+void Camera::set_vaspect(bool p_vaspect) {
+ set_keep_aspect_mode(p_vaspect ? KEEP_WIDTH : KEEP_HEIGHT);
+ _update_camera_mode();
+}
+
+bool Camera::get_vaspect() const {
+ return keep_aspect == KEEP_HEIGHT;
+}
+
void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
if (doppler_tracking == p_tracking)
@@ -511,6 +426,7 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
velocity_tracker->reset(get_global_transform().origin);
}
+ _update_camera_mode();
}
Camera::DopplerTracking Camera::get_doppler_tracking() const {
@@ -529,13 +445,19 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
ClassDB::bind_method(D_METHOD("clear_current"), &Camera::clear_current);
+ ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov);
ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size);
ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar);
ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear);
+ ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov);
+ ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size);
+ ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar);
+ ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear);
ClassDB::bind_method(D_METHOD("get_projection"), &Camera::get_projection);
+ ClassDB::bind_method(D_METHOD("set_projection"), &Camera::set_projection);
ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera::set_h_offset);
ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera::get_h_offset);
ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera::set_v_offset);
@@ -546,10 +468,26 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_environment"), &Camera::get_environment);
ClassDB::bind_method(D_METHOD("set_keep_aspect_mode", "mode"), &Camera::set_keep_aspect_mode);
ClassDB::bind_method(D_METHOD("get_keep_aspect_mode"), &Camera::get_keep_aspect_mode);
+ ClassDB::bind_method(D_METHOD("set_vaspect"), &Camera::set_vaspect);
+ ClassDB::bind_method(D_METHOD("get_vaspect"), &Camera::get_vaspect);
ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera::set_doppler_tracking);
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vaspect"), "set_vaspect", "get_vaspect");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"), "set_projection", "get_projection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "near"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "far"), "set_zfar", "get_zfar");
+
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
@@ -586,10 +524,30 @@ Camera::Projection Camera::get_projection() const {
return mode;
}
-void Camera::set_cull_mask(uint32_t p_layers) {
+void Camera::set_fov(float p_fov) {
+ fov = p_fov;
+ _update_camera_mode();
+}
+
+void Camera::set_size(float p_size) {
+ size = p_size;
+ _update_camera_mode();
+}
+
+void Camera::set_znear(float p_znear) {
+ near = p_znear;
+ _update_camera_mode();
+}
+void Camera::set_zfar(float p_zfar) {
+ far = p_zfar;
+ _update_camera_mode();
+}
+
+void Camera::set_cull_mask(uint32_t p_layers) {
layers = p_layers;
VisualServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ _update_camera_mode();
}
uint32_t Camera::get_cull_mask() const {
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 73c6844c1a..520afb962b 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -95,10 +95,8 @@ protected:
virtual void _request_camera_update();
void _update_camera_mode();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &property) const;
static void _bind_methods();
@@ -111,9 +109,11 @@ public:
void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_orthogonal(float p_size, float p_z_near, float p_z_far);
+ void set_projection(Camera::Projection p_mode);
void make_current();
void clear_current();
+ void set_current(bool p_current);
bool is_current() const;
RID get_camera() const;
@@ -124,6 +124,11 @@ public:
float get_znear() const;
Projection get_projection() const;
+ void set_fov(float p_fov);
+ void set_size(float p_size);
+ void set_zfar(float p_zfar);
+ void set_znear(float p_znear);
+
virtual Transform get_camera_transform() const;
Vector3 project_ray_normal(const Point2 &p_pos) const;
@@ -143,6 +148,8 @@ public:
void set_keep_aspect_mode(KeepAspect p_aspect);
KeepAspect get_keep_aspect_mode() const;
+ void set_vaspect(bool p_vaspect);
+ bool get_vaspect() const;
void set_v_offset(float p_offset);
float get_v_offset() const;
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index b6507aedb3..78cf75e3b3 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -202,7 +202,7 @@ void Navigation::_navmesh_unlink(int p_id) {
nm.linked = false;
}
-int Navigation::navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) {
+int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) {
int id = last_id++;
NavMesh nm;
@@ -686,7 +686,7 @@ Vector3 Navigation::get_up_vector() const {
void Navigation::_bind_methods() {
- ClassDB::bind_method(D_METHOD("navmesh_create", "mesh", "xform", "owner"), &Navigation::navmesh_create, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform);
ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove);
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
index d9a38f7b00..134afa2278 100644
--- a/scene/3d/navigation.h
+++ b/scene/3d/navigation.h
@@ -166,7 +166,7 @@ public:
Vector3 get_up_vector() const;
//API should be as dynamic as possible
- int navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL);
+ int navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner = NULL);
void navmesh_set_transform(int p_id, const Transform &p_xform);
void navmesh_remove(int p_id);
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 40750cdfe8..4fb12b8fac 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -471,7 +471,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) {
if (navmesh.is_valid()) {
- nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
}
}
@@ -508,7 +508,7 @@ void NavigationMeshInstance::_notification(int p_what) {
if (enabled && navmesh.is_valid()) {
- nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
break;
}
@@ -568,7 +568,7 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh> &p_na
navmesh = p_navmesh;
if (navigation && navmesh.is_valid() && enabled) {
- nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
if (debug_view && navmesh.is_valid()) {
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 821f1a5a78..b445ccc5a9 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -598,6 +598,11 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
+ code += "float rand_from_seed_m1_p1(inout uint seed) {\n";
+ code += " return rand_from_seed(seed)*2.0-1.0;\n";
+ code += "}\n";
+ code += "\n";
+
//improve seed quality
code += "uint hash(uint x) {\n";
code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
@@ -614,6 +619,8 @@ void ParticlesMaterial::_update_shader() {
code += " float scale_rand = rand_from_seed(alt_seed);\n";
code += " float hue_rot_rand = rand_from_seed(alt_seed);\n";
code += " float anim_offset_rand = rand_from_seed(alt_seed);\n";
+ code += " float pi = 3.14159;\n";
+ code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
if (emission_shape >= EMISSION_SHAPE_POINTS) {
@@ -638,23 +645,28 @@ void ParticlesMaterial::_update_shader() {
else
code += " float tex_anim_offset = 0.0;\n";
+ code += " float spread_rad = spread*degree_to_rad;\n";
+
if (flags[FLAG_DISABLE_Z]) {
- code += " float angle1 = (rand_from_seed(alt_seed)*2.0-1.0)*spread/180.0*3.1416;\n";
- code += " vec3 rot = vec3( cos(angle1), sin(angle1),0.0 );\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n";
+ code += " vec3 rot = vec3( cos(angle1_rad), sin(angle1_rad),0.0 );\n";
code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
} else {
//initiate velocity spread in 3D
- code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
- code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
- code += " vec3 rot_xz = vec3( sin(angle1), 0.0, cos(angle1) );\n";
- code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
- code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n";
+ code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad*(1.0-flatness);\n";
+ code += " vec3 direction_xz = vec3( sin(angle1_rad), 0, cos(angle1_rad));\n";
+ code += " vec3 direction_yz = vec3( 0, sin(angle2_rad), cos(angle2_rad));\n";
+ code += " direction_yz.z = direction_yz.z / sqrt(direction_yz.z); //better uniform distribution\n";
+ code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
+ code += " direction = normalize(direction);\n";
+ code += " VELOCITY = direction*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
}
code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
- code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+ code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle
code += " CUSTOM.y = 0.0;\n"; //phase
code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1)
switch (emission_shape) {
@@ -777,7 +789,7 @@ void ParticlesMaterial::_update_shader() {
code += " float orbit_amount = (orbit_velocity+tex_orbit_velocity)*mix(1.0,rand_from_seed(alt_seed),orbit_velocity_random);\n";
code += " if (orbit_amount!=0.0) {\n";
- code += " float ang = orbit_amount * DELTA * 3.1416 * 2.0;\n";
+ code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
code += " mat2 rot = mat2(vec2(cos(ang),-sin(ang)),vec2(sin(ang),cos(ang)));\n";
code += " TRANSFORM[3].xy-=diff.xy;\n";
code += " TRANSFORM[3].xy+=rot * diff.xy;\n";
@@ -800,7 +812,7 @@ void ParticlesMaterial::_update_shader() {
code += " }\n";
code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
code += " base_angle += CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n";
- code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+ code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle
code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
if (flags[FLAG_ANIM_LOOP]) {
code += " CUSTOM.z = mod(CUSTOM.z,1.0);\n"; //loop
@@ -821,7 +833,7 @@ void ParticlesMaterial::_update_shader() {
else
code += " float tex_hue_variation = 0.0;\n";
- code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
+ code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*pi*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
code += " float hue_rot_c = cos(hue_rot_angle);\n";
code += " float hue_rot_s = sin(hue_rot_angle);\n";
code += " mat4 hue_rot_mat = mat4( vec4(0.299, 0.587, 0.114, 0.0),\n";
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 98dc1590d8..c05dfddeca 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -1781,7 +1781,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
//print_line("bake line " + itos(i) + " / " + itos(height));
#ifdef _OPENMP
-#pragma omp parallel for
+#pragma omp parallel for schedule(dynamic, 1)
#endif
for (int j = 0; j < width; j++) {
@@ -1878,12 +1878,14 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
LightMap *lightmap_ptr = lightmap.ptrw();
const Cell *cells = bake_cells.ptr();
const Light *light = bake_light.ptr();
-
+#ifdef _OPENMP
+#pragma omp parallel
+#endif
for (int i = 0; i < height; i++) {
//print_line("bake line " + itos(i) + " / " + itos(height));
#ifdef _OPENMP
-#pragma omp parallel for
+#pragma omp parallel for schedule(dynamic, 1)
#endif
for (int j = 0; j < width; j++) {
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index d4912339da..9a55073bb6 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -289,10 +289,17 @@ bool WindowDialog::get_resizable() const {
Size2 WindowDialog::get_minimum_size() const {
Ref<Font> font = get_font("title_font", "WindowDialog");
- int msx = close_button->get_combined_minimum_size().x;
- msx += font->get_string_size(title).x;
- return Size2(msx, 1);
+ const int button_width = close_button->get_combined_minimum_size().x;
+ const int title_width = font->get_string_size(title).x;
+ const int padding = button_width / 2;
+ const int button_area = button_width + padding;
+
+ // as the title gets centered, title_width + close_button_width is not enough.
+ // we want a width w, such that w / 2 - title_width / 2 >= button_area, i.e.
+ // w >= 2 * button_area + title_width
+
+ return Size2(2 * button_area + title_width, 1);
}
TextureButton *WindowDialog::get_close_button() {
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 32f889e826..698676cc39 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -42,24 +42,6 @@ String PopupMenu::_get_accel_text(int p_item) const {
else if (items[p_item].accel)
return keycode_get_string(items[p_item].accel);
return String();
-
- /*
- String atxt;
- if (p_accel&KEY_MASK_SHIFT)
- atxt+="Shift+";
- if (p_accel&KEY_MASK_ALT)
- atxt+="Alt+";
- if (p_accel&KEY_MASK_CTRL)
- atxt+="Ctrl+";
- if (p_accel&KEY_MASK_META)
- atxt+="Meta+";
-
- p_accel&=KEY_CODE_MASK;
-
- atxt+=String::chr(p_accel).to_upper();
-
- return atxt;
-*/
}
Size2 PopupMenu::get_minimum_size() const {
@@ -136,7 +118,6 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
Ref<Font> font = get_font("font");
int vseparation = get_constant("vseparation");
- //int hseparation = get_constant("hseparation");
float font_h = font->get_height();
for (int i = 0; i < items.size(); i++) {
@@ -230,6 +211,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
update();
+
+ if (items[i].submenu != "" && submenu_over != i) {
+ submenu_over = i;
+ submenu_timer->start();
+ }
break;
}
}
@@ -245,6 +231,11 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
mouse_over = i;
update();
+
+ if (items[i].submenu != "" && submenu_over != i) {
+ submenu_over = i;
+ submenu_timer->start();
+ }
break;
}
}
@@ -500,6 +491,13 @@ void PopupMenu::_notification(int p_what) {
} break;
case NOTIFICATION_MOUSE_EXIT: {
+ if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) {
+ mouse_over = -1;
+ update();
+ }
+ } break;
+ case NOTIFICATION_POPUP_HIDE: {
+
if (mouse_over >= 0) {
mouse_over = -1;
update();
@@ -1217,6 +1215,7 @@ void PopupMenu::set_invalidate_click_until_motion() {
PopupMenu::PopupMenu() {
mouse_over = -1;
+ submenu_over = -1;
set_focus_mode(FOCUS_ALL);
set_as_toplevel(true);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 05c6e9f77e..6fbc58a38a 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -31,6 +31,11 @@
#include "os/keyboard.h"
#include "os/os.h"
#include "scene/scene_string_names.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
if (p_free) {
@@ -370,7 +375,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
Color uc = color;
uc.a *= 0.5;
int uy = y + lh - fh + ascent + 2;
- VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc);
+ float underline_width = 1.0;
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc, underline_width);
}
ofs += cw;
}
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 665ae8b6dd..70b8616af1 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -184,10 +184,10 @@ void Slider::_notification(int p_what) {
focus->draw(ci,Rect2i(Point2i(),Size2i(style->get_minimum_size().width+style->get_center_size().width,size.height)));
*/
if (ticks > 1) {
- int tickarea = size.height - tick->get_height();
+ int grabber_offset = (grabber->get_size().height / 2 - tick->get_height() / 2);
for (int i = 0; i < ticks; i++) {
if (!ticks_on_borders && (i == 0 || i + 1 == ticks)) continue;
- int ofs = i * tickarea / (ticks - 1);
+ int ofs = (i * areasize / (ticks - 1)) + grabber_offset;
tick->draw(ci, Point2i((size.width - widget_width) / 2, ofs));
}
}
@@ -205,10 +205,10 @@ void Slider::_notification(int p_what) {
*/
if (ticks > 1) {
- int tickarea = size.width - tick->get_width();
+ int grabber_offset = (grabber->get_size().width / 2 - tick->get_width() / 2);
for (int i = 0; i < ticks; i++) {
if ((!ticks_on_borders) && ((i == 0) || ((i + 1) == ticks))) continue;
- int ofs = i * tickarea / (ticks - 1);
+ int ofs = (i * areasize / (ticks - 1)) + grabber_offset;
tick->draw(ci, Point2i(ofs, (size.height - widget_height) / 2));
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e5169089f2..83aee5ca30 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1664,17 +1664,22 @@ void TextEdit::backspace_at_cursor() {
cursor_set_column(prev_column);
}
-void TextEdit::indent_selection_right() {
+void TextEdit::indent_right() {
- if (!is_selection_active()) {
- return;
- }
+ int start_line;
+ int end_line;
begin_complex_operation();
- int start_line = get_selection_from_line();
- int end_line = get_selection_to_line();
+
+ if (is_selection_active()) {
+ start_line = get_selection_from_line();
+ end_line = get_selection_to_line();
+ } else {
+ start_line = cursor.line;
+ end_line = start_line;
+ }
// ignore if the cursor is not past the first column
- if (get_selection_to_column() == 0) {
+ if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
@@ -1688,23 +1693,32 @@ void TextEdit::indent_selection_right() {
set_line(i, line_text);
}
- // fix selection being off by one on the last line
- selection.to_column++;
+ // fix selection and cursor being off by one on the last line
+ if (is_selection_active()) {
+ selection.to_column++;
+ selection.from_column++;
+ }
+ cursor.column++;
end_complex_operation();
update();
}
-void TextEdit::indent_selection_left() {
+void TextEdit::indent_left() {
- if (!is_selection_active()) {
- return;
- }
+ int start_line;
+ int end_line;
begin_complex_operation();
- int start_line = get_selection_from_line();
- int end_line = get_selection_to_line();
+
+ if (is_selection_active()) {
+ start_line = get_selection_from_line();
+ end_line = get_selection_to_line();
+ } else {
+ start_line = cursor.line;
+ end_line = start_line;
+ }
// ignore if the cursor is not past the first column
- if (get_selection_to_column() == 0) {
+ if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
String last_line_text = get_line(end_line);
@@ -1721,9 +1735,15 @@ void TextEdit::indent_selection_left() {
}
}
- // fix selection being off by one on the last line
- if (last_line_text != get_line(end_line) && selection.to_column > 0) {
- selection.to_column--;
+ // fix selection and cursor being off by one on the last line
+ if (is_selection_active() && last_line_text != get_line(end_line)) {
+ if (selection.to_column > 0)
+ selection.to_column--;
+ if (selection.from_column > 0)
+ selection.from_column--;
+ }
+ if (cursor.column > 0) {
+ cursor.column--;
}
end_complex_operation();
update();
@@ -2216,9 +2236,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
case KEY_TAB: {
if (k->get_shift()) {
- indent_selection_left();
+ indent_left();
} else {
- indent_selection_right();
+ indent_right();
}
dobreak = true;
accept_event();
@@ -2389,8 +2409,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (readonly)
break;
- if (selection.active) {
-
+ if (is_selection_active()) {
+ if (k->get_shift()) {
+ indent_left();
+ } else {
+ indent_right();
+ }
} else {
if (k->get_shift()) {
@@ -5444,8 +5468,10 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut);
ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste);
- ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
+
ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select);
+ ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
+ ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
ClassDB::bind_method(D_METHOD("is_selection_active"), &TextEdit::is_selection_active);
ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index dd305d5822..edef28cc25 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -443,8 +443,8 @@ public:
void set_line(int line, String new_text);
void backspace_at_cursor();
- void indent_selection_left();
- void indent_selection_right();
+ void indent_left();
+ void indent_right();
int get_indent_level(int p_line) const;
inline void set_scroll_pass_end_of_file(bool p_enabled) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index ab12d123ba..b5b42e8f29 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -30,6 +30,7 @@
#include "tree.h"
#include <limits.h>
+#include "math_funcs.h"
#include "os/input.h"
#include "os/keyboard.h"
#include "os/os.h"
@@ -37,6 +38,10 @@
#include "project_settings.h"
#include "scene/main/viewport.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
void TreeItem::move_to_top() {
if (!parent || parent->childs == this)
@@ -1412,9 +1417,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (c->get_children() != NULL)
root_pos -= Point2i(cache.arrow->get_width(), 0);
+ float line_width = 1.0;
+#ifdef TOOLS_ENABLED
+ line_width *= EDSCALE;
+#endif
+
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
- VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x, root_pos.y), cache.relationship_line_color);
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color);
+ VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
+ VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width);
}
int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c);
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 672e893f1b..4afdb56f86 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -36,7 +36,6 @@ void HTTPRequest::_redirect_request(const String &p_new_url) {
Error HTTPRequest::_request() {
- //print_line("Requesting:\n\tURL: "+url+"\n\tString: "+request_string+"\n\tPort: "+itos(port)+"\n\tSSL: "+itos(use_ssl)+"\n\tValidate SSL: "+itos(validate_ssl));
return client->connect_to_host(url, port, use_ssl, validate_ssl);
}
@@ -54,37 +53,32 @@ Error HTTPRequest::_parse_url(const String &p_url) {
downloaded = 0;
redirections = 0;
- //print_line("1 url: "+url);
- if (url.begins_with("http://")) {
-
+ String url_lower = url.to_lower();
+ if (url_lower.begins_with("http://")) {
url = url.substr(7, url.length() - 7);
- //print_line("no SSL");
-
- } else if (url.begins_with("https://")) {
+ } else if (url_lower.begins_with("https://")) {
url = url.substr(8, url.length() - 8);
use_ssl = true;
port = 443;
- //print_line("yes SSL");
} else {
ERR_EXPLAIN("Malformed URL");
ERR_FAIL_V(ERR_INVALID_PARAMETER);
}
- //print_line("2 url: "+url);
+ if (url.length() < 1) {
+ ERR_EXPLAIN("URL too short");
+ ERR_FAIL_V(ERR_INVALID_PARAMETER);
+ }
int slash_pos = url.find("/");
if (slash_pos != -1) {
request_string = url.substr(slash_pos, url.length());
url = url.substr(0, slash_pos);
- //print_line("request string: "+request_string);
} else {
request_string = "/";
- //print_line("no request");
}
- //print_line("3 url: "+url);
-
int colon_pos = url.find(":");
if (colon_pos != -1) {
port = url.substr(colon_pos + 1, url.length()).to_int();
@@ -92,8 +86,6 @@ Error HTTPRequest::_parse_url(const String &p_url) {
ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER);
}
- //print_line("4 url: "+url);
-
return OK;
}
@@ -198,10 +190,8 @@ void HTTPRequest::cancel_request() {
}
client->close();
body.resize(0);
- //downloaded=0;
got_response = false;
response_code = -1;
- //body_len=-1;
request_sent = false;
requesting = false;
}
@@ -221,12 +211,12 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
response_headers.resize(0);
downloaded = 0;
for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
- //print_line("HEADER: "+E->get());
response_headers.push_back(E->get());
}
if (response_code == 301 || response_code == 302) {
- //redirect
+ // Handle redirect
+
if (max_redirects >= 0 && redirections >= max_redirects) {
call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PoolByteArray());
@@ -242,15 +232,13 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
}
}
- //print_line("NEW LOCATION: "+new_request);
-
if (new_request != "") {
- //process redirect
+ // Process redirect
client->close();
- int new_redirs = redirections + 1; //because _request() will clear it
+ int new_redirs = redirections + 1; // Because _request() will clear it
Error err;
if (new_request.begins_with("http")) {
- //new url, request all again
+ // New url, request all again
err = _parse_url(new_request);
} else {
request_string = new_request;
@@ -258,7 +246,6 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
err = _request();
- //print_line("new connection: "+itos(err));
if (err == OK) {
request_sent = false;
got_response = false;
@@ -280,11 +267,11 @@ bool HTTPRequest::_update_connection() {
switch (client->get_status()) {
case HTTPClient::STATUS_DISCONNECTED: {
call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray());
- return true; //end it, since it's doing something
+ return true; // End it, since it's doing something
} break;
case HTTPClient::STATUS_RESOLVING: {
client->poll();
- //must wait
+ // Must wait
return false;
} break;
case HTTPClient::STATUS_CANT_RESOLVE: {
@@ -294,9 +281,9 @@ bool HTTPRequest::_update_connection() {
} break;
case HTTPClient::STATUS_CONNECTING: {
client->poll();
- //must wait
+ // Must wait
return false;
- } break; //connecting to ip
+ } break; // Connecting to IP
case HTTPClient::STATUS_CANT_CONNECT: {
call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PoolStringArray(), PoolByteArray());
@@ -309,7 +296,7 @@ bool HTTPRequest::_update_connection() {
if (!got_response) {
- //no body
+ // No body
bool ret_value;
@@ -320,16 +307,16 @@ bool HTTPRequest::_update_connection() {
return true;
}
if (got_response && body_len < 0) {
- //chunked transfer is done
+ // Chunked transfer is done
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PoolByteArray());
return true;
- //request migh have been done
+ // Request migh have been done
} else {
- //did not request yet, do request
+ // Did not request yet, do request
Error err = client->request(method, request_string, headers, request_data);
if (err != OK) {
@@ -340,13 +327,13 @@ bool HTTPRequest::_update_connection() {
request_sent = true;
return false;
}
- } break; //connected: { } break requests only accepted here
+ } break; // Connected: break requests only accepted here
case HTTPClient::STATUS_REQUESTING: {
- //must wait, it's requesting
+ // Must wait, still requesting
client->poll();
return false;
- } break; // request in progress
+ } break; // Request in progress
case HTTPClient::STATUS_BODY: {
if (!got_response) {
@@ -363,7 +350,7 @@ bool HTTPRequest::_update_connection() {
}
if (client->is_response_chunked()) {
- body_len = -1; //no body len because chunked, change your webserver configuration if you want body len
+ body_len = -1; // No body len because chunked, change your webserver configuration if you want body len
} else {
body_len = client->get_response_body_length();
@@ -383,7 +370,6 @@ bool HTTPRequest::_update_connection() {
}
}
- //print_line("BODY: "+itos(body.size()));
client->poll();
PoolByteArray chunk = client->read_response_body_chunk();
@@ -411,15 +397,11 @@ bool HTTPRequest::_update_connection() {
call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
- /*if (body.size()>=body_len) {
- call_deferred("_request_done",RESULT_BODY_SIZE_MISMATCH,response_code,response_headers,ByteArray());
- return true;
- }*/
}
return false;
- } break; // request resulted in body: { } break which must be read
+ } break; // Request resulted in body: break which must be read
case HTTPClient::STATUS_CONNECTION_ERROR: {
call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PoolStringArray(), PoolByteArray());
return true;
@@ -449,7 +431,7 @@ void HTTPRequest::_notification(int p_what) {
if (done) {
set_process_internal(false);
- //cancel_request(); called from _request done now
+ // cancel_request(); called from _request done now
}
}
@@ -543,7 +525,7 @@ void HTTPRequest::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads");
ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,1024"), "set_max_redirects", "get_max_redirects");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects");
ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "result"), PropertyInfo(Variant::INT, "response_code"), PropertyInfo(Variant::POOL_STRING_ARRAY, "headers"), PropertyInfo(Variant::POOL_BYTE_ARRAY, "body")));
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index 790ff5f7ef..ab5a79c40d 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -42,7 +42,6 @@ class HTTPRequest : public Node {
public:
enum Result {
RESULT_SUCCESS,
- //RESULT_NO_BODY,
RESULT_CHUNKED_BODY_SIZE_MISMATCH,
RESULT_CANT_CONNECT,
RESULT_CANT_RESOLVE,
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index efc5d269a6..af7a6bddd9 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2110,6 +2110,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
StringName script_property_name = CoreStringNames::get_singleton()->_script;
+ List<const Node *> hidden_roots;
List<const Node *> node_tree;
node_tree.push_front(this);
@@ -2120,11 +2121,16 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
for (int i = 0; i < N->get()->get_child_count(); ++i) {
+ Node *descendant = N->get()->get_child(i);
// Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
- if (N->get()->get_child(i)->data.owner != this)
+ // but remember non-instanced nodes that are hidden below instanced ones
+ if (descendant->data.owner != this) {
+ if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this)
+ hidden_roots.push_back(descendant);
continue;
+ }
- node_tree.push_back(N->get()->get_child(i));
+ node_tree.push_back(descendant);
}
}
}
@@ -2201,6 +2207,34 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
node->add_child(dup);
+ if (i < node->get_child_count() - 1) {
+ node->move_child(dup, i);
+ }
+ }
+
+ for (List<const Node *>::Element *E = hidden_roots.front(); E; E = E->next()) {
+
+ Node *parent = node->get_node(get_path_to(E->get()->data.parent));
+ if (!parent) {
+
+ memdelete(node);
+ return NULL;
+ }
+
+ Node *dup = E->get()->_duplicate(p_flags, r_duplimap);
+ if (!dup) {
+
+ memdelete(node);
+ return NULL;
+ }
+
+ parent->add_child(dup);
+ int pos = E->get()->get_position_in_parent();
+
+ if (pos < parent->get_child_count() - 1) {
+
+ parent->move_child(dup, pos);
+ }
}
return node;
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 4635de81e8..f5d7043a40 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1421,7 +1421,7 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
- gui.tooltip_label->set_text(tooltip);
+ gui.tooltip_label->set_text(tooltip.strip_edges());
Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size());
Rect2 vr = gui.tooltip_label->get_viewport_rect();
if (r.size.x + r.position.x > vr.size.x)
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 3a5cb7da2e..879f76e6d8 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -270,6 +270,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (i > 0) {
if (parent) {
parent->_add_child_nocheck(node, snames[n.name]);
+ if (n.index >= 0 && n.index < parent->get_child_count() - 1)
+ parent->move_child(node, n.index);
} else {
//it may be possible that an instanced scene has changed
//and the node has nowhere to go anymore
@@ -386,6 +388,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
nd.name = _nm_get_string(p_node->get_name(), name_map);
nd.instance = -1; //not instanced by default
+ nd.index = p_node->get_index();
// if this node is part of an instanced scene or sub-instanced scene
// we need to get the corresponding instance states.
@@ -1114,7 +1117,10 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
nd.parent = r[idx++];
nd.owner = r[idx++];
nd.type = r[idx++];
- nd.name = r[idx++];
+ uint32_t name_index = r[idx++];
+ nd.name = name_index & ((1 << NAME_INDEX_BITS) - 1);
+ nd.index = (name_index >> NAME_INDEX_BITS);
+ nd.index--; //0 is invaild, stored as 1
nd.instance = r[idx++];
nd.properties.resize(r[idx++]);
for (int j = 0; j < nd.properties.size(); j++) {
@@ -1206,7 +1212,11 @@ Dictionary SceneState::get_bundled_scene() const {
rnodes.push_back(nd.parent);
rnodes.push_back(nd.owner);
rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
+ uint32_t name_index = nd.name;
+ if (nd.index < (1 << (32 - NAME_INDEX_BITS)) - 1) { //save if less than 16k childs
+ name_index |= uint32_t(nd.index + 1) << NAME_INDEX_BITS; //for backwards compatibility, index 0 is no index
+ }
+ rnodes.push_back(name_index);
rnodes.push_back(nd.instance);
rnodes.push_back(nd.properties.size());
for (int j = 0; j < nd.properties.size(); j++) {
@@ -1284,6 +1294,11 @@ StringName SceneState::get_node_name(int p_idx) const {
return names[nodes[p_idx].name];
}
+int SceneState::get_node_index(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, nodes.size(), -1);
+ return nodes[p_idx].index;
+}
+
bool SceneState::is_node_instance_placeholder(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, nodes.size(), false);
@@ -1524,7 +1539,7 @@ int SceneState::add_node_path(const NodePath &p_path) {
node_paths.push_back(p_path);
return (node_paths.size() - 1) | FLAG_ID_IS_PATH;
}
-int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance) {
+int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index) {
NodeData nd;
nd.parent = p_parent;
@@ -1532,6 +1547,7 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
nd.type = p_type;
nd.name = p_name;
nd.instance = p_instance;
+ nd.index = p_index;
nodes.push_back(nd);
@@ -1605,6 +1621,7 @@ void SceneState::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_instance_placeholder", "idx"), &SceneState::get_node_instance_placeholder);
ClassDB::bind_method(D_METHOD("get_node_instance", "idx"), &SceneState::get_node_instance);
ClassDB::bind_method(D_METHOD("get_node_groups", "idx"), &SceneState::_get_node_groups);
+ ClassDB::bind_method(D_METHOD("get_node_index", "idx"), &SceneState::get_node_index);
ClassDB::bind_method(D_METHOD("get_node_property_count", "idx"), &SceneState::get_node_property_count);
ClassDB::bind_method(D_METHOD("get_node_property_name", "idx", "prop_idx"), &SceneState::get_node_property_name);
ClassDB::bind_method(D_METHOD("get_node_property_value", "idx", "prop_idx"), &SceneState::get_node_property_value);
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 20bfb19b1f..70deea24ff 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -48,6 +48,8 @@ class SceneState : public Reference {
enum {
NO_PARENT_SAVED = 0x7FFFFFFF,
+ NAME_INDEX_BITS = 18,
+ NAME_MASK = (1 << NAME_INDEX_BITS) - 1,
};
struct NodeData {
@@ -57,6 +59,7 @@ class SceneState : public Reference {
int type;
int name;
int instance;
+ int index;
struct Property {
@@ -151,6 +154,7 @@ public:
String get_node_instance_placeholder(int p_idx) const;
bool is_node_instance_placeholder(int p_idx) const;
Vector<StringName> get_node_groups(int p_idx) const;
+ int get_node_index(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;
@@ -174,7 +178,7 @@ public:
int find_name(const StringName &p_name) const;
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
- int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance);
+ int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
void add_node_property(int p_node, int p_name, int p_value);
void add_node_group(int p_node, int p_group);
void set_base_scene(int p_idx);
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
index fe23fbf6b3..7bf5f24269 100644
--- a/scene/resources/scene_format_text.cpp
+++ b/scene/resources/scene_format_text.cpp
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene_format_text.h"
-
+#include "core/io/resource_format_binary.h"
#include "os/dir_access.h"
#include "project_settings.h"
#include "version.h"
@@ -53,6 +53,60 @@ Ref<Resource> ResourceInteractiveLoaderText::get_resource() {
return resource;
}
+Error ResourceInteractiveLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
+
+ VariantParser::Token token;
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_NUMBER) {
+ r_err_str = "Expected number (sub-resource index)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int index = token.value;
+
+ if (!p_data->resource_map.has(index)) {
+ Ref<DummyResource> dr;
+ dr.instance();
+ dr->set_subindex(index);
+ p_data->resource_map[index] = dr;
+ p_data->resource_set.insert(dr);
+ }
+
+ r_res = p_data->resource_map[index];
+
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+}
+
+Error ResourceInteractiveLoaderText::_parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
+
+ VariantParser::Token token;
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_NUMBER) {
+ r_err_str = "Expected number (sub-resource index)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int id = token.value;
+
+ ERR_FAIL_COND_V(!p_data->rev_external_resources.has(id), ERR_PARSE_ERROR);
+
+ r_res = p_data->rev_external_resources[id];
+
+ VariantParser::get_token(p_stream, token, line, r_err_str);
+ if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) {
+ r_err_str = "Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ return OK;
+}
+
Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) {
VariantParser::Token token;
@@ -131,6 +185,208 @@ Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream *
return OK;
}
+Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) {
+ Ref<PackedScene> packed_scene;
+ packed_scene.instance();
+
+ while (true) {
+
+ if (next_tag.name == "node") {
+
+ int parent = -1;
+ int owner = -1;
+ int type = -1;
+ int name = -1;
+ int instance = -1;
+ int index = -1;
+ //int base_scene=-1;
+
+ if (next_tag.fields.has("name")) {
+ name = packed_scene->get_state()->add_name(next_tag.fields["name"]);
+ }
+
+ if (next_tag.fields.has("parent")) {
+ NodePath np = next_tag.fields["parent"];
+ np.prepend_period(); //compatible to how it manages paths internally
+ parent = packed_scene->get_state()->add_node_path(np);
+ }
+
+ if (next_tag.fields.has("type")) {
+ type = packed_scene->get_state()->add_name(next_tag.fields["type"]);
+ } else {
+ type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced
+ }
+
+ if (next_tag.fields.has("instance")) {
+
+ instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
+
+ if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) {
+ packed_scene->get_state()->set_base_scene(instance);
+ instance = -1;
+ }
+ }
+
+ if (next_tag.fields.has("instance_placeholder")) {
+
+ String path = next_tag.fields["instance_placeholder"];
+
+ int path_v = packed_scene->get_state()->add_value(path);
+
+ if (packed_scene->get_state()->get_node_count() == 0) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Instance Placeholder can't be used for inheritance.";
+ _printerr();
+ return Ref<PackedScene>();
+ }
+
+ instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER;
+ }
+
+ if (next_tag.fields.has("owner")) {
+ owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
+ } else {
+ if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1))
+ owner = 0; //if no owner, owner is root
+ }
+
+ if (next_tag.fields.has("index")) {
+ index = next_tag.fields["index"];
+ }
+
+ int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index);
+
+ if (next_tag.fields.has("groups")) {
+
+ Array groups = next_tag.fields["groups"];
+ for (int i = 0; i < groups.size(); i++) {
+ packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i]));
+ }
+ }
+
+ while (true) {
+
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &parser);
+
+ if (error) {
+ if (error != ERR_FILE_EOF) {
+ _printerr();
+ return Ref<PackedScene>();
+ } else {
+ return packed_scene;
+ }
+ }
+
+ if (assign != String()) {
+ int nameidx = packed_scene->get_state()->add_name(assign);
+ int valueidx = packed_scene->get_state()->add_value(value);
+ packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
+ //it's assignment
+ } else if (next_tag.name != String()) {
+ break;
+ }
+ }
+ } else if (next_tag.name == "connection") {
+
+ if (!next_tag.fields.has("from")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "missing 'from' field fron connection tag";
+ return Ref<PackedScene>();
+ }
+
+ if (!next_tag.fields.has("to")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "missing 'to' field fron connection tag";
+ return Ref<PackedScene>();
+ }
+
+ if (!next_tag.fields.has("signal")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "missing 'signal' field fron connection tag";
+ return Ref<PackedScene>();
+ }
+
+ if (!next_tag.fields.has("method")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "missing 'method' field fron connection tag";
+ return Ref<PackedScene>();
+ }
+
+ NodePath from = next_tag.fields["from"];
+ NodePath to = next_tag.fields["to"];
+ StringName method = next_tag.fields["method"];
+ StringName signal = next_tag.fields["signal"];
+ int flags = CONNECT_PERSIST;
+ Array binds;
+
+ if (next_tag.fields.has("flags")) {
+ flags = next_tag.fields["flags"];
+ }
+
+ if (next_tag.fields.has("binds")) {
+ binds = next_tag.fields["binds"];
+ }
+
+ Vector<int> bind_ints;
+ for (int i = 0; i < binds.size(); i++) {
+ bind_ints.push_back(packed_scene->get_state()->add_value(binds[i]));
+ }
+
+ packed_scene->get_state()->add_connection(
+ packed_scene->get_state()->add_node_path(from.simplified()),
+ packed_scene->get_state()->add_node_path(to.simplified()),
+ packed_scene->get_state()->add_name(signal),
+ packed_scene->get_state()->add_name(method),
+ flags,
+ bind_ints);
+
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser);
+
+ if (error) {
+ if (error != ERR_FILE_EOF) {
+ _printerr();
+ return Ref<PackedScene>();
+ } else {
+ return packed_scene;
+ }
+ }
+ } else if (next_tag.name == "editable") {
+
+ if (!next_tag.fields.has("path")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "missing 'path' field fron connection tag";
+ _printerr();
+ return Ref<PackedScene>();
+ }
+
+ NodePath path = next_tag.fields["path"];
+
+ packed_scene->get_state()->add_editable_instance(path.simplified());
+
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &parser);
+
+ if (error) {
+ if (error != ERR_FILE_EOF) {
+ _printerr();
+ return Ref<PackedScene>();
+ } else {
+ return packed_scene;
+ }
+ }
+ } else {
+
+ error = ERR_FILE_CORRUPT;
+ _printerr();
+ return Ref<PackedScene>();
+ }
+ }
+
+ return packed_scene;
+}
+
Error ResourceInteractiveLoaderText::poll() {
if (error != OK)
@@ -364,231 +620,21 @@ Error ResourceInteractiveLoaderText::poll() {
return error;
}
- /*
- int add_name(const StringName& p_name);
- int add_value(const Variant& p_value);
- int add_node_path(const NodePath& p_path);
- int add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance);
- void add_node_property(int p_node,int p_name,int p_value);
- void add_node_group(int p_node,int p_group);
- void set_base_scene(int p_idx);
- void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds);
- void add_editable_instance(const NodePath& p_path);
-
- */
-
- int parent = -1;
- int owner = -1;
- int type = -1;
- int name = -1;
- int instance = -1;
- //int base_scene=-1;
-
- if (next_tag.fields.has("name")) {
- name = packed_scene->get_state()->add_name(next_tag.fields["name"]);
- }
-
- if (next_tag.fields.has("parent")) {
- NodePath np = next_tag.fields["parent"];
- np.prepend_period(); //compatible to how it manages paths internally
- parent = packed_scene->get_state()->add_node_path(np);
- }
-
- if (next_tag.fields.has("type")) {
- type = packed_scene->get_state()->add_name(next_tag.fields["type"]);
- } else {
- type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced
- }
-
- if (next_tag.fields.has("instance")) {
-
- instance = packed_scene->get_state()->add_value(next_tag.fields["instance"]);
-
- if (packed_scene->get_state()->get_node_count() == 0 && parent == -1) {
- packed_scene->get_state()->set_base_scene(instance);
- instance = -1;
- }
- }
-
- if (next_tag.fields.has("instance_placeholder")) {
-
- String path = next_tag.fields["instance_placeholder"];
-
- int path_v = packed_scene->get_state()->add_value(path);
-
- if (packed_scene->get_state()->get_node_count() == 0) {
- error = ERR_FILE_CORRUPT;
- error_text = "Instance Placeholder can't be used for inheritance.";
- _printerr();
- return error;
- }
+ Ref<PackedScene> packed_scene = _parse_node_tag(rp);
- instance = path_v | SceneState::FLAG_INSTANCE_IS_PLACEHOLDER;
- }
-
- if (next_tag.fields.has("owner")) {
- owner = packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
- } else {
- if (parent != -1 && !(type == SceneState::TYPE_INSTANCED && instance == -1))
- owner = 0; //if no owner, owner is root
- }
-
- int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance);
-
- if (next_tag.fields.has("groups")) {
-
- Array groups = next_tag.fields["groups"];
- for (int i = 0; i < groups.size(); i++) {
- packed_scene->get_state()->add_node_group(node_id, packed_scene->get_state()->add_name(groups[i]));
- }
- }
-
- while (true) {
-
- String assign;
- Variant value;
-
- error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
-
- if (error) {
- if (error != ERR_FILE_EOF) {
- _printerr();
- } else {
- resource = packed_scene;
- if (!ResourceCache::has(res_path)) {
- packed_scene->set_path(res_path);
- }
- }
- return error;
- }
-
- if (assign != String()) {
- int nameidx = packed_scene->get_state()->add_name(assign);
- int valueidx = packed_scene->get_state()->add_value(value);
- packed_scene->get_state()->add_node_property(node_id, nameidx, valueidx);
- //it's assignment
- } else if (next_tag.name != String()) {
-
- error = OK;
- return error;
- } else {
-
- resource = packed_scene;
- error = ERR_FILE_EOF;
- return error;
- }
- }
-
- return OK;
-
- } else if (next_tag.name == "connection") {
-
- if (!is_scene) {
-
- error_text += "found the 'connection' tag on a resource file!";
- _printerr();
- error = ERR_FILE_CORRUPT;
+ if (!packed_scene.is_valid())
return error;
- }
- if (!next_tag.fields.has("from")) {
- error = ERR_FILE_CORRUPT;
- error_text = "missing 'from' field fron connection tag";
- return error;
+ error = OK;
+ //get it here
+ resource = packed_scene;
+ if (!ResourceCache::has(res_path)) {
+ packed_scene->set_path(res_path);
}
- if (!next_tag.fields.has("to")) {
- error = ERR_FILE_CORRUPT;
- error_text = "missing 'to' field fron connection tag";
- return error;
- }
-
- if (!next_tag.fields.has("signal")) {
- error = ERR_FILE_CORRUPT;
- error_text = "missing 'signal' field fron connection tag";
- return error;
- }
-
- if (!next_tag.fields.has("method")) {
- error = ERR_FILE_CORRUPT;
- error_text = "missing 'method' field fron connection tag";
- return error;
- }
-
- NodePath from = next_tag.fields["from"];
- NodePath to = next_tag.fields["to"];
- StringName method = next_tag.fields["method"];
- StringName signal = next_tag.fields["signal"];
- int flags = CONNECT_PERSIST;
- Array binds;
-
- if (next_tag.fields.has("flags")) {
- flags = next_tag.fields["flags"];
- }
-
- if (next_tag.fields.has("binds")) {
- binds = next_tag.fields["binds"];
- }
-
- Vector<int> bind_ints;
- for (int i = 0; i < binds.size(); i++) {
- bind_ints.push_back(packed_scene->get_state()->add_value(binds[i]));
- }
-
- packed_scene->get_state()->add_connection(
- packed_scene->get_state()->add_node_path(from.simplified()),
- packed_scene->get_state()->add_node_path(to.simplified()),
- packed_scene->get_state()->add_name(signal),
- packed_scene->get_state()->add_name(method),
- flags,
- bind_ints);
-
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
-
- if (error) {
- if (error != ERR_FILE_EOF) {
- _printerr();
- } else {
- resource = packed_scene;
- }
- }
-
- return error;
- } else if (next_tag.name == "editable") {
-
- if (!is_scene) {
-
- error_text += "found the 'editable' tag on a resource file!";
- _printerr();
- error = ERR_FILE_CORRUPT;
- return error;
- }
-
- if (!next_tag.fields.has("path")) {
- error = ERR_FILE_CORRUPT;
- error_text = "missing 'path' field fron connection tag";
- _printerr();
- return error;
- }
-
- NodePath path = next_tag.fields["path"];
-
- packed_scene->get_state()->add_editable_instance(path.simplified());
-
- error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
-
- if (error) {
- if (error != ERR_FILE_EOF) {
- _printerr();
- } else {
- resource = packed_scene;
- }
- }
-
- return error;
+ return ERR_FILE_EOF;
} else {
-
error_text += "Unknown tag in file: " + next_tag.name;
_printerr();
error = ERR_FILE_CORRUPT;
@@ -804,7 +850,6 @@ void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag)
if (tag.name == "gd_scene") {
is_scene = true;
- packed_scene.instance();
} else if (tag.name == "gd_resource") {
if (!tag.fields.has("type")) {
@@ -846,6 +891,281 @@ void ResourceInteractiveLoaderText::open(FileAccess *p_f, bool p_skip_first_tag)
rp.userdata = this;
}
+static void bs_save_unicode_string(FileAccess *f, const String &p_string, bool p_bit_on_len = false) {
+
+ CharString utf8 = p_string.utf8();
+ if (p_bit_on_len) {
+ f->store_32(utf8.length() + 1 | 0x80000000);
+ } else {
+ f->store_32(utf8.length() + 1);
+ }
+ f->store_buffer((const uint8_t *)utf8.get_data(), utf8.length() + 1);
+}
+
+Error ResourceInteractiveLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) {
+
+ if (error)
+ return error;
+
+ FileAccessRef wf = FileAccess::open(p_path, FileAccess::WRITE);
+ if (!wf) {
+ return ERR_CANT_OPEN;
+ }
+
+ //save header compressed
+ static const uint8_t header[4] = { 'R', 'S', 'R', 'C' };
+ wf->store_buffer(header, 4);
+
+ wf->store_32(0); //endianness, little endian
+ wf->store_32(0); //64 bits file, false for now
+ wf->store_32(VERSION_MAJOR);
+ wf->store_32(VERSION_MINOR);
+ static const int save_format_version = 3; //use format version 3 for saving
+ wf->store_32(save_format_version);
+
+ bs_save_unicode_string(wf.f, is_scene ? "PackedScene" : resource_type);
+ wf->store_64(0); //offset to import metadata, this is no longer used
+ for (int i = 0; i < 14; i++)
+ wf->store_32(0); // reserved
+
+ wf->store_32(0); //string table size, will not be in use
+ size_t ext_res_count_pos = wf->get_position();
+
+ wf->store_32(0); //zero ext resources, still parsing them
+
+ //go with external resources
+
+ DummyReadData dummy_read;
+ VariantParser::ResourceParser rp;
+ rp.ext_func = _parse_ext_resource_dummys;
+ rp.sub_func = _parse_sub_resource_dummys;
+ rp.userdata = &dummy_read;
+
+ while (next_tag.name == "ext_resource") {
+
+ if (!next_tag.fields.has("path")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'path' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("type")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("id")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'id' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ String path = next_tag.fields["path"];
+ String type = next_tag.fields["type"];
+ int index = next_tag.fields["id"];
+
+ bs_save_unicode_string(wf.f, type);
+ bs_save_unicode_string(wf.f, path);
+
+ int lindex = dummy_read.external_resources.size();
+ Ref<DummyResource> dr;
+ dr.instance();
+ dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external
+ dummy_read.external_resources[dr] = lindex;
+ dummy_read.rev_external_resources[index] = dr;
+
+ error = VariantParser::parse_tag(&stream, lines, error_text, next_tag, &rp);
+
+ if (error) {
+ _printerr();
+ return error;
+ }
+ }
+
+ // save external resource table
+ wf->seek(ext_res_count_pos);
+ wf->store_32(dummy_read.external_resources.size());
+ wf->seek_end();
+
+ //now, save resources to a separate file, for now
+
+ size_t sub_res_count_pos = wf->get_position();
+ wf->store_32(0); //zero sub resources, still parsing them
+
+ String temp_file = p_path + ".temp";
+ FileAccessRef wf2 = FileAccess::open(temp_file, FileAccess::WRITE);
+ if (!wf2) {
+ return ERR_CANT_OPEN;
+ }
+
+ Vector<size_t> local_offsets;
+ Vector<size_t> local_pointers_pos;
+
+ while (next_tag.name == "sub_resource" || next_tag.name == "resource") {
+
+ String type;
+ int id = -1;
+ bool main_res;
+
+ if (next_tag.name == "sub_resource") {
+ if (!next_tag.fields.has("type")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("id")) {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Missing 'index' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ type = next_tag.fields["type"];
+ id = next_tag.fields["id"];
+ main_res = false;
+ } else {
+ type = res_type;
+ id = 0; //used for last anyway
+ main_res = true;
+ }
+
+ local_offsets.push_back(wf2->get_position());
+
+ bs_save_unicode_string(wf, "local://" + itos(id));
+ local_pointers_pos.push_back(wf->get_position());
+ wf->store_64(0); //temp local offset
+
+ bs_save_unicode_string(wf2, type);
+ size_t propcount_ofs = wf2->get_position();
+ wf2->store_32(0);
+
+ int prop_count = 0;
+
+ while (true) {
+
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream, lines, error_text, next_tag, assign, value, &rp);
+
+ if (error) {
+ if (main_res && error == ERR_FILE_EOF) {
+ next_tag.name = ""; //exit
+ break;
+ }
+
+ _printerr();
+ return error;
+ }
+
+ if (assign != String()) {
+
+ Map<StringName, int> empty_string_map; //unused
+ bs_save_unicode_string(wf2, assign, true);
+ ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map);
+ prop_count++;
+
+ } else if (next_tag.name != String()) {
+
+ error = OK;
+ break;
+ } else {
+ error = ERR_FILE_CORRUPT;
+ error_text = "Premature end of file while parsing [sub_resource]";
+ _printerr();
+ return error;
+ }
+ }
+
+ wf2->seek(propcount_ofs);
+ wf2->store_32(prop_count);
+ wf2->seek_end();
+ }
+
+ if (next_tag.name == "node") {
+ //this is a node, must save one more!
+
+ if (!is_scene) {
+
+ error_text += "found the 'node' tag on a resource file!";
+ _printerr();
+ error = ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ Ref<PackedScene> packed_scene = _parse_node_tag(rp);
+
+ if (!packed_scene.is_valid())
+ return error;
+
+ error = OK;
+ //get it here
+ List<PropertyInfo> props;
+ packed_scene->get_property_list(&props);
+
+ bs_save_unicode_string(wf, "local://0");
+ local_pointers_pos.push_back(wf->get_position());
+ wf->store_64(0); //temp local offset
+
+ local_offsets.push_back(wf2->get_position());
+ bs_save_unicode_string(wf2, "PackedScene");
+ size_t propcount_ofs = wf2->get_position();
+ wf2->store_32(0);
+
+ int prop_count = 0;
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+
+ if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
+ continue;
+
+ String name = E->get().name;
+ Variant value = packed_scene->get(name);
+
+ Map<StringName, int> empty_string_map; //unused
+ bs_save_unicode_string(wf2, name, true);
+ ResourceFormatSaverBinaryInstance::write_variant(wf2, value, dummy_read.resource_set, dummy_read.external_resources, empty_string_map);
+ prop_count++;
+ }
+
+ wf2->seek(propcount_ofs);
+ wf2->store_32(prop_count);
+ wf2->seek_end();
+ }
+
+ wf2->close();
+
+ size_t offset_from = wf->get_position();
+ wf->seek(sub_res_count_pos); //plus one because the saved one
+ wf->store_32(local_offsets.size());
+
+ for (int i = 0; i < local_offsets.size(); i++) {
+ wf->seek(local_pointers_pos[i]);
+ wf->store_64(local_offsets[i] + offset_from);
+ }
+
+ wf->seek_end();
+
+ Vector<uint8_t> data = FileAccess::get_file_as_array(temp_file);
+ wf->store_buffer(data.ptr(), data.size());
+ {
+ DirAccessRef dar = DirAccess::open(temp_file.get_base_dir());
+ dar->remove(temp_file);
+ }
+
+ wf->store_buffer((const uint8_t *)"RSRC", 4); //magic at end
+
+ wf->close();
+
+ return OK;
+}
+
String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) {
error = OK;
@@ -991,6 +1311,25 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
return ria->rename_dependencies(f, p_path, p_map);
}
+Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
+
+ Error err;
+ FileAccess *f = FileAccess::open(p_src_path, FileAccess::READ, &err);
+
+ if (err != OK) {
+
+ ERR_FAIL_COND_V(err != OK, ERR_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew(ResourceInteractiveLoaderText);
+ String path = p_src_path;
+ ria->local_path = ProjectSettings::get_singleton()->localize_path(path);
+ ria->res_path = ria->local_path;
+ //ria->set_local_path( ProjectSettings::get_singleton()->localize_path(p_path) );
+ ria->open(f);
+ return ria->save_as_binary(f, p_dst_path);
+}
+
/*****************************************************************************************************/
/*****************************************************************************************************/
/*****************************************************************************************************/
@@ -1275,6 +1614,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
StringName type = state->get_node_type(i);
StringName name = state->get_node_name(i);
+ int index = state->get_node_index(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);
@@ -1292,6 +1632,9 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
if (owner != NodePath() && owner != NodePath(".")) {
header += " owner=\"" + String(owner.simplified()) + "\"";
}
+ if (index >= 0) {
+ header += " index=\"" + itos(index) + "\"";
+ }
if (groups.size()) {
String sgroups = " groups=[\n";
diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h
index a72a62037c..5d3c2004c1 100644
--- a/scene/resources/scene_format_text.h
+++ b/scene/resources/scene_format_text.h
@@ -78,9 +78,26 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
Error _parse_sub_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
Error _parse_ext_resource(VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
- VariantParser::ResourceParser rp;
+ // for converter
+ class DummyResource : public Resource {
+ public:
+ };
- Ref<PackedScene> packed_scene;
+ struct DummyReadData {
+
+ Map<RES, int> external_resources;
+ Map<int, RES> rev_external_resources;
+ Set<RES> resource_set;
+ Map<int, RES> resource_map;
+ };
+
+ static Error _parse_sub_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_sub_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); }
+ static Error _parse_ext_resource_dummys(void *p_self, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { return _parse_ext_resource_dummy((DummyReadData *)(p_self), p_stream, r_res, line, r_err_str); }
+
+ static Error _parse_sub_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
+ static Error _parse_ext_resource_dummy(DummyReadData *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str);
+
+ VariantParser::ResourceParser rp;
friend class ResourceFormatLoaderText;
@@ -89,6 +106,8 @@ class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
RES resource;
+ Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser);
+
public:
virtual void set_local_path(const String &p_local_path);
virtual Ref<Resource> get_resource();
@@ -102,6 +121,7 @@ public:
void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
Error rename_dependencies(FileAccess *p_f, const String &p_path, const Map<String, String> &p_map);
+ Error save_as_binary(FileAccess *p_f, const String &p_path);
ResourceInteractiveLoaderText();
~ResourceInteractiveLoaderText();
};
@@ -115,6 +135,8 @@ public:
virtual String get_resource_type(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
+
+ static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path);
};
class ResourceFormatSaverTextInstance {