summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/array.cpp11
-rw-r--r--core/array.h2
-rw-r--r--core/class_db.cpp8
-rw-r--r--core/io/resource_format_binary.cpp3
-rw-r--r--core/list.h48
-rw-r--r--core/math/camera_matrix.cpp86
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/matrix3.cpp15
-rw-r--r--core/math/matrix3.h2
-rw-r--r--core/math/transform.cpp12
-rw-r--r--core/object.h12
-rw-r--r--core/project_settings.cpp10
-rw-r--r--core/resource.cpp3
-rw-r--r--core/script_language.h1
-rw-r--r--core/string_buffer.cpp102
-rw-r--r--core/string_buffer.h82
-rw-r--r--core/string_builder.cpp94
-rw-r--r--core/string_builder.h79
-rw-r--r--core/variant_call.cpp2
-rw-r--r--core/variant_parser.cpp22
20 files changed, 496 insertions, 100 deletions
diff --git a/core/array.cpp b/core/array.cpp
index c35bf5bf0c..2e3fbf858d 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -210,6 +210,17 @@ const Variant &Array::get(int p_idx) const {
return operator[](p_idx);
}
+Array Array::duplicate() const {
+
+ Array new_arr;
+ int element_count = size();
+ new_arr.resize(element_count);
+ for (int i = 0; i < element_count; i++) {
+ new_arr[i] = get(i);
+ }
+
+ return new_arr;
+}
struct _ArrayVariantSort {
_FORCE_INLINE_ bool operator()(const Variant &p_l, const Variant &p_r) const {
diff --git a/core/array.h b/core/array.h
index 777116ab56..8a647dd13b 100644
--- a/core/array.h
+++ b/core/array.h
@@ -84,6 +84,8 @@ public:
Variant pop_back();
Variant pop_front();
+ Array duplicate() const;
+
Array(const Array &p_from);
Array();
~Array();
diff --git a/core/class_db.cpp b/core/class_db.cpp
index 872e466e72..f5ddd9c761 100644
--- a/core/class_db.cpp
+++ b/core/class_db.cpp
@@ -536,11 +536,9 @@ void ClassDB::get_method_list(StringName p_class, List<MethodInfo> *p_methods, b
minfo.return_val = method->get_return_info();
minfo.flags = method->get_hint_flags();
- int defval_count = method->get_default_argument_count();
- minfo.default_arguments.resize(defval_count);
-
- for (int i = 0; i < defval_count; i++) {
- minfo.default_arguments[i] = method->get_default_argument(defval_count - i - 1);
+ for (int i = 0; i < method->get_argument_count(); i++) {
+ if (method->has_default_argument(i))
+ minfo.default_arguments.push_back(method->get_default_argument(i));
}
p_methods->push_back(minfo);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index c5909981ea..084d8ffcab 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1117,6 +1117,9 @@ Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path, cons
memdelete(f);
}
ERR_FAIL_COND_V(!fw, ERR_CANT_CREATE);
+
+ uint8_t magic[4] = { 'R', 'S', 'R', 'C' };
+ fw->store_buffer(magic, 4);
}
bool big_endian = f->get_32();
diff --git a/core/list.h b/core/list.h
index a67287a9ab..da201e9868 100644
--- a/core/list.h
+++ b/core/list.h
@@ -291,6 +291,54 @@ public:
erase(_data->first);
}
+ Element *insert_after(Element *p_element, const T &p_value) {
+ CRASH_COND(p_element && (!_data || p_element->data != _data));
+
+ if (!p_element) {
+ return push_back(p_value);
+ }
+
+ Element *n = memnew_allocator(Element, A);
+ n->value = (T &)p_value;
+ n->prev_ptr = p_element;
+ n->next_ptr = p_element->next_ptr;
+ n->data = _data;
+
+ if (!p_element->next_ptr) {
+ _data->last = n;
+ }
+
+ p_element->next_ptr = n;
+
+ _data->size_cache++;
+
+ return n;
+ }
+
+ Element *insert_before(Element *p_element, const T &p_value) {
+ CRASH_COND(p_element && (!_data || p_element->data != _data));
+
+ if (!p_element) {
+ return push_back(p_value);
+ }
+
+ Element *n = memnew_allocator(Element, A);
+ n->value = (T &)p_value;
+ n->prev_ptr = p_element->prev_ptr;
+ n->next_ptr = p_element;
+ n->data = _data;
+
+ if (!p_element->prev_ptr) {
+ _data->first = n;
+ }
+
+ p_element->prev_ptr = n;
+
+ _data->size_cache++;
+
+ return n;
+ }
+
/**
* find an element in the list,
*/
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index 0512cdd798..572a6c5239 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -265,76 +265,28 @@ void CameraMatrix::get_viewport_size(real_t &r_width, real_t &r_height) const {
bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
- const real_t *matrix = (const real_t *)this->matrix;
-
- ///////--- Near Plane ---///////
- Plane near_plane = Plane(matrix[3] + matrix[2],
- matrix[7] + matrix[6],
- matrix[11] + matrix[10],
- -matrix[15] - matrix[14]);
- near_plane.normalize();
-
- ///////--- Far Plane ---///////
- Plane far_plane = Plane(matrix[2] - matrix[3],
- matrix[6] - matrix[7],
- matrix[10] - matrix[11],
- matrix[15] - matrix[14]);
- far_plane.normalize();
-
- ///////--- Right Plane ---///////
- Plane right_plane = Plane(matrix[0] - matrix[3],
- matrix[4] - matrix[7],
- matrix[8] - matrix[11],
- -matrix[15] + matrix[12]);
- right_plane.normalize();
-
- ///////--- Top Plane ---///////
- Plane top_plane = Plane(matrix[1] - matrix[3],
- matrix[5] - matrix[7],
- matrix[9] - matrix[11],
- -matrix[15] + matrix[13]);
- top_plane.normalize();
-
- Vector3 near_endpoint_left, near_endpoint_right;
- Vector3 far_endpoint_left, far_endpoint_right;
-
- bool res = near_plane.intersect_3(right_plane, top_plane, &near_endpoint_right);
- ERR_FAIL_COND_V(!res, false);
-
- res = far_plane.intersect_3(right_plane, top_plane, &far_endpoint_right);
- ERR_FAIL_COND_V(!res, false);
-
- if ((matrix[8] == 0) && (matrix[9] == 0)) {
- near_endpoint_left = near_endpoint_right;
- near_endpoint_left.x = -near_endpoint_left.x;
-
- far_endpoint_left = far_endpoint_right;
- far_endpoint_left.x = -far_endpoint_left.x;
- } else {
- ///////--- Left Plane ---///////
- Plane left_plane = Plane(matrix[0] + matrix[3],
- matrix[4] + matrix[7],
- matrix[8] + matrix[11],
- -matrix[15] - matrix[12]);
- left_plane.normalize();
+ Vector<Plane> planes = get_projection_planes(Transform());
+ const Planes intersections[8][3]={
+ {PLANE_FAR,PLANE_LEFT,PLANE_TOP},
+ {PLANE_FAR,PLANE_LEFT,PLANE_BOTTOM},
+ {PLANE_FAR,PLANE_RIGHT,PLANE_TOP},
+ {PLANE_FAR,PLANE_RIGHT,PLANE_BOTTOM},
+ {PLANE_NEAR,PLANE_LEFT,PLANE_TOP},
+ {PLANE_NEAR,PLANE_LEFT,PLANE_BOTTOM},
+ {PLANE_NEAR,PLANE_RIGHT,PLANE_TOP},
+ {PLANE_NEAR,PLANE_RIGHT,PLANE_BOTTOM},
+ };
- res = near_plane.intersect_3(left_plane, top_plane, &near_endpoint_left);
- ERR_FAIL_COND_V(!res, false);
+ for(int i=0;i<8;i++) {
- res = far_plane.intersect_3(left_plane, top_plane, &far_endpoint_left);
+ Vector3 point;
+ bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]],planes[intersections[i][2]], &point);
ERR_FAIL_COND_V(!res, false);
+ p_8points[i]=p_transform.xform(point);
}
- p_8points[0] = p_transform.xform(Vector3(near_endpoint_right.x, near_endpoint_right.y, near_endpoint_right.z));
- p_8points[1] = p_transform.xform(Vector3(near_endpoint_right.x, -near_endpoint_right.y, near_endpoint_right.z));
- p_8points[2] = p_transform.xform(Vector3(near_endpoint_left.x, near_endpoint_left.y, near_endpoint_left.z));
- p_8points[3] = p_transform.xform(Vector3(near_endpoint_left.x, -near_endpoint_left.y, near_endpoint_left.z));
- p_8points[4] = p_transform.xform(Vector3(far_endpoint_right.x, far_endpoint_right.y, far_endpoint_right.z));
- p_8points[5] = p_transform.xform(Vector3(far_endpoint_right.x, -far_endpoint_right.y, far_endpoint_right.z));
- p_8points[6] = p_transform.xform(Vector3(far_endpoint_left.x, far_endpoint_left.y, far_endpoint_left.z));
- p_8points[7] = p_transform.xform(Vector3(far_endpoint_left.x, -far_endpoint_left.y, far_endpoint_left.z));
-
return true;
+
}
Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const {
@@ -610,6 +562,12 @@ int CameraMatrix::get_pixels_per_meter(int p_for_pixel_width) const {
return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
}
+bool CameraMatrix::is_orthogonal() const {
+
+ return matrix[3][3]==1.0;
+}
+
+
real_t CameraMatrix::get_fov() const {
const real_t *matrix = (const real_t *)this->matrix;
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 175d0cdb1b..87cc4b95b8 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -69,6 +69,7 @@ struct CameraMatrix {
real_t get_z_near() const;
real_t get_aspect() const;
real_t get_fov() const;
+ bool is_orthogonal() const;
Vector<Plane> get_projection_planes(const Transform &p_transform) const;
@@ -83,6 +84,7 @@ struct CameraMatrix {
Plane xform4(const Plane &p_vec4) const;
_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
+
operator String() const;
void scale_translate_to_fit(const Rect3 &p_aabb);
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index 9732a1ff37..4051de7afb 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -234,7 +234,22 @@ Basis Basis::scaled(const Vector3 &p_scale) const {
return m;
}
+void Basis::set_scale(const Vector3 &p_scale) {
+
+ set_axis(0, get_axis(0).normalized() * p_scale.x);
+ set_axis(1, get_axis(1).normalized() * p_scale.y);
+ set_axis(2, get_axis(2).normalized() * p_scale.z);
+}
+
Vector3 Basis::get_scale() const {
+
+ return Vector3(
+ Vector3(elements[0][0], elements[1][0], elements[2][0]).length(),
+ Vector3(elements[0][1], elements[1][1], elements[2][1]).length(),
+ Vector3(elements[0][2], elements[1][2], elements[2][2]).length());
+}
+
+Vector3 Basis::get_signed_scale() const {
// FIXME: We are assuming M = R.S (R is rotation and S is scaling), and use polar decomposition to extract R and S.
// A polar decomposition is M = O.P, where O is an orthogonal matrix (meaning rotation and reflection) and
// P is a positive semi-definite matrix (meaning it contains absolute values of scaling along its diagonal).
diff --git a/core/math/matrix3.h b/core/math/matrix3.h
index 9c9080ac46..23429888e0 100644
--- a/core/math/matrix3.h
+++ b/core/math/matrix3.h
@@ -97,7 +97,9 @@ public:
void scale(const Vector3 &p_scale);
Basis scaled(const Vector3 &p_scale) const;
+ void set_scale(const Vector3 &p_scale);
Vector3 get_scale() const;
+ Vector3 get_signed_scale() const;
// transposed dot products
_FORCE_INLINE_ real_t tdotx(const Vector3 &v) const {
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index 60df69a509..638a39ab73 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -118,17 +118,17 @@ Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c)
/* not sure if very "efficient" but good enough? */
- Vector3 src_scale = basis.get_scale();
- Quat src_rot = basis;
+ Vector3 src_scale = basis.get_signed_scale();
+ Quat src_rot = basis.orthonormalized();
Vector3 src_loc = origin;
- Vector3 dst_scale = p_transform.basis.get_scale();
+ Vector3 dst_scale = p_transform.basis.get_signed_scale();
Quat dst_rot = p_transform.basis;
Vector3 dst_loc = p_transform.origin;
- Transform dst;
- dst.basis = src_rot.slerp(dst_rot, p_c);
- dst.basis.scale(src_scale.linear_interpolate(dst_scale, p_c));
+ Transform dst; //this could be made faster by using a single function in Basis..
+ dst.basis = src_rot.slerp(dst_rot, p_c).normalized();
+ dst.basis.set_scale(src_scale.linear_interpolate(dst_scale, p_c));
dst.origin = src_loc.linear_interpolate(dst_loc, p_c);
return dst;
diff --git a/core/object.h b/core/object.h
index 6e1ed4308e..644e2b8270 100644
--- a/core/object.h
+++ b/core/object.h
@@ -567,12 +567,6 @@ public:
template <class T>
static T *cast_to(Object *p_object) {
-#ifdef DEBUG_ENABLED
- // TODO there are some legitimate reasons to pass NULL as p_object.
- // we need to figure out how to deal with that in debug mode.
- // This code will return NULL for a NULL input in release mode also.
- ERR_FAIL_COND_V(p_object == NULL, NULL);
-#endif
#ifndef NO_SAFE_CAST
return dynamic_cast<T *>(p_object);
#else
@@ -587,12 +581,6 @@ public:
template <class T>
static const T *cast_to(const Object *p_object) {
-#ifdef DEBUG_ENABLED
- // TODO there are some legitimate reasons to pass NULL as p_object.
- // we need to figure out how to deal with that in debug mode.
- // This code will return NULL for a NULL input in release mode also.
- ERR_FAIL_COND_V(p_object == NULL, NULL);
-#endif
#ifndef NO_SAFE_CAST
return dynamic_cast<const T *>(p_object);
#else
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index a74917162b..23e4961138 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -114,7 +114,15 @@ String ProjectSettings::globalize_path(const String &p_path) const {
return p_path.replace("res:/", resource_path);
};
return p_path.replace("res://", "");
- };
+ } else if (p_path.begins_with("user://")) {
+
+ String data_dir = OS::get_singleton()->get_data_dir();
+ if (data_dir != "") {
+
+ return p_path.replace("user:/", data_dir);
+ };
+ return p_path.replace("user://", "");
+ }
return p_path;
}
diff --git a/core/resource.cpp b/core/resource.cpp
index 37d42226b4..78e20bada4 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -69,12 +69,11 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
ResourceCache::resources.get(p_path)->set_name("");
ResourceCache::lock->write_unlock();
} else {
- ERR_EXPLAIN("Another resource is loaded from path: " + p_path);
-
ResourceCache::lock->read_lock();
bool exists = ResourceCache::resources.has(p_path);
ResourceCache::lock->read_unlock();
+ ERR_EXPLAIN("Another resource is loaded from path: " + p_path);
ERR_FAIL_COND(exists);
}
}
diff --git a/core/script_language.h b/core/script_language.h
index 342d8c8072..2261737f9a 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -206,6 +206,7 @@ public:
virtual int find_function(const String &p_function, const String &p_code) const = 0;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const = 0;
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
+ virtual bool overrides_external_editor() { return false; }
virtual Error complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }
diff --git a/core/string_buffer.cpp b/core/string_buffer.cpp
new file mode 100644
index 0000000000..195068f887
--- /dev/null
+++ b/core/string_buffer.cpp
@@ -0,0 +1,102 @@
+/*************************************************************************/
+/* string_buffer.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "string_buffer.h"
+
+#include <string.h>
+
+StringBuffer &StringBuffer::append(CharType p_char) {
+ reserve(string_length + 2);
+ current_buffer_ptr()[string_length++] = p_char;
+ return *this;
+}
+
+StringBuffer &StringBuffer::append(const String &p_string) {
+ return append(p_string.c_str());
+}
+
+StringBuffer &StringBuffer::append(const char *p_str) {
+ int len = strlen(p_str);
+ reserve(string_length + len + 1);
+
+ CharType *buf = current_buffer_ptr();
+ for (const char *c_ptr = p_str; c_ptr; ++c_ptr) {
+ buf[string_length++] = *c_ptr;
+ }
+ return *this;
+}
+
+StringBuffer &StringBuffer::append(const CharType *p_str, int p_clip_to_len) {
+ int len = 0;
+ while ((p_clip_to_len < 0 || len < p_clip_to_len) && p_str[len]) {
+ ++len;
+ }
+ reserve(string_length + len + 1);
+ memcpy(&(current_buffer_ptr()[string_length]), p_str, len * sizeof(CharType));
+ string_length += len;
+
+ return *this;
+}
+
+StringBuffer &StringBuffer::reserve(int p_size) {
+ if (p_size < SHORT_BUFFER_SIZE || p_size < buffer.size())
+ return *this;
+
+ bool need_copy = string_length > 0 && buffer.empty();
+ buffer.resize(next_power_of_2(p_size));
+ if (need_copy) {
+ memcpy(buffer.ptr(), short_buffer, string_length * sizeof(CharType));
+ }
+
+ return *this;
+}
+
+int StringBuffer::length() const {
+ return string_length;
+}
+
+String StringBuffer::as_string() {
+ current_buffer_ptr()[string_length] = '\0';
+ if (buffer.empty()) {
+ return String(short_buffer);
+ } else {
+ buffer.resize(string_length + 1);
+ return buffer;
+ }
+}
+
+double StringBuffer::as_double() {
+ current_buffer_ptr()[string_length] = '\0';
+ return String::to_double(current_buffer_ptr());
+}
+
+int64_t StringBuffer::as_int() {
+ current_buffer_ptr()[string_length] = '\0';
+ return String::to_int(current_buffer_ptr());
+}
diff --git a/core/string_buffer.h b/core/string_buffer.h
new file mode 100644
index 0000000000..3f36249148
--- /dev/null
+++ b/core/string_buffer.h
@@ -0,0 +1,82 @@
+/*************************************************************************/
+/* string_buffer.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef STRING_BUFFER_H
+#define STRING_BUFFER_H
+
+#include "ustring.h"
+
+class StringBuffer {
+ static const int SHORT_BUFFER_SIZE = 64;
+
+ CharType short_buffer[SHORT_BUFFER_SIZE];
+ String buffer;
+ int string_length = 0;
+
+ _FORCE_INLINE_ CharType *current_buffer_ptr() {
+ return static_cast<Vector<CharType> &>(buffer).empty() ? short_buffer : buffer.ptr();
+ }
+
+public:
+ StringBuffer &append(CharType p_char);
+ StringBuffer &append(const String &p_string);
+ StringBuffer &append(const char *p_str);
+ StringBuffer &append(const CharType *p_str, int p_clip_to_len = -1);
+
+ _FORCE_INLINE_ void operator+=(CharType p_char) {
+ append(p_char);
+ }
+
+ _FORCE_INLINE_ void operator+=(const String &p_string) {
+ append(p_string);
+ }
+
+ _FORCE_INLINE_ void operator+=(const char *p_str) {
+ append(p_str);
+ }
+
+ _FORCE_INLINE_ void operator+=(const CharType *p_str) {
+ append(p_str);
+ }
+
+ StringBuffer &reserve(int p_size);
+
+ int length() const;
+
+ String as_string();
+
+ double as_double();
+ int64_t as_int();
+
+ _FORCE_INLINE_ operator String() {
+ return as_string();
+ }
+};
+
+#endif
diff --git a/core/string_builder.cpp b/core/string_builder.cpp
new file mode 100644
index 0000000000..18c710ed2d
--- /dev/null
+++ b/core/string_builder.cpp
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* string_builder.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "string_builder.h"
+
+#include <string.h>
+
+StringBuilder &StringBuilder::append(const String &p_string) {
+
+ strings.push_back(p_string);
+ appended_strings.push_back(-1);
+
+ string_length += p_string.length();
+
+ return *this;
+}
+
+StringBuilder &StringBuilder::append(const char *p_cstring) {
+
+ int32_t len = strlen(p_cstring);
+
+ c_strings.push_back(p_cstring);
+ appended_strings.push_back(len);
+
+ string_length += len;
+
+ return *this;
+}
+
+String StringBuilder::as_string() const {
+
+ CharType *buffer = memnew_arr(CharType, string_length);
+
+ int current_position = 0;
+
+ int godot_string_elem = 0;
+ int c_string_elem = 0;
+
+ for (int i = 0; i < appended_strings.size(); i++) {
+ if (appended_strings[i] == -1) {
+ // Godot string
+ const String &s = strings[godot_string_elem];
+
+ memcpy(buffer + current_position, s.ptr(), s.length() * sizeof(CharType));
+
+ current_position += s.length();
+
+ godot_string_elem++;
+ } else {
+
+ const char *s = c_strings[c_string_elem];
+
+ for (int32_t j = 0; j < appended_strings[i]; j++) {
+ buffer[current_position + j] = s[j];
+ }
+
+ current_position += appended_strings[i];
+
+ c_string_elem++;
+ }
+ }
+
+ String final_string = String(buffer, string_length);
+
+ memdelete_arr(buffer);
+
+ return final_string;
+}
diff --git a/core/string_builder.h b/core/string_builder.h
new file mode 100644
index 0000000000..7cf2f07872
--- /dev/null
+++ b/core/string_builder.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* string_builder.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef STRING_BUILDER_H
+#define STRING_BUILDER_H
+
+#include "core/ustring.h"
+
+#include "core/vector.h"
+
+class StringBuilder {
+
+ uint32_t string_length = 0;
+
+ Vector<String> strings;
+ Vector<const char *> c_strings;
+
+ // -1 means it's a Godot String
+ // a natural number means C string.
+ Vector<int32_t> appended_strings;
+
+public:
+ StringBuilder &append(const String &p_string);
+ StringBuilder &append(const char *p_cstring);
+
+ _FORCE_INLINE_ StringBuilder &operator+(const String &p_string) {
+ return append(p_string);
+ }
+
+ _FORCE_INLINE_ StringBuilder &operator+(const char *p_cstring) {
+ return append(p_cstring);
+ }
+
+ _FORCE_INLINE_ void operator+=(const String &p_string) {
+ append(p_string);
+ }
+
+ _FORCE_INLINE_ void operator+=(const char *p_cstring) {
+ append(p_cstring);
+ }
+
+ _FORCE_INLINE_ int num_strings_appended() const {
+ return appended_strings.size();
+ }
+
+ String as_string() const;
+
+ _FORCE_INLINE_ operator String() const {
+ return as_string();
+ }
+};
+
+#endif // STRING_BUILDER_H
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index ad15f8f5cb..dc1c24d234 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -481,6 +481,7 @@ struct _VariantCall {
VCALL_LOCALMEM1(Array, erase);
VCALL_LOCALMEM0(Array, sort);
VCALL_LOCALMEM2(Array, sort_custom);
+ VCALL_LOCALMEM0R(Array, duplicate);
VCALL_LOCALMEM0(Array, invert);
static void _call_PoolByteArray_get_string_from_ascii(Variant &r_ret, Variant &p_self, const Variant **p_args) {
@@ -1575,6 +1576,7 @@ void register_variant_methods() {
ADDFUNC0(ARRAY, NIL, Array, sort, varray());
ADDFUNC2(ARRAY, NIL, Array, sort_custom, OBJECT, "obj", STRING, "func", varray());
ADDFUNC0(ARRAY, NIL, Array, invert, varray());
+ ADDFUNC0(ARRAY, ARRAY, Array, duplicate, varray());
ADDFUNC0(POOL_BYTE_ARRAY, INT, PoolByteArray, size, varray());
ADDFUNC2(POOL_BYTE_ARRAY, NIL, PoolByteArray, set, INT, "idx", INT, "byte", varray());
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
index 65c7b7cfec..d60d10cd3a 100644
--- a/core/variant_parser.cpp
+++ b/core/variant_parser.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "variant_parser.h"
+#include "core/string_buffer.h"
#include "io/resource_loader.h"
#include "os/input_event.h"
#include "os/keyboard.h"
@@ -176,14 +177,15 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
};
case '#': {
- String color_str = "#";
+ StringBuffer color_str;
+ color_str += '#';
while (true) {
CharType ch = p_stream->get_char();
if (p_stream->is_eof()) {
r_token.type = TK_EOF;
return OK;
} else if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) {
- color_str += String::chr(ch);
+ color_str += ch;
} else {
p_stream->saved = ch;
@@ -191,7 +193,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
}
}
- r_token.value = Color::html(color_str);
+ r_token.value = Color::html(color_str.as_string());
r_token.type = TK_COLOR;
return OK;
};
@@ -296,7 +298,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
if (cchar == '-' || (cchar >= '0' && cchar <= '9')) {
//a number
- String num;
+ StringBuffer num;
#define READING_SIGN 0
#define READING_INT 1
#define READING_DEC 2
@@ -359,7 +361,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
if (reading == READING_DONE)
break;
- num += String::chr(c);
+ num += c;
c = p_stream->get_char();
}
@@ -368,19 +370,19 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
r_token.type = TK_NUMBER;
if (is_float)
- r_token.value = num.to_double();
+ r_token.value = num.as_double();
else
- r_token.value = num.to_int();
+ r_token.value = num.as_int();
return OK;
} else if ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_') {
- String id;
+ StringBuffer id;
bool first = true;
while ((cchar >= 'A' && cchar <= 'Z') || (cchar >= 'a' && cchar <= 'z') || cchar == '_' || (!first && cchar >= '0' && cchar <= '9')) {
- id += String::chr(cchar);
+ id += cchar;
cchar = p_stream->get_char();
first = false;
}
@@ -388,7 +390,7 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri
p_stream->saved = cchar;
r_token.type = TK_IDENTIFIER;
- r_token.value = id;
+ r_token.value = id.as_string();
return OK;
} else {
r_err_str = "Unexpected character.";