summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bind/core_bind.cpp12
-rw-r--r--core/bind/core_bind.h2
-rw-r--r--core/dictionary.cpp103
-rw-r--r--core/global_constants.cpp2
-rw-r--r--core/os/input_event.h4
-rw-r--r--core/os/os.h4
-rw-r--r--core/translation.cpp4
-rw-r--r--doc/classes/@GDScript.xml52
-rw-r--r--doc/classes/Geometry.xml39
-rw-r--r--doc/classes/OS.xml2
-rw-r--r--doc/classes/Object.xml55
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp3
-rw-r--r--editor/SCsub2
-rw-r--r--editor/editor_about.cpp4
-rw-r--r--editor/editor_help.cpp75
-rw-r--r--editor/editor_node.cpp9
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp129
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.h5
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp10
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp253
-rw-r--r--editor/plugins/line_2d_editor_plugin.h68
-rw-r--r--editor/plugins/theme_editor_plugin.cpp16
-rw-r--r--editor/plugins/theme_editor_plugin.h3
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp4
-rw-r--r--editor/scene_tree_dock.cpp10
-rw-r--r--main/main.cpp63
-rw-r--r--modules/bullet/bullet_physics_server.cpp39
-rw-r--r--modules/bullet/bullet_physics_server.h3
-rw-r--r--modules/bullet/collision_object_bullet.cpp4
-rw-r--r--modules/bullet/space_bullet.h1
-rw-r--r--modules/gdnative/gdnative/array.cpp5
-rw-r--r--modules/gdnative/gdnative/dictionary.cpp6
-rw-r--r--modules/gdnative/gdnative_api.json23
-rw-r--r--modules/gdnative/include/gdnative/array.h2
-rw-r--r--modules/gdnative/include/gdnative/dictionary.h2
-rw-r--r--modules/gdscript/gd_editor.cpp4
-rw-r--r--modules/gdscript/gd_function.cpp130
-rw-r--r--modules/mobile_vr/mobile_interface.cpp10
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp2
-rw-r--r--platform/android/detect.py36
-rw-r--r--platform/android/os_android.cpp6
-rw-r--r--platform/android/os_android.h2
-rw-r--r--platform/android/platform_config.h1
-rw-r--r--platform/haiku/os_haiku.cpp4
-rw-r--r--platform/haiku/os_haiku.h1
-rw-r--r--platform/iphone/app_delegate.mm3
-rw-r--r--platform/javascript/SCsub3
-rw-r--r--platform/javascript/audio_driver_javascript.cpp44
-rw-r--r--platform/javascript/audio_driver_javascript.h5
-rw-r--r--platform/javascript/audio_server_javascript.cpp853
-rw-r--r--platform/javascript/audio_server_javascript.h229
-rw-r--r--platform/javascript/os_javascript.cpp5
-rw-r--r--platform/javascript/os_javascript.h3
-rw-r--r--platform/osx/os_osx.h1
-rw-r--r--platform/server/os_server.cpp4
-rw-r--r--platform/server/os_server.h1
-rw-r--r--platform/uwp/detect.py2
-rw-r--r--platform/uwp/os_uwp.cpp5
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/windows/os_windows.cpp5
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--platform/x11/os_x11.cpp4
-rw-r--r--platform/x11/os_x11.h1
-rw-r--r--scene/3d/particles.cpp4
-rw-r--r--scene/gui/rich_text_label.cpp3
-rw-r--r--scene/gui/text_edit.cpp187
-rw-r--r--scene/gui/text_edit.h9
-rw-r--r--scene/resources/texture.cpp23
-rw-r--r--scene/resources/texture.h4
-rw-r--r--servers/physics/body_pair_sw.cpp38
-rw-r--r--servers/physics/body_pair_sw.h1
-rw-r--r--servers/physics/body_sw.h10
-rw-r--r--servers/physics_2d/space_2d_sw.cpp26
-rw-r--r--thirdparty/openssl/uwp.cpp2
74 files changed, 862 insertions, 1831 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 12b892d873..c369f4bffe 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -1316,6 +1316,16 @@ Vector<int> _Geometry::triangulate_polygon(const Vector<Vector2> &p_polygon) {
return Geometry::triangulate_polygon(p_polygon);
}
+Vector<Point2> _Geometry::convex_hull_2d(const Vector<Point2> &p_points) {
+
+ return Geometry::convex_hull_2d(p_points);
+}
+
+Vector<Vector3> _Geometry::clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane) {
+
+ return Geometry::clip_polygon(p_points, p_plane);
+}
+
Dictionary _Geometry::make_atlas(const Vector<Size2> &p_rects) {
Dictionary ret;
@@ -1376,6 +1386,8 @@ void _Geometry::_bind_methods() {
ClassDB::bind_method(D_METHOD("point_is_inside_triangle", "point", "a", "b", "c"), &_Geometry::point_is_inside_triangle);
ClassDB::bind_method(D_METHOD("triangulate_polygon", "polygon"), &_Geometry::triangulate_polygon);
+ ClassDB::bind_method(D_METHOD("convex_hull_2d", "points"), &_Geometry::convex_hull_2d);
+ ClassDB::bind_method(D_METHOD("clip_polygon", "points", "plane"), &_Geometry::clip_polygon);
ClassDB::bind_method(D_METHOD("make_atlas", "sizes"), &_Geometry::make_atlas);
}
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 7f8c734e36..bbbb40d926 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -363,6 +363,8 @@ public:
int get_uv84_normal_bit(const Vector3 &p_vector);
Vector<int> triangulate_polygon(const Vector<Vector2> &p_polygon);
+ Vector<Point2> convex_hull_2d(const Vector<Point2> &p_points);
+ Vector<Vector3> clip_polygon(const Vector<Vector3> &p_points, const Plane &p_plane);
Dictionary make_atlas(const Vector<Size2> &p_rects);
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index bb2e892951..48e65c734f 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "dictionary.h"
+#include "ordered_hash_map.h"
#include "safe_refcount.h"
#include "variant.h"
@@ -39,22 +40,8 @@ struct _DictionaryVariantHash {
struct DictionaryPrivate {
- struct Data {
- Variant variant;
- int order;
- };
-
SafeRefCount refcount;
- HashMap<Variant, Data, _DictionaryVariantHash> variant_map;
- int counter;
-};
-
-struct DictionaryPrivateSort {
-
- bool operator()(const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *A, const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *B) const {
-
- return A->data.order < B->data.order;
- }
+ OrderedHashMap<Variant, Variant, _DictionaryVariantHash> variant_map;
};
void Dictionary::get_key_list(List<Variant> *p_keys) const {
@@ -62,61 +49,45 @@ void Dictionary::get_key_list(List<Variant> *p_keys) const {
if (_p->variant_map.empty())
return;
- int count = _p->variant_map.size();
- const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **pairs = (const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **)alloca(count * sizeof(HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *));
- _p->variant_map.get_key_value_ptr_array(pairs);
-
- SortArray<const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *, DictionaryPrivateSort> sort;
- sort.sort(pairs, count);
-
- for (int i = 0; i < count; i++) {
- p_keys->push_back(pairs[i]->key);
+ for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ p_keys->push_back(E.key());
}
}
Variant &Dictionary::operator[](const Variant &p_key) {
- DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key);
-
- if (!v) {
-
- DictionaryPrivate::Data d;
- d.order = _p->counter++;
- _p->variant_map[p_key] = d;
- v = _p->variant_map.getptr(p_key);
- }
- return v->variant;
+ return _p->variant_map[p_key];
}
const Variant &Dictionary::operator[](const Variant &p_key) const {
- return _p->variant_map[p_key].variant;
+ return _p->variant_map[p_key];
}
const Variant *Dictionary::getptr(const Variant &p_key) const {
- const DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key);
- if (!v)
+ OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::ConstElement E = ((const OrderedHashMap<Variant, Variant, _DictionaryVariantHash> *)&_p->variant_map)->find(p_key);
+
+ if (!E)
return NULL;
- else
- return &v->variant;
+ return &E.get();
}
Variant *Dictionary::getptr(const Variant &p_key) {
- DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key);
- if (!v)
+ OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.find(p_key);
+
+ if (!E)
return NULL;
- else
- return &v->variant;
+ return &E.get();
}
Variant Dictionary::get_valid(const Variant &p_key) const {
- DictionaryPrivate::Data *v = _p->variant_map.getptr(p_key);
- if (!v)
+ OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::ConstElement E = ((const OrderedHashMap<Variant, Variant, _DictionaryVariantHash> *)&_p->variant_map)->find(p_key);
+
+ if (!E)
return Variant();
- else
- return v->variant;
+ return E.get();
}
int Dictionary::size() const {
@@ -171,7 +142,6 @@ void Dictionary::_ref(const Dictionary &p_from) const {
void Dictionary::clear() {
_p->variant_map.clear();
- _p->counter = 0;
}
void Dictionary::_unref() const {
@@ -205,15 +175,10 @@ Array Dictionary::keys() const {
if (_p->variant_map.empty())
return varr;
- int count = _p->variant_map.size();
- const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **pairs = (const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **)alloca(count * sizeof(HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *));
- _p->variant_map.get_key_value_ptr_array(pairs);
-
- SortArray<const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *, DictionaryPrivateSort> sort;
- sort.sort(pairs, count);
-
- for (int i = 0; i < count; i++) {
- varr[i] = pairs[i]->key;
+ int i = 0;
+ for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ varr[i] = E.key();
+ i++;
}
return varr;
@@ -226,15 +191,10 @@ Array Dictionary::values() const {
if (_p->variant_map.empty())
return varr;
- int count = _p->variant_map.size();
- const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **pairs = (const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair **)alloca(count * sizeof(HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *));
- _p->variant_map.get_key_value_ptr_array(pairs);
-
- SortArray<const HashMap<Variant, DictionaryPrivate::Data, _DictionaryVariantHash>::Pair *, DictionaryPrivateSort> sort;
- sort.sort(pairs, count);
-
- for (int i = 0; i < count; i++) {
- varr[i] = pairs[i]->data.variant;
+ int i = 0;
+ for (OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.front(); E; E = E.next()) {
+ varr[i] = E.get();
+ i++;
}
return varr;
@@ -242,7 +202,15 @@ Array Dictionary::values() const {
const Variant *Dictionary::next(const Variant *p_key) const {
- return _p->variant_map.next(p_key);
+ if (p_key == NULL) {
+ // caller wants to get the first element
+ return &_p->variant_map.front().key();
+ }
+ OrderedHashMap<Variant, Variant, _DictionaryVariantHash>::Element E = _p->variant_map.find(*p_key);
+
+ if (E && E.next())
+ return &E.next().key();
+ return NULL;
}
Dictionary Dictionary::copy() const {
@@ -273,7 +241,6 @@ Dictionary::Dictionary() {
_p = memnew(DictionaryPrivate);
_p->refcount.init();
- _p->counter = 0;
}
Dictionary::~Dictionary() {
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 8bddeae69a..7854f342b0 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -435,6 +435,8 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_5);
BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_6);
BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_7);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_8);
+ BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_9);
BIND_GLOBAL_ENUM_CONSTANT(JOY_AXIS_MAX);
BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_LX);
diff --git a/core/os/input_event.h b/core/os/input_event.h
index f2c8cc802d..de3c0232ff 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -122,7 +122,9 @@ enum JoystickList {
JOY_AXIS_5 = 5,
JOY_AXIS_6 = 6,
JOY_AXIS_7 = 7,
- JOY_AXIS_MAX = 8,
+ JOY_AXIS_8 = 8,
+ JOY_AXIS_9 = 9,
+ JOY_AXIS_MAX = 10,
JOY_ANALOG_LX = JOY_AXIS_0,
JOY_ANALOG_LY = JOY_AXIS_1,
diff --git a/core/os/os.h b/core/os/os.h
index f5e479ac0b..4ac6e81b15 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -1,4 +1,4 @@
-/*************************************************************************/
+/************************************************************************* /
/* os.h */
/*************************************************************************/
/* This file is part of: */
@@ -109,8 +109,6 @@ protected:
virtual int get_video_driver_count() const = 0;
virtual const char *get_video_driver_name(int p_driver) const = 0;
- virtual VideoMode get_default_video_mode() const = 0;
-
virtual int get_audio_driver_count() const = 0;
virtual const char *get_audio_driver_name(int p_driver) const = 0;
diff --git a/core/translation.cpp b/core/translation.cpp
index 058db956e5..7e4d4feb89 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -966,7 +966,7 @@ Vector<String> TranslationServer::get_all_locale_names() {
const char **ptr = locale_names;
while (*ptr) {
- locales.push_back(*ptr);
+ locales.push_back(String::utf8(*ptr));
ptr++;
}
@@ -1168,6 +1168,6 @@ TranslationServer::TranslationServer()
for (int i = 0; locale_list[i]; ++i) {
- locale_name_map.insert(locale_list[i], locale_names[i]);
+ locale_name_map.insert(locale_list[i], String::utf8(locale_names[i]));
}
}
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index b61cf93ef7..9c1d9a1aa2 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -1050,6 +1050,58 @@
A weak reference to an object is not enough to keep the object alive: when the only remaining references to a referent are weak references, garbage collection is free to destroy the referent and reuse its memory for something else. However, until the object is actually destroyed the weak reference may return the object even if there are no strong references to it.
</description>
</method>
+ <method name="wrapf">
+ <return type="float">
+ </return>
+ <argument index="0" name="value" type="float">
+ </argument>
+ <argument index="1" name="min" type="float">
+ </argument>
+ <argument index="2" name="max" type="float">
+ </argument>
+ <description>
+ Wraps float [code]value[/code] between [code]min[/code] and [code]max[/code].
+ Usable for creating loop-alike behavior or infinite surfaces.
+ [codeblock]
+ # a is 0.5
+ a = wrapf(10.5, 0.0, 10.0)
+ [/codeblock]
+ [codeblock]
+ # a is 9.5
+ a = wrapf(-0.5, 0.0, 10.0)
+ [/codeblock]
+ [codeblock]
+ # infinite loop between 0.0 and 0.99
+ f = wrapf(f + 0.1, 0.0, 1.0)
+ [/codeblock]
+ </description>
+ </method>
+ <method name="wrapi">
+ <return type="int">
+ </return>
+ <argument index="0" name="value" type="int">
+ </argument>
+ <argument index="1" name="min" type="int">
+ </argument>
+ <argument index="2" name="max" type="int">
+ </argument>
+ <description>
+ Wraps integer [code]value[/code] between [code]min[/code] and [code]max[/code].
+ Usable for creating loop-alike behavior or infinite surfaces.
+ [codeblock]
+ # a is 0
+ a = wrapi(10, 0, 10)
+ [/codeblock]
+ [codeblock]
+ # a is 9
+ a = wrapi(-1, 0, 10)
+ [/codeblock]
+ [codeblock]
+ # infinite loop between 0 and 9
+ frame = wrapi(frame + 1, 0, 10)
+ [/codeblock]
+ </description>
+ </method>
<method name="yield">
<return type="GDFunctionState">
</return>
diff --git a/doc/classes/Geometry.xml b/doc/classes/Geometry.xml
index 49f32bc68f..1589a9a906 100644
--- a/doc/classes/Geometry.xml
+++ b/doc/classes/Geometry.xml
@@ -15,6 +15,7 @@
<argument index="0" name="extents" type="Vector3">
</argument>
<description>
+ Returns an array with 6 [Plane]s that describe the sides of a box centered at the origin. The box size is defined by [code]extents[/code], which represents one (positive) corner of the box (i.e. half its actual size).
</description>
</method>
<method name="build_capsule_planes">
@@ -31,6 +32,7 @@
<argument index="4" name="axis" type="int" enum="Vector3.Axis" default="2">
</argument>
<description>
+ Returns an array of [Plane]s closely bounding a faceted capsule centered at the origin with radius [code]radius[/code] and height [code]height[/code]. The parameter [code]sides[/code] defines how many planes will be generated for the side part of the capsule, whereas [code]lats[/code] gives the number of latitudinal steps at the bottom and top of the capsule. The parameter [code]axis[/code] describes the axis along which the capsule is oriented (0 for X, 1 for Y, 2 for Z).
</description>
</method>
<method name="build_cylinder_planes">
@@ -45,6 +47,7 @@
<argument index="3" name="axis" type="int" enum="Vector3.Axis" default="2">
</argument>
<description>
+ Returns an array of [Plane]s closely bounding a faceted cylinder centered at the origin with radius [code]radius[/code] and height [code]height[/code]. The parameter [code]sides[/code] defines how many planes will be generated for the round part of the cylinder. The parameter [code]axis[/code] describes the axis along which the cylinder is oriented (0 for X, 1 for Y, 2 for Z).
</description>
</method>
<method name="get_closest_point_to_segment">
@@ -57,6 +60,7 @@
<argument index="2" name="s2" type="Vector3">
</argument>
<description>
+ Returns the 3d point on the 3d segment ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point will always be inside the specified segment.
</description>
</method>
<method name="get_closest_point_to_segment_2d">
@@ -69,6 +73,7 @@
<argument index="2" name="s2" type="Vector2">
</argument>
<description>
+ Returns the 2d point on the 2d segment ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point will always be inside the specified segment.
</description>
</method>
<method name="get_closest_point_to_segment_uncapped">
@@ -81,6 +86,7 @@
<argument index="2" name="s2" type="Vector3">
</argument>
<description>
+ Returns the 3d point on the 3d line defined by ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point can be inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. somewhere on the line extending from the segment.
</description>
</method>
<method name="get_closest_point_to_segment_uncapped_2d">
@@ -93,6 +99,7 @@
<argument index="2" name="s2" type="Vector2">
</argument>
<description>
+ Returns the 2d point on the 2d line defined by ([code]s1[/code], [code]s2[/code]) that is closest to [code]point[/code]. The returned point can be inside the segment ([code]s1[/code], [code]s2[/code]) or outside of it, i.e. somewhere on the line extending from the segment.
</description>
</method>
<method name="get_closest_points_between_segments">
@@ -107,6 +114,7 @@
<argument index="3" name="q2" type="Vector3">
</argument>
<description>
+ Given the two 3d segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PoolVector3Array] that contains this point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point on ([code]q1[/code], [code]q2[/code]).
</description>
</method>
<method name="get_closest_points_between_segments_2d">
@@ -121,6 +129,7 @@
<argument index="3" name="q2" type="Vector2">
</argument>
<description>
+ Given the two 2d segments ([code]p1[/code], [code]p2[/code]) and ([code]q1[/code], [code]q2[/code]), finds those two points on the two segments that are closest to each other. Returns a [PoolVector2Array] that contains this point on ([code]p1[/code], [code]p2[/code]) as well the accompanying point on ([code]q1[/code], [code]q2[/code]).
</description>
</method>
<method name="get_uv84_normal_bit">
@@ -137,6 +146,7 @@
<argument index="0" name="sizes" type="PoolVector2Array">
</argument>
<description>
+ Given an array of [Vector2]s representing tiles, builds an atlas. The returned dictionary has two keys: [code]points[/code] is a vector of [Vector2] that specifies the positions of each tile, [code]size[/code] contains the overall size of the whole atlas as [Vector2].
</description>
</method>
<method name="point_is_inside_triangle" qualifiers="const">
@@ -151,6 +161,7 @@
<argument index="3" name="c" type="Vector2">
</argument>
<description>
+ Returns if [code]point[/code] is inside the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code].
</description>
</method>
<method name="ray_intersects_triangle">
@@ -167,6 +178,7 @@
<argument index="4" name="c" type="Vector3">
</argument>
<description>
+ Tests if the 3d ray starting at [code]from[/code] with the direction of [code]dir[/code] intersects the triangle specified by [code]a[/code], [code]b[/code] and [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, an empty [Variant] is returned.
</description>
</method>
<method name="segment_intersects_circle">
@@ -181,6 +193,7 @@
<argument index="3" name="circle_radius" type="float">
</argument>
<description>
+ Given the 2d segment ([code]segment_from[/code], [code]segment_to[/code]), returns the position on the segment (as a number between 0 and 1) at which the segment hits the circle that is located at position [code]circle_position[/code] and has radius [code]circle_radius[/code]. If the segment does not intersect the circle, -1 is returned (this is also the case if the line extending the segment would intersect the circle, but the segment does not).
</description>
</method>
<method name="segment_intersects_convex">
@@ -193,6 +206,7 @@
<argument index="2" name="planes" type="Array">
</argument>
<description>
+ Given a convex hull defined though the [Plane]s in the array [code]planes[/code], tests if the segment ([code]from[/code], [code]to[/code]) intersects with that hull. If an intersection is found, returns a [PoolVector3Array] containing the point the intersection and the hull's normal. If no intersecion is found, an the returned array is empty.
</description>
</method>
<method name="segment_intersects_cylinder">
@@ -207,6 +221,7 @@
<argument index="3" name="radius" type="float">
</argument>
<description>
+ Checks if the segment ([code]from[/code], [code]to[/code]) intersects the cylinder with height [code]height[/code] that is centered at the origin and has radius [code]radius[/code]. If no, returns an empty [PoolVector3Array]. If an intersection takes place, the returned array contains the point of intersection and the cylinder's normal at the point of intersection.
</description>
</method>
<method name="segment_intersects_segment_2d">
@@ -221,6 +236,7 @@
<argument index="3" name="to_b" type="Vector2">
</argument>
<description>
+ Checks if the two segments ([code]from_a[/code], [code]to_a[/code]) and ([code]from_b[/code], [code]to_b[/code]) intersect. If yes, return the point of intersection as [Vector2]. If no intersection takes place, returns an empty [Variant].
</description>
</method>
<method name="segment_intersects_sphere">
@@ -235,6 +251,7 @@
<argument index="3" name="sphere_radius" type="float">
</argument>
<description>
+ Checks if the segment ([code]from[/code], [code]to[/code]) intersects the sphere that is located at [code]sphere_position[/code] and has radius [code]sphere_radius[/code]. If no, returns an empty [PoolVector3Array]. If yes, returns a [PoolVector3Array] containing the point of intersection and the sphere's normal at the point of intersection.
</description>
</method>
<method name="segment_intersects_triangle">
@@ -251,6 +268,7 @@
<argument index="4" name="c" type="Vector3">
</argument>
<description>
+ Tests if the segment ([code]from[/code], [code]to[/code]) intersects the triangle [code]a[/code], [code]b[/code], [code]c[/code]. If yes, returns the point of intersection as [Vector3]. If no intersection takes place, an empty [Variant] is returned.
</description>
</method>
<method name="triangulate_polygon">
@@ -259,6 +277,27 @@
<argument index="0" name="polygon" type="PoolVector2Array">
</argument>
<description>
+ Triangulates the polygon specified by the points in [code]polygon[/code]. Returns a [PoolIntArray] where each triangle consists of three consecutive point indices into [code]polygon[/code] (i.e. the returned array will have [code]n * 3[/code] elements, with [code]n[/code] being the number of found triangles). If the triangulation did not succeed, an empty [PoolIntArray] is returned.
+ </description>
+ </method>
+ <method name="convex_hull_2d">
+ <return type="PoolVector2Array">
+ </return>
+ <argument index="0" name="points" type="PoolVector2Array">
+ </argument>
+ <description>
+ Given an array of [Vector2]s, returns the convex hull as a list of points in counter-clockwise order. The last point is the same as the first one.
+ </description>
+ </method>
+ <method name="clip_polygon">
+ <return type="PoolVector3Array">
+ </return>
+ <argument index="0" name="points" type="PoolVector3Array">
+ </argument>
+ <argument index="1" name="plane" type="Plane">
+ </argument>
+ <description>
+ Clips the polygon defined by the points in [code]points[/code] against the [code]plane[/code] and returns the points of the clipped polygon.
</description>
</method>
</methods>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 2629e6740d..9fd4328402 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -376,7 +376,7 @@
<return type="String">
</return>
<description>
- Returns a unique string.
+ Returns a string that is unique to the device. Currently only works on Android and iOS. Returns empty string on other platforms.
</description>
</method>
<method name="get_unix_time" qualifiers="const">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index d30ebfaef8..5ba5299a77 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -21,20 +21,21 @@
<argument index="0" name="property" type="String">
</argument>
<description>
- Return a property, return null if the property does not exist.
+ Returns the given property. Returns [code]null[/code] if the [code]property[/code] does not exist.
</description>
</method>
<method name="_get_property_list" qualifiers="virtual">
<return type="Array">
</return>
<description>
- Return the property list, array of dictionaries, dictionaries must contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
+ Returns the object's property list as an [Array] of dictionaries. Dictionaries must contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
</description>
</method>
<method name="_init" qualifiers="virtual">
<return type="void">
</return>
<description>
+ The virtual method called upon initialization.
</description>
</method>
<method name="_notification" qualifiers="virtual">
@@ -43,7 +44,7 @@
<argument index="0" name="what" type="int">
</argument>
<description>
- Notification request, the notification id is received.
+ Notify the object internally using an ID.
</description>
</method>
<method name="_set" qualifiers="virtual">
@@ -54,7 +55,7 @@
<argument index="1" name="value" type="Variant">
</argument>
<description>
- Set a property. Return true if the property was found.
+ Sets a property. Returns [code]true[/code] if the [code]property[/code] exists.
</description>
</method>
<method name="add_user_signal">
@@ -65,7 +66,7 @@
<argument index="1" name="arguments" type="Array" default="[ ]">
</argument>
<description>
- Add a user signal (can be added anytime). Arguments are optional, but can be added as an array of dictionaries, each containing "name" and "type" (from [@Global Scope] TYPE_*).
+ Adds a user-defined [code]signal[/code]. Arguments are optional, but can be added as an [Array] of dictionaries, each containing "name" and "type" (from [@Global Scope] TYPE_*).
</description>
</method>
<method name="call" qualifiers="vararg">
@@ -74,6 +75,7 @@
<argument index="0" name="method" type="String">
</argument>
<description>
+ Calls the [code]method[/code] on the object and returns a result. Pass parameters as a comma separated list.
</description>
</method>
<method name="call_deferred" qualifiers="vararg">
@@ -82,6 +84,7 @@
<argument index="0" name="method" type="String">
</argument>
<description>
+ Calls the [code]method[/code] on the object during idle time and returns a result. Pass parameters as a comma separated list.
</description>
</method>
<method name="callv">
@@ -92,13 +95,14 @@
<argument index="1" name="arg_array" type="Array">
</argument>
<description>
+ Calls the [code]method[/code] on the object and returns a result. Pass parameters as an [Array].
</description>
</method>
<method name="can_translate_messages" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if this object can translate strings.
+ Returns [code]true[/code] if the object can translate strings.
</description>
</method>
<method name="connect">
@@ -115,7 +119,7 @@
<argument index="4" name="flags" type="int" default="0">
</argument>
<description>
- Connect a signal to a method at a target (member function). Binds are optional and are passed as extra arguments to the call. Flags specify optional deferred or one shot connections, see enum CONNECT_*. A signal can only be connected once to a method, and it will throw an error if already connected. If you want to avoid this, use [method is_connected] to check.
+ Connects a [code]signal[/code] to a [code]method[/code] on a [code]target[/code] object. Pass optional [code]binds[/code] to the call. Use [code]flags[/code] to set deferred or one shot connections. See [code]CONNECT_*[/code] constants. A [code]signal[/code] can only be connected once to a [code]method[/code]. It will throw an error if already connected. To avoid this, first use [method is_connected] to check for existing connections.
</description>
</method>
<method name="disconnect">
@@ -128,7 +132,7 @@
<argument index="2" name="method" type="String">
</argument>
<description>
- Disconnect a signal from a method.
+ Disconnects a [code]signal[/code] from a [code]method[/code] on the given [code]target[/code].
</description>
</method>
<method name="emit_signal" qualifiers="vararg">
@@ -137,12 +141,14 @@
<argument index="0" name="signal" type="String">
</argument>
<description>
+ Emits the given [code]signal[/code].
</description>
</method>
<method name="free">
<return type="void">
</return>
<description>
+ Deletes the object from memory.
</description>
</method>
<method name="get" qualifiers="const">
@@ -151,21 +157,21 @@
<argument index="0" name="property" type="String">
</argument>
<description>
- Get a property from the object.
+ Returns a [Variant] for a [code]property[/code].
</description>
</method>
<method name="get_class" qualifiers="const">
<return type="String">
</return>
<description>
- Return the class of the object as a string.
+ Returns the object's class as a [String].
</description>
</method>
<method name="get_incoming_connections" qualifiers="const">
<return type="Array">
</return>
<description>
- Returns an [Array] of dictionaries with information about signals that are connected to this object.
+ Returns an [Array] of dictionaries with information about signals that are connected to the object.
Inside each [Dictionary] there are 3 fields:
- "source" is a reference to signal emitter.
- "signal_name" is name of connected signal.
@@ -176,7 +182,7 @@
<return type="int">
</return>
<description>
- Return the instance ID. All objects have a unique instance ID.
+ Returns the object's unique instance ID.
</description>
</method>
<method name="get_meta" qualifiers="const">
@@ -185,34 +191,35 @@
<argument index="0" name="name" type="String">
</argument>
<description>
- Return a metadata from the object.
+ Returns the object's metadata for the given [code]name[/code].
</description>
</method>
<method name="get_meta_list" qualifiers="const">
<return type="PoolStringArray">
</return>
<description>
- Return the list of metadata in the object.
+ Returns the object's metadata as a [PoolStringArray].
</description>
</method>
<method name="get_method_list" qualifiers="const">
<return type="Array">
</return>
<description>
+ Returns the object's methods and their signatures as an [Array].
</description>
</method>
<method name="get_property_list" qualifiers="const">
<return type="Array">
</return>
<description>
- Return the list of properties as an array of dictionaries, dictionaries contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
+ Returns the list of properties as an [Array] of dictionaries. Dictionaries contain: name:String, type:int (see TYPE_* enum in [@Global Scope]) and optionally: hint:int (see PROPERTY_HINT_* in [@Global Scope]), hint_string:String, usage:int (see PROPERTY_USAGE_* in [@Global Scope]).
</description>
</method>
<method name="get_script" qualifiers="const">
<return type="Reference">
</return>
<description>
- Return the object script (or null if it doesn't have one).
+ Returns the object's [Script] or [code]null[/code] if one doesn't exist.
</description>
</method>
<method name="get_signal_connection_list" qualifiers="const">
@@ -221,13 +228,14 @@
<argument index="0" name="signal" type="String">
</argument>
<description>
+ Returns an [Array] of connections for the given [code]signal[/code].
</description>
</method>
<method name="get_signal_list" qualifiers="const">
<return type="Array">
</return>
<description>
- Return the list of signals as an array of dictionaries.
+ Returns the list of signals as an [Array] of dictionaries.
</description>
</method>
<method name="has_meta" qualifiers="const">
@@ -236,7 +244,7 @@
<argument index="0" name="name" type="String">
</argument>
<description>
- Return true if a metadata is found with the requested name.
+ Returns [code]true[/code] if a metadata is found with the given [code]name[/code].
</description>
</method>
<method name="has_method" qualifiers="const">
@@ -245,6 +253,7 @@
<argument index="0" name="method" type="String">
</argument>
<description>
+ Returns [code]true[/code] if the object contains the given [code]method[/code].
</description>
</method>
<method name="has_user_signal" qualifiers="const">
@@ -253,13 +262,14 @@
<argument index="0" name="signal" type="String">
</argument>
<description>
+ Returns [code]true[/code] if the given user-defined [code]signal[/code] exists.
</description>
</method>
<method name="is_blocking_signals" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if signal emission blocking is enabled.
+ Returns [code]true[/code] if signal emission blocking is enabled.
</description>
</method>
<method name="is_class" qualifiers="const">
@@ -268,7 +278,7 @@
<argument index="0" name="type" type="String">
</argument>
<description>
- Check the class of the object against a string (including inheritance).
+ Returns [code]true[/code] if the object inherits from the given [code]type[/code].
</description>
</method>
<method name="is_connected" qualifiers="const">
@@ -281,13 +291,14 @@
<argument index="2" name="method" type="String">
</argument>
<description>
- Return true if a connection exists for a given signal and target/method.
+ Returns [code]true[/code] if a connection exists for a given [code]signal[/code], [code]target[/code], and [code]method[/code].
</description>
</method>
<method name="is_queued_for_deletion" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if the [code]queue_free[/code] method was called for the object.
</description>
</method>
<method name="notification">
@@ -333,7 +344,7 @@
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Define whether this object can translate strings (with calls to [method tr]). Default is true.
+ Define whether the object can translate strings (with calls to [method tr]). Default is true.
</description>
</method>
<method name="set_meta">
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index d1c8ccfe21..72a3c3256b 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -83,6 +83,9 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
if (type == _EXT_DEBUG_TYPE_OTHER_ARB)
return;
+ if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB)
+ return; //these are ultimately annoying, so removing for now
+
char debSource[256], debType[256], debSev[256];
if (source == _EXT_DEBUG_SOURCE_API_ARB)
strcpy(debSource, "OpenGL");
diff --git a/editor/SCsub b/editor/SCsub
index 2b6494608b..c531d2c7a6 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -39,6 +39,8 @@ def make_doc_header(target, source, env):
docend = ""
for s in source:
src = s.srcnode().abspath
+ if not src.endswith(".xml"):
+ continue
f = open_utf8(src, "r")
content = f.read()
buf+=content
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index a48e6c9057..290cb1be42 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -117,7 +117,7 @@ EditorAbout::EditorAbout() {
Label *about_text = memnew(Label);
about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\u00A9 2007-2017 Juan Linietsky, Ariel Manzur.\n\u00A9 2014-2017 ") +
+ about_text->set_text(VERSION_FULL_NAME + hash + String::utf8("\n\xc2\xa9 2007-2017 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2017 ") +
TTR("Godot Engine contributors") + "\n");
hbc->add_child(about_text);
@@ -201,7 +201,7 @@ EditorAbout::EditorAbout() {
for (int j = 0; j < about_tp_copyright_count[i]; j++) {
text += "\n Files:\n " + String(about_tp_file[read_idx]).replace("\n", "\n ") + "\n";
- String copyright = String::utf8(" \u00A9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n \u00A9 "));
+ String copyright = String::utf8(" \xc2\xa9 ") + String::utf8(about_tp_copyright[read_idx]).replace("\n", String::utf8("\n \xc2\xa9 "));
text += copyright;
long_text += copyright;
String license = "\n License: " + String(about_tp_license[read_idx]) + "\n";
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 2c4d3035a4..03cd2c9b6b 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1045,12 +1045,17 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop(); // end monofont
if (cd.signals[i].description != "") {
+ class_desc->push_font(doc_font);
class_desc->push_color(comment_color);
- class_desc->add_text(" ");
+ class_desc->push_indent(1);
+ // class_desc->add_text(" ");
_add_text(cd.signals[i].description);
+ class_desc->pop(); // indent
class_desc->pop();
+ class_desc->pop(); // font
}
class_desc->add_newline();
+ class_desc->add_newline();
}
class_desc->pop();
@@ -1129,11 +1134,14 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop();
if (enum_list[i].description != "") {
class_desc->push_font(doc_font);
- class_desc->add_text(" ");
+ //class_desc->add_text(" ");
+ class_desc->push_indent(1);
class_desc->push_color(comment_color);
_add_text(enum_list[i].description);
class_desc->pop();
class_desc->pop();
+ class_desc->pop(); // indent
+ class_desc->add_newline();
}
class_desc->add_newline();
@@ -1177,11 +1185,14 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
class_desc->pop();
if (constants[i].description != "") {
class_desc->push_font(doc_font);
- class_desc->add_text(" ");
+ class_desc->push_indent(1);
+ //class_desc->add_text(" ");
class_desc->push_color(comment_color);
_add_text(constants[i].description);
class_desc->pop();
class_desc->pop();
+ class_desc->pop(); // indent
+ class_desc->add_newline();
}
class_desc->add_newline();
@@ -1231,54 +1242,62 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
method_line[cd.properties[i].name] = class_desc->get_line_count() - 2;
+ class_desc->push_table(2);
+ class_desc->set_table_column_expand(1, 1);
+
+ class_desc->push_cell();
class_desc->push_font(doc_code_font);
_add_type(cd.properties[i].type, cd.properties[i].enumeration);
-
class_desc->add_text(" ");
+ class_desc->pop(); // font
+ class_desc->pop(); // cell
+
+ class_desc->push_cell();
+ class_desc->push_font(doc_code_font);
class_desc->push_color(headline_color);
_add_text(cd.properties[i].name);
- class_desc->pop(); //color
-
- class_desc->add_text(" ");
+ class_desc->pop(); // color
+ class_desc->pop(); // font
+ class_desc->pop(); // cell
- class_desc->pop(); //font
+ //class_desc->add_text(" ");
if (cd.properties[i].setter != "") {
- class_desc->push_font(doc_font);
-
- class_desc->push_indent(2);
- class_desc->push_color(comment_color);
- class_desc->add_text("Setter: ");
- class_desc->pop();
+ class_desc->push_cell();
+ class_desc->pop(); // cell
+ class_desc->push_cell();
+ class_desc->push_font(doc_code_font);
class_desc->push_color(text_color);
class_desc->add_text(cd.properties[i].setter + "(value)");
- class_desc->pop(); //color
-
- class_desc->pop(); //indent
-
- class_desc->pop(); //font
+ class_desc->pop(); // color
+ class_desc->push_color(comment_color);
+ class_desc->add_text(" setter");
+ class_desc->pop(); // color
+ class_desc->pop(); // font
+ class_desc->pop(); // cell
}
if (cd.properties[i].getter != "") {
- class_desc->push_font(doc_font);
-
- class_desc->push_indent(2);
- class_desc->push_color(comment_color);
- class_desc->add_text("Getter: ");
- class_desc->pop();
+ class_desc->push_cell();
+ class_desc->pop(); // cell
+ class_desc->push_cell();
+ class_desc->push_font(doc_code_font);
class_desc->push_color(text_color);
class_desc->add_text(cd.properties[i].getter + "()");
class_desc->pop(); //color
-
- class_desc->pop(); //indent
-
+ class_desc->push_color(comment_color);
+ class_desc->add_text(" getter");
+ class_desc->pop(); //color
class_desc->pop(); //font
+ class_desc->pop(); //cell
}
+ class_desc->pop(); // table
+
class_desc->add_newline();
class_desc->push_color(text_color);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 3513126a9b..3d171b692c 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -1933,6 +1933,15 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
} break;
case FILE_EXPORT_TILESET: {
+ //Make sure that the scene has a root before trying to convert to tileset
+ if (!editor_data.get_edited_scene_root()) {
+ current_option = -1;
+ accept->get_ok()->set_text(TTR("I see.."));
+ accept->set_text(TTR("This operation can't be done without a root node."));
+ accept->popup_centered_minsize();
+ break;
+ }
+
List<String> extensions;
Ref<TileSet> ml(memnew(TileSet));
ResourceSaver::get_recognized_extensions(ml, &extensions);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 2f839b96cf..f2f913d2b3 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -92,6 +92,11 @@ bool AbstractPolygon2DEditor::_is_empty() const {
return true;
}
+bool AbstractPolygon2DEditor::_is_line() const {
+
+ return false;
+}
+
int AbstractPolygon2DEditor::_get_polygon_count() const {
return 1;
@@ -158,12 +163,23 @@ void AbstractPolygon2DEditor::_menu_option(int p_option) {
mode = MODE_CREATE;
button_create->set_pressed(true);
button_edit->set_pressed(false);
+ button_delete->set_pressed(false);
} break;
case MODE_EDIT: {
+ wip_active = false;
mode = MODE_EDIT;
button_create->set_pressed(false);
button_edit->set_pressed(true);
+ button_delete->set_pressed(false);
+ } break;
+ case MODE_DELETE: {
+
+ wip_active = false;
+ mode = MODE_DELETE;
+ button_create->set_pressed(false);
+ button_edit->set_pressed(false);
+ button_delete->set_pressed(true);
} break;
}
}
@@ -174,8 +190,9 @@ void AbstractPolygon2DEditor::_notification(int p_what) {
case NOTIFICATION_READY: {
- button_create->set_icon(get_icon("Edit", "EditorIcons"));
- button_edit->set_icon(get_icon("MovePoint", "EditorIcons"));
+ button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
+ button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
+ button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
button_edit->set_pressed(true);
get_tree()->connect("node_removed", this, "_node_removed");
@@ -199,19 +216,32 @@ void AbstractPolygon2DEditor::_node_removed(Node *p_node) {
}
}
+void AbstractPolygon2DEditor::_wip_changed() {
+
+ if (wip_active && _is_line()) {
+ _set_polygon(0, wip);
+ }
+}
+
void AbstractPolygon2DEditor::_wip_close() {
+ if (_is_line()) {
- if (wip.size() >= 3) {
+ _set_polygon(0, wip);
+ } else if (wip.size() >= 3) {
undo_redo->create_action(TTR("Create Poly"));
_action_add_polygon(wip);
_commit_action();
+ } else {
- mode = MODE_EDIT;
- button_edit->set_pressed(true);
- button_create->set_pressed(false);
+ return;
}
+ mode = MODE_EDIT;
+ button_edit->set_pressed(true);
+ button_create->set_pressed(false);
+ button_delete->set_pressed(false);
+
wip.clear();
wip_active = false;
@@ -252,6 +282,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip.clear();
wip.push_back(cpoint);
wip_active = true;
+ _wip_changed();
edited_point = PosVertex(-1, 1, cpoint);
canvas_item_editor->get_viewport_control()->update();
hover_point = Vertex();
@@ -262,20 +293,20 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
const real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
- if (wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
+ if (!_is_line() && wip.size() > 1 && xform.xform(wip[0]).distance_to(gpoint) < grab_threshold) {
//wip closed
_wip_close();
return true;
} else {
+ //add wip point
wip.push_back(cpoint);
+ _wip_changed();
edited_point = PosVertex(-1, wip.size(), cpoint);
selected_point = Vertex(wip.size() - 1);
canvas_item_editor->get_viewport_control()->update();
return true;
-
- //add wip point
}
}
} else if (mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed() && wip_active) {
@@ -362,6 +393,18 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return true;
}
}
+ } else if (mode == MODE_DELETE) {
+
+ if (mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
+
+ const PosVertex closest = closest_point(gpoint);
+
+ if (closest.valid()) {
+
+ remove_point(closest);
+ return true;
+ }
+ }
}
}
@@ -414,25 +457,33 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
Ref<InputEventKey> k = p_event;
- if (k.is_valid() && k->is_pressed() && (k->get_scancode() == KEY_DELETE || k->get_scancode() == KEY_BACKSPACE)) {
- if (wip_active && selected_point.polygon == -1) {
+ if (k.is_valid() && k->is_pressed()) {
- if (wip.size() > selected_point.vertex) {
+ if (k->get_scancode() == KEY_DELETE || k->get_scancode() == KEY_BACKSPACE) {
- wip.remove(selected_point.vertex);
- selected_point = wip.size() - 1;
- canvas_item_editor->get_viewport_control()->update();
- return true;
- }
- } else {
+ if (wip_active && selected_point.polygon == -1) {
- const Vertex active_point = get_active_point();
+ if (wip.size() > selected_point.vertex) {
- if (active_point.valid()) {
+ wip.remove(selected_point.vertex);
+ _wip_changed();
+ selected_point = wip.size() - 1;
+ canvas_item_editor->get_viewport_control()->update();
+ return true;
+ }
+ } else {
+
+ const Vertex active_point = get_active_point();
+
+ if (active_point.valid()) {
- remove_point(active_point);
- return true;
+ remove_point(active_point);
+ return true;
+ }
}
+ } else if (wip_active && k->get_scancode() == KEY_ENTER) {
+
+ _wip_close();
}
}
@@ -451,6 +502,7 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {
const Vertex active_point = get_active_point();
const int n_polygons = _get_polygon_count();
+ const bool is_closed = !_is_line();
for (int j = -1; j < n_polygons; j++) {
@@ -476,7 +528,7 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {
const Color col = Color(0.5, 0.5, 0.5); // FIXME polygon->get_outline_color();
const int n = pre_move_edit.size();
- for (int i = 0; i < n; i++) {
+ for (int i = 0; i < n - is_closed ? 0 : 1; i++) {
Vector2 p, p2;
p = pre_move_edit[i] + offset;
@@ -496,17 +548,22 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {
const Vertex vertex(j, i);
- Vector2 p, p2;
- p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
- if (j == edited_point.polygon && ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex)))
- p2 = edited_point.pos;
- else
- p2 = points[(i + 1) % n_points] + offset;
+ const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
+ const Vector2 point = xform.xform(p);
- Vector2 point = xform.xform(p);
- Vector2 next_point = xform.xform(p2);
+ if (is_closed || i < n_points - 1) {
+
+ Vector2 p2;
+ if (j == edited_point.polygon &&
+ ((wip_active && i == n_points - 1) || (((i + 1) % n_points) == edited_point.vertex)))
+ p2 = edited_point.pos;
+ else
+ p2 = points[(i + 1) % n_points] + offset;
+
+ const Vector2 next_point = xform.xform(p2);
+ vpc->draw_line(point, next_point, col, 2);
+ }
- vpc->draw_line(point, next_point, col, 2);
Ref<Texture> handle = vertex == active_point ? selected_handle : default_handle;
vpc->draw_texture(handle, point - handle->get_size() * 0.5);
}
@@ -674,7 +731,7 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
add_child(button_create);
button_create->connect("pressed", this, "_menu_option", varray(MODE_CREATE));
button_create->set_toggle_mode(true);
- button_create->set_tooltip(TTR("Create a new polygon from scratch."));
+ button_create->set_tooltip(TTR("Create a new polygon from scratch"));
button_edit = memnew(ToolButton);
add_child(button_edit);
@@ -682,6 +739,12 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(EditorNode *p_editor, bool p_wi
button_edit->set_toggle_mode(true);
button_edit->set_tooltip(TTR("Edit existing polygon:\nLMB: Move Point.\nCtrl+LMB: Split Segment.\nRMB: Erase Point."));
+ button_delete = memnew(ToolButton);
+ add_child(button_delete);
+ button_delete->connect("pressed", this, "_menu_option", varray(MODE_DELETE));
+ button_delete->set_toggle_mode(true);
+ button_delete->set_tooltip(TTR("Delete points"));
+
create_resource = memnew(ConfirmationDialog);
add_child(create_resource);
create_resource->get_ok()->set_text(TTR("Create"));
diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h
index 8dd22958db..915fe0803e 100644
--- a/editor/plugins/abstract_polygon_2d_editor.h
+++ b/editor/plugins/abstract_polygon_2d_editor.h
@@ -46,6 +46,7 @@ class AbstractPolygon2DEditor : public HBoxContainer {
ToolButton *button_create;
ToolButton *button_edit;
+ ToolButton *button_delete;
struct Vertex {
Vertex();
@@ -89,6 +90,7 @@ protected:
MODE_CREATE,
MODE_EDIT,
+ MODE_DELETE,
MODE_CONT,
};
@@ -98,7 +100,9 @@ protected:
UndoRedo *undo_redo;
virtual void _menu_option(int p_option);
+ void _wip_changed();
void _wip_close();
+ bool _delete_point(const Vector2 &p_gpoint);
void _notification(int p_what);
void _node_removed(Node *p_node);
@@ -116,6 +120,7 @@ protected:
virtual Node2D *_get_node() const = 0;
virtual void _set_node(Node *p_polygon) = 0;
+ virtual bool _is_line() const;
virtual int _get_polygon_count() const;
virtual Vector2 _get_offset(int p_idx) const;
virtual Variant _get_polygon(int p_idx) const;
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index cd53264437..d2e7feb6e1 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -33,6 +33,8 @@
#include "editor_settings.h"
#include "io/json.h"
+#include "version_generated.gen.h"
+
void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, int p_rating, const String &p_cost) {
title->set_text(p_title);
@@ -867,6 +869,8 @@ void EditorAssetLibrary::_search(int p_page) {
}
args += String() + "sort=" + sort_key[sort->get_selected()];
+ args += "&godot_version=" + itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR);
+
String support_list;
for (int i = 0; i < SUPPORT_MAX; i++) {
if (support->get_popup()->is_item_checked(i)) {
@@ -1348,13 +1352,11 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(memnew(Label(TTR("Site:") + " ")));
repository = memnew(OptionButton);
- // FIXME: Reenable me once GH-7147 is fixed.
- /*
repository->add_item("godotengine.org");
repository->set_item_metadata(0, "https://godotengine.org/asset-library/api");
- */
repository->add_item("localhost");
- repository->set_item_metadata(/*1*/ 0, "http://127.0.0.1/asset-library/api");
+ repository->set_item_metadata(1, "http://127.0.0.1/asset-library/api");
+
repository->connect("item_selected", this, "_repository_changed");
search_hb2->add_child(repository);
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index 0533aaa9c0..51fa488b43 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -29,259 +29,42 @@
/*************************************************************************/
#include "line_2d_editor_plugin.h"
-#include "canvas_item_editor_plugin.h"
-#include "editor/editor_settings.h"
-#include "os/file_access.h"
-#include "os/keyboard.h"
+Node2D *Line2DEditor::_get_node() const {
-//----------------------------------------------------------------------------
-// Line2DEditor
-//----------------------------------------------------------------------------
-
-void Line2DEditor::_node_removed(Node *p_node) {
- if (p_node == node) {
- node = NULL;
- hide();
- }
-}
-
-void Line2DEditor::_notification(int p_what) {
- switch (p_what) {
- case NOTIFICATION_VISIBILITY_CHANGED:
- // This widget is not a child but should have the same visibility state
- base_hb->set_visible(is_visible());
- break;
- }
-}
-
-int Line2DEditor::get_point_index_at(const Transform2D &xform, Vector2 gpos) {
- ERR_FAIL_COND_V(node == 0, -1);
-
- real_t grab_threshold = EDITOR_DEF("editors/poly_editor/point_grab_radius", 8);
-
- for (int i = 0; i < node->get_point_count(); ++i) {
- Point2 p = xform.xform(node->get_point_position(i));
- if (gpos.distance_to(p) < grab_threshold) {
- return i;
- }
- }
-
- return -1;
-}
-
-bool Line2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
-
- if (!node)
- return false;
-
- if (!node->is_visible())
- return false;
-
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
-
- Vector2 gpoint = mb->get_position();
- Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mb->get_position())));
-
- if (mb->is_pressed() && _dragging == false) {
- int i = get_point_index_at(canvas_item_editor->get_canvas_transform() * node->get_global_transform(), gpoint);
- if (i != -1) {
- if (mb->get_button_index() == BUTTON_LEFT && !mb->get_shift() && mode == MODE_EDIT) {
- _dragging = true;
- action_point = i;
- moving_from = node->get_point_position(i);
- moving_screen_from = gpoint;
- } else if ((mb->get_button_index() == BUTTON_RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == BUTTON_LEFT && mode == MODE_DELETE)) {
- undo_redo->create_action(TTR("Remove Point from Line2D"));
- undo_redo->add_do_method(node, "remove_point", i);
- undo_redo->add_undo_method(node, "add_point", node->get_point_position(i), i);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->commit_action();
- }
- return true;
- }
- }
-
- if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && ((mb->get_command() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
-
- undo_redo->create_action(TTR("Add Point to Line2D"));
- undo_redo->add_do_method(node, "add_point", cpoint);
- undo_redo->add_undo_method(node, "remove_point", node->get_point_count());
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->commit_action();
-
- _dragging = true;
- action_point = node->get_point_count() - 1;
- moving_from = node->get_point_position(action_point);
- moving_screen_from = gpoint;
-
- canvas_item_editor->get_viewport_control()->update();
-
- return true;
- }
-
- if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && _dragging) {
- undo_redo->create_action(TTR("Move Point in Line2D"));
- undo_redo->add_do_method(node, "set_point_position", action_point, cpoint);
- undo_redo->add_undo_method(node, "set_point_position", action_point, moving_from);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->commit_action();
- _dragging = false;
- return true;
- }
- }
-
- Ref<InputEventMouseMotion> mm = p_event;
-
- if (mm.is_valid()) {
-
- if (_dragging) {
- Vector2 gpoint = mm->get_position();
- Vector2 cpoint = node->get_global_transform().affine_inverse().xform(canvas_item_editor->snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(mm->get_position())));
- node->set_point_position(action_point, cpoint);
- canvas_item_editor->get_viewport_control()->update();
- return true;
- }
- }
-
- return false;
+ return node;
}
-void Line2DEditor::forward_draw_over_canvas(Control *p_canvas) {
-
- if (!node)
- return;
-
- if (!node->is_visible())
- return;
+void Line2DEditor::_set_node(Node *p_line) {
- Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform();
- Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons");
- Size2 handle_size = handle->get_size();
-
- int len = node->get_point_count();
- Control *vpc = canvas_item_editor->get_viewport_control();
-
- for (int i = 0; i < len; ++i) {
- Vector2 point = xform.xform(node->get_point_position(i));
- vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false);
- }
+ node = Object::cast_to<Line2D>(p_line);
}
-void Line2DEditor::_node_visibility_changed() {
- if (!node)
- return;
- canvas_item_editor->get_viewport_control()->update();
-}
-
-void Line2DEditor::edit(Node *p_line2d) {
-
- if (!canvas_item_editor)
- canvas_item_editor = CanvasItemEditor::get_singleton();
+bool Line2DEditor::_is_line() const {
- if (p_line2d) {
- node = Object::cast_to<Line2D>(p_line2d);
- if (!node->is_connected("visibility_changed", this, "_node_visibility_changed"))
- node->connect("visibility_changed", this, "_node_visibility_changed");
- } else {
- // node may have been deleted at this point
- if (node && node->is_connected("visibility_changed", this, "_node_visibility_changed"))
- node->disconnect("visibility_changed", this, "_node_visibility_changed");
- node = NULL;
- }
+ return true;
}
-void Line2DEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Line2DEditor::_node_visibility_changed);
- ClassDB::bind_method(D_METHOD("_mode_selected"), &Line2DEditor::_mode_selected);
-}
+Variant Line2DEditor::_get_polygon(int p_idx) const {
-void Line2DEditor::_mode_selected(int p_mode) {
- for (int i = 0; i < _MODE_COUNT; ++i) {
- toolbar_buttons[i]->set_pressed(i == p_mode);
- }
- mode = Mode(p_mode);
+ return _get_node()->get("points");
}
-Line2DEditor::Line2DEditor(EditorNode *p_editor) {
-
- canvas_item_editor = NULL;
- editor = p_editor;
- undo_redo = editor->get_undo_redo();
-
- _dragging = false;
-
- base_hb = memnew(HBoxContainer);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(base_hb);
-
- sep = memnew(VSeparator);
- base_hb->add_child(sep);
-
- {
- ToolButton *b = memnew(ToolButton);
- b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveEdit", "EditorIcons"));
- b->set_toggle_mode(true);
- b->set_focus_mode(Control::FOCUS_NONE);
- b->set_tooltip(
- TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
- b->connect("pressed", this, "_mode_selected", varray(MODE_EDIT));
- toolbar_buttons[MODE_EDIT] = b;
- base_hb->add_child(b);
- }
+void Line2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
- {
- ToolButton *b = memnew(ToolButton);
- b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveCreate", "EditorIcons"));
- b->set_toggle_mode(true);
- b->set_focus_mode(Control::FOCUS_NONE);
- b->set_tooltip(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in line)"));
- b->connect("pressed", this, "_mode_selected", varray(MODE_CREATE));
- toolbar_buttons[MODE_CREATE] = b;
- base_hb->add_child(b);
- }
-
- {
- ToolButton *b = memnew(ToolButton);
- b->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("CurveDelete", "EditorIcons"));
- b->set_toggle_mode(true);
- b->set_focus_mode(Control::FOCUS_NONE);
- b->set_tooltip(TTR("Delete Point"));
- b->connect("pressed", this, "_mode_selected", varray(MODE_DELETE));
- toolbar_buttons[MODE_DELETE] = b;
- base_hb->add_child(b);
- }
-
- base_hb->hide();
- hide();
-
- _mode_selected(MODE_CREATE);
+ _get_node()->set("points", p_polygon);
}
-//----------------------------------------------------------------------------
-// Line2DEditorPlugin
-//----------------------------------------------------------------------------
-
-void Line2DEditorPlugin::edit(Object *p_object) {
- line2d_editor->edit(Object::cast_to<Node>(p_object));
-}
+void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
-bool Line2DEditorPlugin::handles(Object *p_object) const {
- return p_object->is_class("Line2D");
+ Node2D *node = _get_node();
+ undo_redo->add_do_method(node, "set_points", p_polygon);
+ undo_redo->add_undo_method(node, "set_points", p_previous);
}
-void Line2DEditorPlugin::make_visible(bool p_visible) {
- line2d_editor->set_visible(p_visible);
- if (p_visible == false)
- line2d_editor->edit(NULL);
+Line2DEditor::Line2DEditor(EditorNode *p_editor)
+ : AbstractPolygon2DEditor(p_editor) {
}
-Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) {
- editor = p_node;
- line2d_editor = memnew(Line2DEditor(p_node));
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(line2d_editor);
- line2d_editor->hide();
+Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node)
+ : AbstractPolygon2DEditorPlugin(p_node, memnew(Line2DEditor(p_node)), "Line2D") {
}
diff --git a/editor/plugins/line_2d_editor_plugin.h b/editor/plugins/line_2d_editor_plugin.h
index 6858680aed..24c19c420d 100644
--- a/editor/plugins/line_2d_editor_plugin.h
+++ b/editor/plugins/line_2d_editor_plugin.h
@@ -30,78 +30,34 @@
#ifndef LINE_2D_EDITOR_PLUGIN_H
#define LINE_2D_EDITOR_PLUGIN_H
-#include "editor/editor_node.h"
-#include "editor/editor_plugin.h"
+#include "editor/plugins/abstract_polygon_2d_editor.h"
#include "scene/2d/line_2d.h"
-#include "scene/2d/path_2d.h"
-#include "scene/gui/tool_button.h"
-class CanvasItemEditor;
+class Line2DEditor : public AbstractPolygon2DEditor {
-class Line2DEditor : public HBoxContainer {
- GDCLASS(Line2DEditor, HBoxContainer)
-private:
- void _mode_selected(int p_mode);
- void _node_visibility_changed();
+ GDCLASS(Line2DEditor, AbstractPolygon2DEditor);
- int get_point_index_at(const Transform2D &xform, Vector2 gpos);
-
- UndoRedo *undo_redo;
-
- CanvasItemEditor *canvas_item_editor;
- EditorNode *editor;
- Panel *panel;
Line2D *node;
- HBoxContainer *base_hb;
- Separator *sep;
-
- enum Mode {
- MODE_CREATE = 0,
- MODE_EDIT,
- MODE_DELETE,
- _MODE_COUNT
- };
-
- Mode mode;
- ToolButton *toolbar_buttons[_MODE_COUNT];
-
- bool _dragging;
- int action_point;
- Point2 moving_from;
- Point2 moving_screen_from;
-
protected:
- void _node_removed(Node *p_node);
- void _notification(int p_what);
+ virtual Node2D *_get_node() const;
+ virtual void _set_node(Node *p_line);
- static void _bind_methods();
+ virtual bool _is_line() const;
+ virtual Variant _get_polygon(int p_idx) const;
+ virtual void _set_polygon(int p_idx, const Variant &p_polygon) const;
+ virtual void _action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon);
public:
- bool forward_canvas_gui_input(const Ref<InputEvent> &p_event);
- void forward_draw_over_canvas(Control *p_canvas);
- void edit(Node *p_line2d);
Line2DEditor(EditorNode *p_editor);
};
-class Line2DEditorPlugin : public EditorPlugin {
- GDCLASS(Line2DEditorPlugin, EditorPlugin)
-
-public:
- virtual bool forward_canvas_gui_input(const Ref<InputEvent> &p_event) { return line2d_editor->forward_canvas_gui_input(p_event); }
- virtual void forward_draw_over_canvas(Control *p_canvas) { return line2d_editor->forward_draw_over_canvas(p_canvas); }
+class Line2DEditorPlugin : public AbstractPolygon2DEditorPlugin {
- virtual String get_name() const { return "Line2D"; }
- bool has_main_screen() const { return false; }
- virtual void edit(Object *p_object);
- virtual bool handles(Object *p_object) const;
- virtual void make_visible(bool p_visible);
+ GDCLASS(Line2DEditorPlugin, AbstractPolygon2DEditorPlugin);
+public:
Line2DEditorPlugin(EditorNode *p_node);
-
-private:
- Line2DEditor *line2d_editor;
- EditorNode *editor;
};
#endif // LINE_2D_EDITOR_PLUGIN_H
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 02ead3aee8..7f956b01ff 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -427,7 +427,9 @@ void ThemeEditor::_dialog_cbk() {
void ThemeEditor::_theme_menu_cbk(int p_option) {
- if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY) {
+ if (p_option == POPUP_CREATE_EMPTY || p_option == POPUP_CREATE_EDITOR_EMPTY || p_option == POPUP_IMPORT_EDITOR_THEME) {
+
+ bool import = (p_option == POPUP_IMPORT_EDITOR_THEME);
Ref<Theme> base_theme;
@@ -449,21 +451,21 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
base_theme->get_icon_list(type, &icons);
for (List<StringName>::Element *E = icons.front(); E; E = E->next()) {
- theme->set_icon(E->get(), type, Ref<Texture>());
+ theme->set_icon(E->get(), type, import ? base_theme->get_icon(E->get(), type) : Ref<Texture>());
}
List<StringName> shaders;
base_theme->get_shader_list(type, &shaders);
for (List<StringName>::Element *E = shaders.front(); E; E = E->next()) {
- theme->set_shader(E->get(), type, Ref<Shader>());
+ theme->set_shader(E->get(), type, import ? base_theme->get_shader(E->get(), type) : Ref<Shader>());
}
List<StringName> styleboxs;
base_theme->get_stylebox_list(type, &styleboxs);
for (List<StringName>::Element *E = styleboxs.front(); E; E = E->next()) {
- theme->set_stylebox(E->get(), type, Ref<StyleBox>());
+ theme->set_stylebox(E->get(), type, import ? base_theme->get_stylebox(E->get(), type) : Ref<StyleBox>());
}
List<StringName> fonts;
@@ -477,14 +479,14 @@ void ThemeEditor::_theme_menu_cbk(int p_option) {
base_theme->get_color_list(type, &colors);
for (List<StringName>::Element *E = colors.front(); E; E = E->next()) {
- theme->set_color(E->get(), type, Color());
+ theme->set_color(E->get(), type, import ? base_theme->get_color(E->get(), type) : Color());
}
List<StringName> constants;
base_theme->get_constant_list(type, &constants);
for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- theme->set_constant(E->get(), type, base_theme->get_constant(type, E->get()));
+ theme->set_constant(E->get(), type, base_theme->get_constant(E->get(), type));
}
}
}
@@ -639,7 +641,7 @@ ThemeEditor::ThemeEditor() {
theme_menu->get_popup()->add_separator();
theme_menu->get_popup()->add_item(TTR("Create Empty Template"), POPUP_CREATE_EMPTY);
theme_menu->get_popup()->add_item(TTR("Create Empty Editor Template"), POPUP_CREATE_EDITOR_EMPTY);
-
+ theme_menu->get_popup()->add_item(TTR("Create From Current Editor Theme"), POPUP_IMPORT_EDITOR_THEME);
add_child(theme_menu);
theme_menu->set_position(Vector2(3, 3) * EDSCALE);
theme_menu->get_popup()->connect("id_pressed", this, "_theme_menu_cbk");
diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h
index 16b2da94d1..4d46282ba1 100644
--- a/editor/plugins/theme_editor_plugin.h
+++ b/editor/plugins/theme_editor_plugin.h
@@ -69,7 +69,8 @@ class ThemeEditor : public Control {
POPUP_REMOVE,
POPUP_CLASS_REMOVE,
POPUP_CREATE_EMPTY,
- POPUP_CREATE_EDITOR_EMPTY
+ POPUP_CREATE_EDITOR_EMPTY,
+ POPUP_IMPORT_EDITOR_THEME
};
int popup_mode;
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 9235dafaa6..0ee0eed3a2 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -973,7 +973,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2i pos = points[i];
- if (!paint_undo.has(over_tile)) {
+ if (!paint_undo.has(pos)) {
paint_undo[pos] = _get_op_from_cell(pos);
}
@@ -993,7 +993,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
Point2i pos = points[i];
- if (!paint_undo.has(over_tile)) {
+ if (!paint_undo.has(pos)) {
paint_undo[pos] = _get_op_from_cell(pos);
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 7438c7671e..58f70ce11e 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -533,10 +533,6 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (p_confirm_override) {
_delete_confirm();
- // hack, force 2d editor viewport to refresh after deletion
- if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton())
- editor->get_viewport_control()->update();
-
} else {
delete_dialog->set_text(TTR("Delete Node(s)?"));
delete_dialog->popup_centered_minsize();
@@ -1345,6 +1341,12 @@ void SceneTreeDock::_delete_confirm() {
}
}
editor_data->get_undo_redo().commit_action();
+
+ // hack, force 2d editor viewport to refresh after deletion
+ if (CanvasItemEditor *editor = CanvasItemEditor::get_singleton())
+ editor->get_viewport_control()->update();
+
+ editor->push_item(NULL);
}
void SceneTreeDock::_selection_changed() {
diff --git a/main/main.cpp b/main/main.cpp
index 5e8e52d3e5..aa4dce93a6 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -321,8 +321,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
I = args.front();
- video_mode = OS::get_singleton()->get_default_video_mode();
-
String video_driver = "";
String audio_driver = "";
String game_path = ".";
@@ -779,38 +777,41 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
//if (video_driver == "") // useless for now, so removing
// video_driver = GLOBAL_DEF("display/driver/name", Variant((const char *)OS::get_singleton()->get_video_driver_name(0)));
- if (!force_res && use_custom_res && globals->has_setting("display/window/size/width"))
- video_mode.width = globals->get("display/window/size/width");
- if (!force_res && use_custom_res && globals->has_setting("display/window/size/height"))
- video_mode.height = globals->get("display/window/size/height");
- if (!editor && ((globals->has_setting("display/window/dpi/allow_hidpi") && !globals->get("display/window/dpi/allow_hidpi")) || force_lowdpi)) {
- OS::get_singleton()->_allow_hidpi = false;
- }
- if (use_custom_res && globals->has_setting("display/window/size/fullscreen"))
- video_mode.fullscreen = globals->get("display/window/size/fullscreen");
- if (use_custom_res && globals->has_setting("display/window/size/resizable"))
- video_mode.resizable = globals->get("display/window/size/resizable");
- if (use_custom_res && globals->has_setting("display/window/size/borderless"))
- video_mode.borderless_window = globals->get("display/window/size/borderless");
-
- if (!force_res && use_custom_res && globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) {
- int tw = globals->get("display/window/size/test_width");
- int th = globals->get("display/window/size/test_height");
- if (tw > 0 && th > 0) {
- video_mode.width = tw;
- video_mode.height = th;
+ GLOBAL_DEF("display/window/size/width", 1024);
+ GLOBAL_DEF("display/window/size/height", 600);
+ GLOBAL_DEF("display/window/size/resizable", true);
+ GLOBAL_DEF("display/window/size/borderless", false);
+ GLOBAL_DEF("display/window/size/fullscreen", false);
+ GLOBAL_DEF("display/window/size/test_width", 0);
+ GLOBAL_DEF("display/window/size/test_height", 0);
+
+ if (use_custom_res) {
+
+ if (!force_res) {
+ video_mode.width = GLOBAL_GET("display/window/size/width");
+ video_mode.height = GLOBAL_GET("display/window/size/height");
+
+ if (globals->has_setting("display/window/size/test_width") && globals->has_setting("display/window/size/test_height")) {
+ int tw = globals->get("display/window/size/test_width");
+ int th = globals->get("display/window/size/test_height");
+ if (tw > 0 && th > 0) {
+ video_mode.width = tw;
+ video_mode.height = th;
+ }
+ }
}
+
+ video_mode.resizable = GLOBAL_GET("display/window/size/resizable");
+ video_mode.borderless_window = GLOBAL_GET("display/window/size/borderless");
+ video_mode.fullscreen = GLOBAL_GET("display/window/size/fullscreen");
}
- GLOBAL_DEF("display/window/size/width", video_mode.width);
- GLOBAL_DEF("display/window/size/height", video_mode.height);
- GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
- GLOBAL_DEF("display/window/size/fullscreen", video_mode.fullscreen);
- GLOBAL_DEF("display/window/size/resizable", video_mode.resizable);
- GLOBAL_DEF("display/window/size/borderless", video_mode.borderless_window);
- use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", use_vsync);
- GLOBAL_DEF("display/window/size/test_width", 0);
- GLOBAL_DEF("display/window/size/test_height", 0);
+ if (!force_lowdpi) {
+ OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false);
+ }
+
+ use_vsync = GLOBAL_DEF("display/window/vsync/use_vsync", true);
+
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation", 2);
GLOBAL_DEF("rendering/quality/intended_usage/framebuffer_allocation.mobile", 3);
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index 3fbbdf50b3..7f95d16ba6 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -81,7 +81,7 @@ void BulletPhysicsServer::_bind_methods() {
BulletPhysicsServer::BulletPhysicsServer()
: PhysicsServer(),
active(true),
- activeSpace(NULL) {}
+ active_spaces_count(0) {}
BulletPhysicsServer::~BulletPhysicsServer() {}
@@ -162,27 +162,28 @@ RID BulletPhysicsServer::space_create() {
}
void BulletPhysicsServer::space_set_active(RID p_space, bool p_active) {
+
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+
+ if (space_is_active(p_space) == p_active) {
+ return;
+ }
+
if (p_active) {
- if (activeSpace) {
- // There is another space and this cannot be activated
- ERR_PRINT("There is another space, before activate new one deactivate the current space.");
- } else {
- SpaceBullet *space = space_owner.get(p_space);
- if (space) {
- activeSpace = space;
- } else {
- ERR_PRINT("The passed RID is not a valid space. Please provide a RID with SpaceBullet type.");
- }
- }
+ ++active_spaces_count;
+ active_spaces.push_back(space);
} else {
- if (!space_is_active(p_space)) {
- activeSpace = NULL;
- }
+ --active_spaces_count;
+ active_spaces.erase(space);
}
}
bool BulletPhysicsServer::space_is_active(RID p_space) const {
- return NULL != activeSpace && activeSpace == p_space.get_data();
+ SpaceBullet *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space, false);
+
+ return -1 != active_spaces.find(space);
}
void BulletPhysicsServer::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
@@ -1318,8 +1319,10 @@ void BulletPhysicsServer::step(float p_deltaTime) {
return;
BulletPhysicsDirectBodyState::singleton_setDeltaTime(p_deltaTime);
- if (activeSpace) {
- activeSpace->step(p_deltaTime);
+
+ for (int i = 0; i < active_spaces_count; ++i) {
+
+ active_spaces[i]->step(p_deltaTime);
}
}
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index c1859ca149..ad8137ee2f 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -47,7 +47,8 @@ class BulletPhysicsServer : public PhysicsServer {
friend class BulletPhysicsDirectSpaceState;
bool active;
- SpaceBullet *activeSpace;
+ char active_spaces_count;
+ Vector<SpaceBullet *> active_spaces;
mutable RID_Owner<SpaceBullet> space_owner;
mutable RID_Owner<ShapeBullet> shape_owner;
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index 449d4322d4..91a049b1f3 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -93,11 +93,15 @@ void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_coll
void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
exceptions.insert(p_ignoreCollisionObject->get_self());
bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true);
+ if (space)
+ space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());
}
void CollisionObjectBullet::remove_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
exceptions.erase(p_ignoreCollisionObject->get_self());
bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, false);
+ if (space)
+ space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());
}
bool CollisionObjectBullet::has_collision_exception(const CollisionObjectBullet *p_otherCollisionObject) const {
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index c0acef4f86..d9206f8046 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -113,6 +113,7 @@ public:
void flush_queries();
void step(real_t p_delta_time);
+ _FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; }
_FORCE_INLINE_ btCollisionDispatcher *get_dispatcher() { return dispatcher; }
_FORCE_INLINE_ btSoftBodyWorldInfo *get_soft_body_world_info() { return soft_body_world_info; }
_FORCE_INLINE_ bool is_using_soft_world() { return soft_body_world_info; }
diff --git a/modules/gdnative/gdnative/array.cpp b/modules/gdnative/gdnative/array.cpp
index 51c023981f..90bc4dc031 100644
--- a/modules/gdnative/gdnative/array.cpp
+++ b/modules/gdnative/gdnative/array.cpp
@@ -158,6 +158,11 @@ godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, const godot
return (godot_variant *)&self->operator[](p_idx);
}
+const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, const godot_int p_idx) {
+ const Array *self = (const Array *)p_self;
+ return (const godot_variant *)&self->operator[](p_idx);
+}
+
void GDAPI godot_array_append(godot_array *p_self, const godot_variant *p_value) {
Array *self = (Array *)p_self;
Variant *val = (Variant *)p_value;
diff --git a/modules/gdnative/gdnative/dictionary.cpp b/modules/gdnative/gdnative/dictionary.cpp
index ed98cdbb00..7f8320622d 100644
--- a/modules/gdnative/gdnative/dictionary.cpp
+++ b/modules/gdnative/gdnative/dictionary.cpp
@@ -130,6 +130,12 @@ godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, c
return (godot_variant *)&self->operator[](*key);
}
+const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key) {
+ const Dictionary *self = (const Dictionary *)p_self;
+ const Variant *key = (const Variant *)p_key;
+ return (const godot_variant *)&self->operator[](*key);
+}
+
godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key) {
Dictionary *self = (Dictionary *)p_self;
const Variant *key = (const Variant *)p_key;
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index ac0293172d..0bd9dbceb4 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -2489,6 +2489,14 @@
]
},
{
+ "name": "godot_array_operator_index_const",
+ "return_type": "const godot_variant *",
+ "arguments": [
+ ["const godot_array *", "p_self"],
+ ["const godot_int", "p_idx"]
+ ]
+ },
+ {
"name": "godot_array_append",
"return_type": "void",
"arguments": [
@@ -2787,6 +2795,14 @@
]
},
{
+ "name": "godot_dictionary_operator_index_const",
+ "return_type": "const godot_variant *",
+ "arguments": [
+ ["const godot_dictionary *", "p_self"],
+ ["const godot_variant *", "p_key"]
+ ]
+ },
+ {
"name": "godot_dictionary_next",
"return_type": "godot_variant *",
"arguments": [
@@ -5645,6 +5661,13 @@
]
},
{
+ "name": "godot_pluginscript_register_language",
+ "return_type": "void",
+ "arguments": [
+ ["const godot_pluginscript_language_desc *", "language_desc"]
+ ]
+ },
+ {
"name": "godot_arvr_register_interface",
"return_type": "void",
"arguments": [
diff --git a/modules/gdnative/include/gdnative/array.h b/modules/gdnative/include/gdnative/array.h
index d0639589b7..01ae61e280 100644
--- a/modules/gdnative/include/gdnative/array.h
+++ b/modules/gdnative/include/gdnative/array.h
@@ -76,6 +76,8 @@ godot_variant GDAPI godot_array_get(const godot_array *p_self, const godot_int p
godot_variant GDAPI *godot_array_operator_index(godot_array *p_self, const godot_int p_idx);
+const godot_variant GDAPI *godot_array_operator_index_const(const godot_array *p_self, const godot_int p_idx);
+
void GDAPI godot_array_append(godot_array *p_self, const godot_variant *p_value);
void GDAPI godot_array_clear(godot_array *p_self);
diff --git a/modules/gdnative/include/gdnative/dictionary.h b/modules/gdnative/include/gdnative/dictionary.h
index e68d0fdc29..6d1f436921 100644
--- a/modules/gdnative/include/gdnative/dictionary.h
+++ b/modules/gdnative/include/gdnative/dictionary.h
@@ -85,6 +85,8 @@ void GDAPI godot_dictionary_set(godot_dictionary *p_self, const godot_variant *p
godot_variant GDAPI *godot_dictionary_operator_index(godot_dictionary *p_self, const godot_variant *p_key);
+const godot_variant GDAPI *godot_dictionary_operator_index_const(const godot_dictionary *p_self, const godot_variant *p_key);
+
godot_variant GDAPI *godot_dictionary_next(const godot_dictionary *p_self, const godot_variant *p_key);
godot_bool GDAPI godot_dictionary_operator_equal(const godot_dictionary *p_self, const godot_dictionary *p_b);
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index d9b10ff3fa..de8e35c406 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -1060,7 +1060,7 @@ static bool _guess_identifier_type_in_block(GDCompletionContext &context, int p_
}
//use the last assignment, (then backwards?)
- if (last_assign) {
+ if (last_assign && last_assign_line != p_line) {
return _guess_expression_type(context, last_assign, last_assign_line, r_type);
}
@@ -1194,6 +1194,8 @@ static bool _guess_identifier_type(GDCompletionContext &context, int p_line, con
r_type = _get_type_from_pinfo(context._class->variables[i]._export);
return true;
} else if (context._class->variables[i].expression) {
+ if (p_line <= context._class->variables[i].line)
+ return false;
bool rtype = _guess_expression_type(context, context._class->variables[i].expression, context._class->variables[i].line, r_type);
if (rtype && r_type.type != Variant::NIL)
diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp
index ce503b62f2..1a46ad324a 100644
--- a/modules/gdscript/gd_function.cpp
+++ b/modules/gdscript/gd_function.cpp
@@ -170,7 +170,7 @@ static String _get_var_type(const Variant *p_type) {
return basestr;
}
-#if defined(__GNUC__) && !defined(__clang__)
+#if defined(__GNUC__)
#define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
@@ -427,8 +427,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 5;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_EXTENDS_TEST) {
CHECK_SPACE(4);
@@ -492,8 +493,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = extends_ok;
ip += 4;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_SET) {
CHECK_SPACE(3);
@@ -518,8 +520,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 4;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_GET) {
CHECK_SPACE(3);
@@ -550,8 +553,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 4;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_SET_NAMED) {
CHECK_SPACE(3);
@@ -575,8 +579,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 4;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_GET_NAMED) {
CHECK_SPACE(4);
@@ -609,8 +614,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = ret;
#endif
ip += 4;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_SET_MEMBER) {
CHECK_SPACE(3);
@@ -631,8 +637,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 3;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_GET_MEMBER) {
CHECK_SPACE(3);
@@ -649,8 +656,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 3;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN) {
CHECK_SPACE(3);
@@ -660,8 +668,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = *src;
ip += 3;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN_TRUE) {
CHECK_SPACE(2);
@@ -670,8 +679,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = true;
ip += 2;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSIGN_FALSE) {
CHECK_SPACE(2);
@@ -680,8 +690,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = false;
ip += 2;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CONSTRUCT) {
CHECK_SPACE(2);
@@ -708,8 +719,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ip += 4 + argc;
//construct a basic type
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CONSTRUCT_ARRAY) {
CHECK_SPACE(1);
@@ -728,8 +740,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = array;
ip += 3 + argc;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CONSTRUCT_DICTIONARY) {
CHECK_SPACE(1);
@@ -750,8 +763,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = dict;
ip += 3 + argc * 2;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CALL_RETURN)
OPCODE(OPCODE_CALL) {
@@ -830,8 +844,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
ip += argc + 1;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CALL_BUILT_IN) {
CHECK_SPACE(4);
@@ -869,12 +884,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += argc + 1;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_CALL_SELF) {
OPCODE_BREAK;
}
+
OPCODE(OPCODE_CALL_SELF_BASE) {
CHECK_SPACE(2);
@@ -948,8 +965,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
ip += 4 + argc;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_YIELD)
OPCODE(OPCODE_YIELD_SIGNAL) {
@@ -1032,6 +1050,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
exit_ok = true;
OPCODE_BREAK;
}
+
OPCODE(OPCODE_YIELD_RESUME) {
CHECK_SPACE(2);
@@ -1044,8 +1063,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(result, 1);
*result = p_state->result;
ip += 2;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
@@ -1053,8 +1073,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP_IF) {
CHECK_SPACE(3);
@@ -1067,11 +1088,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- DISPATCH_OPCODE;
+ } else {
+ ip += 3;
}
- ip += 3;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP_IF_NOT) {
CHECK_SPACE(3);
@@ -1084,17 +1106,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int to = _code_ptr[ip + 2];
GD_ERR_BREAK(to < 0 || to > _code_size);
ip = to;
- DISPATCH_OPCODE;
+ } else {
+ ip += 3;
}
- ip += 3;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP_TO_DEF_ARGUMENT) {
CHECK_SPACE(2);
ip = _default_arg_ptr[defarg];
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_RETURN) {
CHECK_SPACE(2);
@@ -1103,6 +1127,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
exit_ok = true;
OPCODE_BREAK;
}
+
OPCODE(OPCODE_ITERATE_BEGIN) {
CHECK_SPACE(8); //space for this a regular iterate
@@ -1121,20 +1146,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int jumpto = _code_ptr[ip + 3];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
- DISPATCH_OPCODE;
- }
- GET_VARIANT_PTR(iterator, 4);
+ } else {
+ GET_VARIANT_PTR(iterator, 4);
- *iterator = container->iter_get(*counter, valid);
+ *iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
- OPCODE_BREAK;
- }
+ if (!valid) {
+ err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
+ OPCODE_BREAK;
+ }
#endif
- ip += 5; //skip regular iterate which is always next
- DISPATCH_OPCODE;
+ ip += 5; //skip regular iterate which is always next
+ }
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ITERATE) {
CHECK_SPACE(4);
@@ -1153,20 +1179,21 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
int jumpto = _code_ptr[ip + 3];
GD_ERR_BREAK(jumpto < 0 || jumpto > _code_size);
ip = jumpto;
- DISPATCH_OPCODE;
- }
- GET_VARIANT_PTR(iterator, 4);
+ } else {
+ GET_VARIANT_PTR(iterator, 4);
- *iterator = container->iter_get(*counter, valid);
+ *iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
- if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
- OPCODE_BREAK;
- }
+ if (!valid) {
+ err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
+ OPCODE_BREAK;
+ }
#endif
- ip += 5; //loop again
- DISPATCH_OPCODE;
+ ip += 5; //loop again
+ }
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_ASSERT) {
CHECK_SPACE(2);
GET_VARIANT_PTR(test, 1);
@@ -1182,8 +1209,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
ip += 2;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_BREAKPOINT) {
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
@@ -1191,8 +1219,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip += 1;
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_LINE) {
CHECK_SPACE(2);
@@ -1220,8 +1249,9 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ScriptDebugger::get_singleton()->line_poll();
}
- DISPATCH_OPCODE;
}
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_END) {
exit_ok = true;
diff --git a/modules/mobile_vr/mobile_interface.cpp b/modules/mobile_vr/mobile_interface.cpp
index eb87bb2cf0..93d5c22ef8 100644
--- a/modules/mobile_vr/mobile_interface.cpp
+++ b/modules/mobile_vr/mobile_interface.cpp
@@ -122,6 +122,7 @@ void MobileVRInterface::set_position_from_sensors() {
Vector3 north(0.0, 0.0, 1.0); // North is Z positive
// make copies of our inputs
+ bool has_grav = false;
Vector3 acc = input->get_accelerometer();
Vector3 gyro = input->get_gyroscope();
Vector3 grav = input->get_gravity();
@@ -143,14 +144,17 @@ void MobileVRInterface::set_position_from_sensors() {
// what a stable gravity vector is
grav = acc;
if (grav.length() > 0.1) {
- has_gyro = true;
+ has_grav = true;
};
} else {
- has_gyro = true;
+ has_grav = true;
};
bool has_magneto = magneto.length() > 0.1;
- bool has_grav = grav.length() > 0.1;
+ if (gyro.length() > 0.1) {
+ /* this can return to 0.0 if the user doesn't move the phone, so once on, it's on */
+ has_gyro = true;
+ };
#ifdef ANDROID_ENABLED
///@TODO needs testing, i don't have a gyro, potentially can be removed depending on what comes out of issue #8101
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 8d73de9889..a5dc6ffc13 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -858,6 +858,8 @@ public:
if (call_mode == VisualScriptFunctionCall::CALL_MODE_INSTANCE) {
if (returns >= 2) {
*p_outputs[1] = v.call(function, p_inputs + 1, input_args, r_error);
+ } else if (returns == 1) {
+ v.call(function, p_inputs + 1, input_args, r_error);
} else {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Invalid returns count for call_mode == CALL_MODE_INSTANCE";
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 13fc4ee810..966de832e8 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -2,6 +2,7 @@ import os
import sys
import string
import platform
+from distutils.version import LooseVersion
def is_active():
@@ -25,7 +26,7 @@ def get_opts():
('ndk_platform', 'Target platform (android-<api>, e.g. "android-18")', "android-18"),
EnumVariable('android_arch', 'Target architecture', "armv7", ('armv7', 'armv6', 'arm64v8', 'x86')),
BoolVariable('android_neon', 'Enable NEON support (armv7 only)', True),
- BoolVariable('android_stl', 'Enable Android STL support (for modules)', False),
+ BoolVariable('android_stl', 'Enable Android STL support (for modules)', True)
]
@@ -178,12 +179,24 @@ def configure(env):
env['RANLIB'] = tools_path + "/ranlib"
env['AS'] = tools_path + "/as"
- sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
common_opts = ['-fno-integrated-as', '-gcc-toolchain', gcc_toolchain_path]
+ lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env['ndk_platform'] + "/" + env['ARCH']
+
## Compile flags
- env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
+ ndk_version = get_ndk_version(env["ANDROID_NDK_ROOT"])
+ if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("15.0.4075724"):
+ print("Using NDK unified headers")
+ sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot"
+ env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
+ env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath])
+ # For unified headers this define has to be set manually
+ env.Append(CPPFLAGS=["-D__ANDROID_API__=" + str(int(env['ndk_platform'].split("-")[1]))])
+ else:
+ print("Using NDK deprecated headers")
+ env.Append(CPPFLAGS=["-isystem", lib_sysroot + "/usr/include"])
+
env.Append(CPPFLAGS='-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing'.split())
env.Append(CPPFLAGS='-DNO_STATVFS -DGLES2_ENABLED'.split())
@@ -224,7 +237,7 @@ def configure(env):
## Link flags
- env['LINKFLAGS'] = ['-shared', '--sysroot=' + sysroot, '-Wl,--warn-shared-textrel']
+ env['LINKFLAGS'] = ['-shared', '--sysroot=' + lib_sysroot, '-Wl,--warn-shared-textrel']
if env["android_arch"] == "armv7":
env.Append(LINKFLAGS='-Wl,--fix-cortex-a8'.split())
env.Append(LINKFLAGS='-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now'.split())
@@ -248,3 +261,18 @@ def configure(env):
if (env["android_arch"] == "armv6" or env["android_arch"] == "armv7"):
env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
env.opus_fixed_point = "yes"
+
+# Return NDK version string in source.properties (adapted from the Chromium project).
+def get_ndk_version(path):
+ if path == None:
+ return None
+ prop_file_path = os.path.join(path, "source.properties")
+ try:
+ with open(prop_file_path) as prop_file:
+ for line in prop_file:
+ key_value = map(lambda x: string.strip(x), line.split("="))
+ if key_value[0] == "Pkg.Revision":
+ return key_value[1]
+ except:
+ print("Could not read source prop file '%s'" % prop_file_path)
+ return None
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 9d43adf788..970e0cdf68 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -65,12 +65,6 @@ const char *OS_Android::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-
-OS::VideoMode OS_Android::get_default_video_mode() const {
-
- return OS::VideoMode();
-}
-
int OS_Android::get_audio_driver_count() const {
return 1;
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index d9a66b4e3a..fee91b9a55 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -141,8 +141,6 @@ public:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h
index b1c3f027f3..b1f51c9256 100644
--- a/platform/android/platform_config.h
+++ b/platform/android/platform_config.h
@@ -28,3 +28,4 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include <alloca.h>
+#include <malloc.h>
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index 7a681d46f7..0c34e39655 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -79,10 +79,6 @@ const char *OS_Haiku::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-OS::VideoMode OS_Haiku::get_default_video_mode() const {
- return OS::VideoMode(800, 600, false);
-}
-
void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
main_loop = NULL;
current_video_mode = p_desired;
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index 501650c94f..86148f1fb4 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -65,7 +65,6 @@ private:
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index 65cafbd6d4..8f2893e69e 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -638,6 +638,9 @@ static int frame_count = 0;
mainViewController = view_controller;
+ // prevent to stop music in another background app
+ [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
+
#ifdef MODULE_GAME_ANALYTICS_ENABLED
printf("********************* didFinishLaunchingWithOptions\n");
if (!ProjectSettings::get_singleton()->has("mobileapptracker/advertiser_id")) {
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index f01d9367d2..cfc0741318 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -6,7 +6,6 @@ javascript_files = [
"os_javascript.cpp",
"audio_driver_javascript.cpp",
"javascript_main.cpp",
- "audio_server_javascript.cpp",
"power_javascript.cpp",
"javascript_eval.cpp",
]
@@ -19,7 +18,7 @@ javascript_objects = []
for x in javascript_files:
javascript_objects.append(env_javascript.Object(x))
-env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync','_send_notification']\""])
+env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_main_after_fs_sync','_send_notification']\""])
# output file name without file extension
basename = "godot" + env["PROGSUFFIX"]
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index cd3974669f..9633472cd2 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -30,29 +30,19 @@
#include "audio_driver_javascript.h"
#include <emscripten.h>
-#include <string.h>
-
-#define MAX_NUMBER_INTERFACES 3
-#define MAX_NUMBER_OUTPUT_DEVICES 6
-
-/* Structure for passing information to callback function */
-
-//AudioDriverJavaScript* AudioDriverJavaScript::s_ad=NULL;
AudioDriverJavaScript *AudioDriverJavaScript::singleton_js = NULL;
+
const char *AudioDriverJavaScript::get_name() const {
return "JavaScript";
}
-extern "C" {
-
-void js_audio_driver_mix_function(int p_frames) {
+extern "C" EMSCRIPTEN_KEEPALIVE void js_audio_driver_mix_function(int p_frames) {
//print_line("MIXI! "+itos(p_frames));
AudioDriverJavaScript::singleton_js->mix_to_js(p_frames);
}
-}
void AudioDriverJavaScript::mix_to_js(int p_frames) {
@@ -65,11 +55,11 @@ void AudioDriverJavaScript::mix_to_js(int p_frames) {
audio_server_process(p_frames, stream_buffer);
for (int i = 0; i < tomix * internal_buffer_channels; i++) {
- internal_buffer[i] = float(stream_buffer[i] >> 16) * 32768.0;
+ internal_buffer[i] = float(stream_buffer[i] >> 16) / 32768.0;
}
/* clang-format off */
- EM_ASM_({
+ EM_ASM_ARGS({
var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2);
for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) {
@@ -95,29 +85,24 @@ Error AudioDriverJavaScript::init() {
void AudioDriverJavaScript::start() {
- internal_buffer_channels = 2;
internal_buffer = memnew_arr(float, INTERNAL_BUFFER_SIZE *internal_buffer_channels);
stream_buffer = memnew_arr(int32_t, INTERNAL_BUFFER_SIZE * 4); //max 4 channels
/* clang-format off */
- EM_ASM(
- _as_audioctx = new (window.AudioContext || window.webkitAudioContext)();
-
- audio_server_mix_function = Module.cwrap('js_audio_driver_mix_function', 'void', ['number']);
- );
-
- int buffer_latency = 16384;
- EM_ASM_( {
- _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2);
+ mix_rate = EM_ASM_INT({
+ _as_audioctx = new (window.AudioContext || window.webkitAudioContext);
+ _as_script_node = _as_audioctx.createScriptProcessor($0, 0, $1);
_as_script_node.connect(_as_audioctx.destination);
console.log(_as_script_node.bufferSize);
+ var jsAudioDriverMixFunction = cwrap('js_audio_driver_mix_function', null, ['number']);
_as_script_node.onaudioprocess = function(audioProcessingEvent) {
- // The output buffer contains the samples that will be modified and played
+ // The output buffer contains the samples that will be modified and played
_as_output_buffer = audioProcessingEvent.outputBuffer;
- audio_server_mix_function(_as_output_buffer.getChannelData(0).length);
- }
- }, buffer_latency);
+ jsAudioDriverMixFunction([_as_output_buffer.getChannelData(0).length]);
+ };
+ return _as_audioctx.sampleRate;
+ }, INTERNAL_BUFFER_SIZE, internal_buffer_channels);
/* clang-format on */
}
@@ -152,6 +137,7 @@ void AudioDriverJavaScript::finish() {
AudioDriverJavaScript::AudioDriverJavaScript() {
- mix_rate = 44100;
+ internal_buffer_channels = 2;
+ mix_rate = DEFAULT_MIX_RATE;
singleton_js = this;
}
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index c3adeca07b..b265c4e030 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -32,20 +32,15 @@
#include "servers/audio_server.h"
-#include "os/mutex.h"
-
class AudioDriverJavaScript : public AudioDriver {
enum {
INTERNAL_BUFFER_SIZE = 4096,
- STREAM_SCALE_BITS = 12
-
};
int mix_rate;
float *internal_buffer;
int internal_buffer_channels;
- int internal_buffer_size;
int32_t *stream_buffer;
public:
diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp
deleted file mode 100644
index ab9f66ce5b..0000000000
--- a/platform/javascript/audio_server_javascript.cpp
+++ /dev/null
@@ -1,853 +0,0 @@
-/*************************************************************************/
-/* audio_server_javascript.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 "audio_server_javascript.h"
-
-// FIXME: Needs to be ported to the new AudioServer API in 3.0
-#if 0
-#include "emscripten.h"
-
-AudioMixer *AudioServerJavascript::get_mixer() {
-
- return NULL;
-}
-
-void AudioServerJavascript::audio_mixer_chunk_callback(int p_frames){
-
-
-}
-
-
-RID AudioServerJavascript::sample_create(SampleFormat p_format, bool p_stereo, int p_length) {
-
- Sample *sample = memnew( Sample );
- sample->format=p_format;
- sample->stereo=p_stereo;
- sample->length=p_length;
- sample->loop_begin=0;
- sample->loop_end=p_length;
- sample->loop_format=SAMPLE_LOOP_NONE;
- sample->mix_rate=44100;
- sample->index=-1;
-
- return sample_owner.make_rid(sample);
-
-}
-
-void AudioServerJavascript::sample_set_description(RID p_sample, const String& p_description){
-
-
-}
-String AudioServerJavascript::sample_get_description(RID p_sample) const{
-
- return String();
-}
-
-AudioServerJavascript::SampleFormat AudioServerJavascript::sample_get_format(RID p_sample) const{
-
- return SAMPLE_FORMAT_PCM8;
-}
-bool AudioServerJavascript::sample_is_stereo(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,false);
- return sample->stereo;
-
-}
-int AudioServerJavascript::sample_get_length(RID p_sample) const{
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->length;
-}
-const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{
-
- return NULL;
-}
-
-void AudioServerJavascript::sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- int chans = sample->stereo?2:1;
-
- Vector<float> buffer;
- buffer.resize(sample->length*chans);
- PoolVector<uint8_t>::Read r=p_buffer.read();
- if (sample->format==SAMPLE_FORMAT_PCM8) {
- const int8_t*ptr = (const int8_t*)r.ptr();
- for(int i=0;i<sample->length*chans;i++) {
- buffer[i]=ptr[i]/128.0;
- }
- } else if (sample->format==SAMPLE_FORMAT_PCM16){
- const int16_t*ptr = (const int16_t*)r.ptr();
- for(int i=0;i<sample->length*chans;i++) {
- buffer[i]=ptr[i]/32768.0;
- }
- } else {
- ERR_EXPLAIN("Unsupported for now");
- ERR_FAIL();
- }
-
- sample->tmp_data=buffer;
-
-
-
-}
-PoolVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{
-
-
- return PoolVector<uint8_t>();
-}
-
-void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->mix_rate=p_rate;
-
-}
-
-int AudioServerJavascript::sample_get_mix_rate(RID p_sample) const{
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->mix_rate;
-}
-
-
-void AudioServerJavascript::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_format=p_format;
-
-}
-
-AudioServerJavascript::SampleLoopFormat AudioServerJavascript::sample_get_loop_format(RID p_sample) const {
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,SAMPLE_LOOP_NONE);
- return sample->loop_format;
-}
-
-void AudioServerJavascript::sample_set_loop_begin(RID p_sample,int p_pos){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_begin=p_pos;
-
-}
-int AudioServerJavascript::sample_get_loop_begin(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->loop_begin;
-}
-
-void AudioServerJavascript::sample_set_loop_end(RID p_sample,int p_pos){
-
- Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
- sample->loop_end=p_pos;
-
-}
-int AudioServerJavascript::sample_get_loop_end(RID p_sample) const{
-
- const Sample *sample = sample_owner.get(p_sample);
- ERR_FAIL_COND_V(!sample,0);
- return sample->loop_end;
-}
-
-
-/* VOICE API */
-
-RID AudioServerJavascript::voice_create(){
-
- Voice *voice = memnew( Voice );
-
- voice->index=voice_base;
- voice->volume=1.0;
- voice->pan=0.0;
- voice->pan_depth=.0;
- voice->pan_height=0.0;
- voice->chorus=0;
- voice->reverb_type=REVERB_SMALL;
- voice->reverb=0;
- voice->mix_rate=-1;
- voice->positional=false;
- voice->active=false;
-
- /* clang-format off */
- EM_ASM_( {
- _as_voices[$0] = null;
- _as_voice_gain[$0] = _as_audioctx.createGain();
- _as_voice_pan[$0] = _as_audioctx.createStereoPanner();
- _as_voice_gain[$0].connect(_as_voice_pan[$0]);
- _as_voice_pan[$0].connect(_as_audioctx.destination);
- }, voice_base);
- /* clang-format on */
-
- voice_base++;
-
- return voice_owner.make_rid( voice );
-}
-
-void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
- Sample *sample=sample_owner.get(p_sample);
- ERR_FAIL_COND(!sample);
-
- // due to how webaudio works, sample cration is deferred until used
- // sorry! WebAudio absolutely sucks
-
-
- if (sample->index==-1) {
- //create sample if not created
- ERR_FAIL_COND(sample->tmp_data.size()==0);
- sample->index=sample_base;
- /* clang-format off */
- EM_ASM_({
- _as_samples[$0] = _as_audioctx.createBuffer($1, $2, $3);
- }, sample_base, sample->stereo ? 2 : 1, sample->length, sample->mix_rate);
- /* clang-format on */
-
- sample_base++;
- int chans = sample->stereo?2:1;
-
-
- for(int i=0;i<chans;i++) {
- /* clang-format off */
- EM_ASM_({
- _as_edited_buffer = _as_samples[$0].getChannelData($1);
- }, sample->index, i);
- /* clang-format on */
-
- for(int j=0;j<sample->length;j++) {
- /* clang-format off */
- EM_ASM_({
- _as_edited_buffer[$0] = $1;
- }, j, sample->tmp_data[j * chans + i]);
- /* clang-format on */
- }
- }
-
- sample->tmp_data.clear();
- }
-
-
- voice->sample_mix_rate=sample->mix_rate;
- if (voice->mix_rate==-1) {
- voice->mix_rate=voice->sample_mix_rate;
- }
-
- float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
- int detune = int(freq_diff*1200.0);
-
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop(); //stop and byebye
- }
- _as_voices[$0] = _as_audioctx.createBufferSource();
- _as_voices[$0].connect(_as_voice_gain[$0]);
- _as_voices[$0].buffer = _as_samples[$1];
- _as_voices[$0].loopStart.value = $1;
- _as_voices[$0].loopEnd.value = $2;
- _as_voices[$0].loop.value = $3;
- _as_voices[$0].detune.value = $6;
- _as_voice_pan[$0].pan.value = $4;
- _as_voice_gain[$0].gain.value = $5;
- _as_voices[$0].start();
- _as_voices[$0].onended = function() {
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- _as_voices[$0] = null;
- }
- }, voice->index, sample->index, sample->mix_rate * sample->loop_begin, sample->mix_rate * sample->loop_end, sample->loop_format != SAMPLE_LOOP_NONE, voice->pan, voice->volume * fx_volume_scale, detune);
- /* clang-format on */
-
- voice->active=true;
-}
-
-void AudioServerJavascript::voice_set_volume(RID p_voice, float p_volume){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->volume=p_volume;
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- _as_voice_gain[$0].gain.value = $1;
- }, voice->index, voice->volume * fx_volume_scale);
- /* clang-format on */
- }
-
-}
-void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_depth,float height){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->pan=p_pan;
- voice->pan_depth=p_depth;
- voice->pan_height=height;
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- _as_voice_pan[$0].pan.value = $1;
- }, voice->index, voice->pan);
- /* clang-format on */
- }
-}
-void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){
-
-}
-void AudioServerJavascript::voice_set_chorus(RID p_voice, float p_chorus ){
-
-}
-void AudioServerJavascript::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb){
-
-}
-void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- voice->mix_rate=p_mix_rate;
-
- if (voice->active) {
-
- float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
- int detune = int(freq_diff*1200.0);
- /* clang-format off */
- EM_ASM_({
- _as_voices[$0].detune.value = $1;
- }, voice->index, detune);
- /* clang-format on */
- }
-}
-void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){
-
-}
-
-float AudioServerJavascript::voice_get_volume(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->volume;
-}
-float AudioServerJavascript::voice_get_pan(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan;
-}
-float AudioServerJavascript::voice_get_pan_depth(RID p_voice) const{
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan_depth;
-}
-float AudioServerJavascript::voice_get_pan_height(RID p_voice) const{
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,0);
-
- return voice->pan_height;
-}
-AudioServerJavascript::FilterType AudioServerJavascript::voice_get_filter_type(RID p_voice) const{
-
- return FILTER_NONE;
-}
-float AudioServerJavascript::voice_get_filter_cutoff(RID p_voice) const{
-
- return 0;
-}
-float AudioServerJavascript::voice_get_filter_resonance(RID p_voice) const{
-
- return 0;
-}
-float AudioServerJavascript::voice_get_chorus(RID p_voice) const{
-
- return 0;
-}
-AudioServerJavascript::ReverbRoomType AudioServerJavascript::voice_get_reverb_type(RID p_voice) const{
-
- return REVERB_SMALL;
-}
-float AudioServerJavascript::voice_get_reverb(RID p_voice) const{
-
- return 0;
-}
-
-int AudioServerJavascript::voice_get_mix_rate(RID p_voice) const{
-
- return 44100;
-}
-
-bool AudioServerJavascript::voice_is_positional(RID p_voice) const{
-
- return false;
-}
-
-void AudioServerJavascript::voice_stop(RID p_voice){
-
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND(!voice);
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop();
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- _as_voices[$0] = null;
- }
- }, voice->index);
- /* clang-format on */
-
- voice->active=false;
- }
-
-
-}
-bool AudioServerJavascript::voice_is_active(RID p_voice) const{
- Voice* voice=voice_owner.get(p_voice);
- ERR_FAIL_COND_V(!voice,false);
-
- return voice->active;
-}
-
-/* STREAM API */
-
-RID AudioServerJavascript::audio_stream_create(AudioStream *p_stream) {
-
-
- Stream *s = memnew(Stream);
- s->audio_stream=p_stream;
- s->event_stream=NULL;
- s->active=false;
- s->E=NULL;
- s->volume_scale=1.0;
- p_stream->set_mix_rate(webaudio_mix_rate);
-
- return stream_owner.make_rid(s);
-}
-
-RID AudioServerJavascript::event_stream_create(EventStream *p_stream) {
-
-
- Stream *s = memnew(Stream);
- s->audio_stream=NULL;
- s->event_stream=p_stream;
- s->active=false;
- s->E=NULL;
- s->volume_scale=1.0;
- //p_stream->set_mix_rate(AudioDriverJavascript::get_singleton()->get_mix_rate());
-
- return stream_owner.make_rid(s);
-
-
-}
-
-
-void AudioServerJavascript::stream_set_active(RID p_stream, bool p_active) {
-
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND(!s);
-
- if (s->active==p_active)
- return;
-
- s->active=p_active;
- if (p_active)
- s->E=active_audio_streams.push_back(s);
- else {
- active_audio_streams.erase(s->E);
- s->E=NULL;
- }
-}
-
-bool AudioServerJavascript::stream_is_active(RID p_stream) const {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND_V(!s,false);
- return s->active;
-}
-
-void AudioServerJavascript::stream_set_volume_scale(RID p_stream, float p_scale) {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND(!s);
- s->volume_scale=p_scale;
-
-}
-
-float AudioServerJavascript::stream_set_volume_scale(RID p_stream) const {
-
- Stream *s = stream_owner.get(p_stream);
- ERR_FAIL_COND_V(!s,0);
- return s->volume_scale;
-
-}
-
-
-/* Audio Physics API */
-
-void AudioServerJavascript::free(RID p_id){
-
- if (voice_owner.owns(p_id)) {
- Voice* voice=voice_owner.get(p_id);
- ERR_FAIL_COND(!voice);
-
- if (voice->active) {
- /* clang-format off */
- EM_ASM_({
- if (_as_voices[$0] !== null) {
- _as_voices[$0].stop();
- _as_voices[$0].disconnect(_as_voice_gain[$0]);
- }
- }, voice->index);
- /* clang-format on */
- }
-
- /* clang-format off */
- EM_ASM_({
- delete _as_voices[$0];
- _as_voice_gain[$0].disconnect(_as_voice_pan[$0]);
- delete _as_voice_gain[$0];
- _as_voice_pan[$0].disconnect(_as_audioctx.destination);
- delete _as_voice_pan[$0];
- }, voice->index);
- /* clang-format on */
-
- voice_owner.free(p_id);
- memdelete(voice);
-
- } else if (sample_owner.owns(p_id)) {
-
- Sample *sample = sample_owner.get(p_id);
- ERR_FAIL_COND(!sample);
-
- /* clang-format off */
- EM_ASM_({
- delete _as_samples[$0];
- }, sample->index);
- /* clang-format on */
-
- sample_owner.free(p_id);
- memdelete(sample);
-
- } else if (stream_owner.owns(p_id)) {
-
-
- Stream *s=stream_owner.get(p_id);
-
- if (s->active) {
- stream_set_active(p_id,false);
- }
-
- memdelete(s);
- stream_owner.free(p_id);
- }
-}
-
-extern "C" {
-
-
-void audio_server_mix_function(int p_frames) {
-
- //print_line("MIXI! "+itos(p_frames));
- static_cast<AudioServerJavascript*>(AudioServerJavascript::get_singleton())->mix_to_js(p_frames);
-}
-
-}
-
-void AudioServerJavascript::mix_to_js(int p_frames) {
-
-
- //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
- int todo=p_frames;
- int offset=0;
-
- while(todo) {
-
- int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
- driver_process_chunk(tomix);
-
- /* clang-format off */
- EM_ASM_({
- var data = HEAPF32.subarray($0 / 4, $0 / 4 + $2 * 2);
-
- for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) {
- var outputData = _as_output_buffer.getChannelData(channel);
- // Loop through samples
- for (var sample = 0; sample < $2; sample++) {
- // make output equal to the same as the input
- outputData[sample + $1] = data[sample * 2 + channel];
- }
- }
- }, internal_buffer, offset, tomix);
- /* clang-format on */
-
- todo-=tomix;
- offset+=tomix;
- }
-}
-
-void AudioServerJavascript::init(){
-
- /*
- // clang-format off
- EM_ASM(
- console.log('server is ' + audio_server);
- );
- // clang-format on
- */
-
-
- //int latency = GLOBAL_DEF("javascript/audio_latency",16384);
-
- internal_buffer_channels=2;
- internal_buffer = memnew_arr(float,INTERNAL_BUFFER_SIZE*internal_buffer_channels);
- stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels
-
- stream_volume=0.3;
-
- int buffer_latency=16384;
-
- /* clang-format off */
- EM_ASM_( {
- _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2);
- _as_script_node.connect(_as_audioctx.destination);
- console.log(_as_script_node.bufferSize);
-
- _as_script_node.onaudioprocess = function(audioProcessingEvent) {
- // The output buffer contains the samples that will be modified and played
- _as_output_buffer = audioProcessingEvent.outputBuffer;
- audio_server_mix_function(_as_output_buffer.getChannelData(0).length);
- }
- }, buffer_latency);
- /* clang-format on */
-
-
-}
-
-void AudioServerJavascript::finish(){
-
-}
-void AudioServerJavascript::update(){
-
- for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
-
- List<Stream*>::Element *N=E->next();
-
- if (E->get()->audio_stream)
- E->get()->audio_stream->update();
-
- E=N;
- }
-}
-
-/* MISC config */
-
-void AudioServerJavascript::lock(){
-
-}
-void AudioServerJavascript::unlock(){
-
-}
-int AudioServerJavascript::get_default_channel_count() const{
-
- return 1;
-}
-int AudioServerJavascript::get_default_mix_rate() const{
-
- return 44100;
-}
-
-void AudioServerJavascript::set_stream_global_volume_scale(float p_volume){
-
- stream_volume_scale=p_volume;
-}
-void AudioServerJavascript::set_fx_global_volume_scale(float p_volume){
-
- fx_volume_scale=p_volume;
-}
-void AudioServerJavascript::set_event_voice_global_volume_scale(float p_volume){
-
-}
-
-float AudioServerJavascript::get_stream_global_volume_scale() const{
- return 1;
-}
-float AudioServerJavascript::get_fx_global_volume_scale() const{
-
- return 1;
-}
-float AudioServerJavascript::get_event_voice_global_volume_scale() const{
-
- return 1;
-}
-
-uint32_t AudioServerJavascript::read_output_peak() const{
-
- return 0;
-}
-
-AudioServerJavascript *AudioServerJavascript::singleton=NULL;
-
-AudioServer *AudioServerJavascript::get_singleton() {
- return singleton;
-}
-
-double AudioServerJavascript::get_mix_time() const{
-
- return 0;
-}
-double AudioServerJavascript::get_output_delay() const {
-
- return 0;
-}
-
-
-void AudioServerJavascript::driver_process_chunk(int p_frames) {
-
-
-
- int samples=p_frames*internal_buffer_channels;
-
- for(int i=0;i<samples;i++) {
- internal_buffer[i]=0;
- }
-
-
- for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) {
-
- ERR_CONTINUE(!E->get()->active); // bug?
-
-
- AudioStream *as=E->get()->audio_stream;
- if (!as)
- continue;
-
- int channels=as->get_channel_count();
- if (channels==0)
- continue; // does not want mix
- if (!as->mix(stream_buffer,p_frames))
- continue; //nothing was mixed!!
-
- int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS);
-
-#define STRSCALE(m_val) ((((m_val >> STREAM_SCALE_BITS) * stream_vol_scale) >> 8) / 8388608.0)
- switch(channels) {
- case 1: {
-
- for(int i=0;i<p_frames;i++) {
-
- internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]);
- internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]);
- }
- } break;
- case 2: {
-
- for(int i=0;i<p_frames*2;i++) {
-
- internal_buffer[i]+=STRSCALE(stream_buffer[i]);
- }
- } break;
- case 4: {
-
- for(int i=0;i<p_frames;i++) {
-
- internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1);
- internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1);
- }
- } break;
-
-
- }
-
-#undef STRSCALE
- }
-}
-
-
-/*void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) {
-
-
- _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate());
- //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
- int todo=p_frames;
- while(todo) {
-
- int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
- driver_process_chunk(tomix,p_buffer);
- p_buffer+=tomix;
- todo-=tomix;
- }
-
-
-}*/
-
-AudioServerJavascript::AudioServerJavascript() {
-
- singleton=this;
- sample_base=1;
- voice_base=1;
- /* clang-format off */
- EM_ASM(
- _as_samples = {};
- _as_voices = {};
- _as_voice_pan = {};
- _as_voice_gain = {};
-
- _as_audioctx = new (window.AudioContext || window.webkitAudioContext)();
-
- audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']);
- );
- /* clang-format on */
-
- /* clang-format off */
- webaudio_mix_rate = EM_ASM_INT_V(
- return _as_audioctx.sampleRate;
- );
- /* clang-format on */
- print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate));
- event_voice_scale=1.0;
- fx_volume_scale=1.0;
- stream_volume_scale=1.0;
-
-}
-#endif
diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h
deleted file mode 100644
index 0773459f56..0000000000
--- a/platform/javascript/audio_server_javascript.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/*************************************************************************/
-/* audio_server_javascript.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 AUDIO_SERVER_JAVASCRIPT_H
-#define AUDIO_SERVER_JAVASCRIPT_H
-
-// FIXME: Needs to be ported to the new AudioServer API in 3.0
-#if 0
-#include "servers/audio_server.h"
-
-class AudioServerJavascript : public AudioServer {
-
- GDCLASS(AudioServerJavascript,AudioServer);
-
- enum {
- INTERNAL_BUFFER_SIZE=4096,
- STREAM_SCALE_BITS=12
-
- };
-
- AudioMixer *get_mixer();
- void audio_mixer_chunk_callback(int p_frames);
-
- struct Sample {
- SampleFormat format;
- SampleLoopFormat loop_format;
- int loop_begin;
- int loop_end;
- int length;
- int index;
- int mix_rate;
- bool stereo;
-
- Vector<float> tmp_data;
- };
-
- mutable RID_Owner<Sample> sample_owner;
- int sample_base;
-
- struct Voice {
- int index;
- float volume;
- float pan;
- float pan_depth;
- float pan_height;
-
- float chorus;
- ReverbRoomType reverb_type;
- float reverb;
-
- int mix_rate;
- int sample_mix_rate;
- bool positional;
-
- bool active;
-
- };
-
- mutable RID_Owner<Voice> voice_owner;
-
- int voice_base;
-
- struct Stream {
- bool active;
- List<Stream*>::Element *E;
- AudioStream *audio_stream;
- EventStream *event_stream;
- float volume_scale;
- };
-
- List<Stream*> active_audio_streams;
-
- //List<Stream*> event_streams;
-
- float * internal_buffer;
- int internal_buffer_channels;
- int32_t * stream_buffer;
-
- mutable RID_Owner<Stream> stream_owner;
-
- float stream_volume;
- float stream_volume_scale;
-
- float event_voice_scale;
- float fx_volume_scale;
-
-
- void driver_process_chunk(int p_frames);
-
- int webaudio_mix_rate;
-
-
- static AudioServerJavascript *singleton;
-public:
-
- void mix_to_js(int p_frames);
- /* SAMPLE API */
-
- virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length);
-
- virtual void sample_set_description(RID p_sample, const String& p_description);
- virtual String sample_get_description(RID p_sample) const;
-
- virtual SampleFormat sample_get_format(RID p_sample) const;
- virtual bool sample_is_stereo(RID p_sample) const;
- virtual int sample_get_length(RID p_sample) const;
- virtual const void* sample_get_data_ptr(RID p_sample) const;
-
-
- virtual void sample_set_data(RID p_sample, const PoolVector<uint8_t>& p_buffer);
- virtual PoolVector<uint8_t> sample_get_data(RID p_sample) const;
-
- virtual void sample_set_mix_rate(RID p_sample,int p_rate);
- virtual int sample_get_mix_rate(RID p_sample) const;
-
- virtual void sample_set_loop_format(RID p_sample,SampleLoopFormat p_format);
- virtual SampleLoopFormat sample_get_loop_format(RID p_sample) const;
-
- virtual void sample_set_loop_begin(RID p_sample,int p_pos);
- virtual int sample_get_loop_begin(RID p_sample) const;
-
- virtual void sample_set_loop_end(RID p_sample,int p_pos);
- virtual int sample_get_loop_end(RID p_sample) const;
-
-
- /* VOICE API */
-
- virtual RID voice_create();
-
- virtual void voice_play(RID p_voice, RID p_sample);
-
- virtual void voice_set_volume(RID p_voice, float p_volume);
- virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1
- virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0);
- virtual void voice_set_chorus(RID p_voice, float p_chorus );
- virtual void voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb);
- virtual void voice_set_mix_rate(RID p_voice, int p_mix_rate);
- virtual void voice_set_positional(RID p_voice, bool p_positional);
-
- virtual float voice_get_volume(RID p_voice) const;
- virtual float voice_get_pan(RID p_voice) const; //pan and depth go from -1 to 1
- virtual float voice_get_pan_depth(RID p_voice) const; //pan and depth go from -1 to 1
- virtual float voice_get_pan_height(RID p_voice) const; //pan and depth go from -1 to 1
- virtual FilterType voice_get_filter_type(RID p_voice) const;
- virtual float voice_get_filter_cutoff(RID p_voice) const;
- virtual float voice_get_filter_resonance(RID p_voice) const;
- virtual float voice_get_chorus(RID p_voice) const;
- virtual ReverbRoomType voice_get_reverb_type(RID p_voice) const;
- virtual float voice_get_reverb(RID p_voice) const;
-
- virtual int voice_get_mix_rate(RID p_voice) const;
- virtual bool voice_is_positional(RID p_voice) const;
-
- virtual void voice_stop(RID p_voice);
- virtual bool voice_is_active(RID p_voice) const;
-
- /* STREAM API */
-
- virtual RID audio_stream_create(AudioStream *p_stream);
- virtual RID event_stream_create(EventStream *p_stream);
-
- virtual void stream_set_active(RID p_stream, bool p_active);
- virtual bool stream_is_active(RID p_stream) const;
-
- virtual void stream_set_volume_scale(RID p_stream, float p_scale);
- virtual float stream_set_volume_scale(RID p_stream) const;
-
- /* Audio Physics API */
-
- virtual void free(RID p_id);
-
- virtual void init();
- virtual void finish();
- virtual void update();
-
- /* MISC config */
-
- virtual void lock();
- virtual void unlock();
- virtual int get_default_channel_count() const;
- virtual int get_default_mix_rate() const;
-
- virtual void set_stream_global_volume_scale(float p_volume);
- virtual void set_fx_global_volume_scale(float p_volume);
- virtual void set_event_voice_global_volume_scale(float p_volume);
-
- virtual float get_stream_global_volume_scale() const;
- virtual float get_fx_global_volume_scale() const;
- virtual float get_event_voice_global_volume_scale() const;
-
- virtual uint32_t read_output_peak() const;
-
- static AudioServer *get_singleton();
-
- virtual double get_mix_time() const; //useful for video -> audio sync
- virtual double get_output_delay() const;
-
-
- AudioServerJavascript();
-};
-
-#endif // AUDIO_SERVER_JAVASCRIPT_H
-#endif
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 3a57de2646..e5bdcec30d 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -64,11 +64,6 @@ const char *OS_JavaScript::get_video_driver_name(int p_driver) const {
return "GLES3";
}
-OS::VideoMode OS_JavaScript::get_default_video_mode() const {
-
- return OS::VideoMode();
-}
-
int OS_JavaScript::get_audio_driver_count() const {
return 1;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 908a252905..f478f95dd2 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -31,7 +31,6 @@
#define OS_JAVASCRIPT_H
#include "audio_driver_javascript.h"
-#include "audio_server_javascript.h"
#include "drivers/unix/os_unix.h"
#include "javascript_eval.h"
#include "main/input_default.h"
@@ -84,8 +83,6 @@ public:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index fba53f61b6..53f45511f9 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -120,7 +120,6 @@ public:
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual void initialize_logger();
virtual void initialize_core();
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 80c04aa5ad..ca73f610e4 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -46,10 +46,6 @@ const char *OS_Server::get_video_driver_name(int p_driver) const {
return "Dummy";
}
-OS::VideoMode OS_Server::get_default_video_mode() const {
-
- return OS::VideoMode(800, 600, false);
-}
void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 630c82ccdd..03f7c2a6c8 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -66,7 +66,6 @@ class OS_Server : public OS_Unix {
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
diff --git a/platform/uwp/detect.py b/platform/uwp/detect.py
index af53f97446..434c597449 100644
--- a/platform/uwp/detect.py
+++ b/platform/uwp/detect.py
@@ -84,7 +84,7 @@ def configure(env):
## Architecture
arch = ""
- if os.getenv('Platform') == "ARM":
+ if str(os.getenv('Platform')).lower() == "arm":
print("Compiled program architecture will be an ARM executable. (forcing bits=32).")
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 8db2a749df..acb0ba4bca 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -72,11 +72,6 @@ const char *OSUWP::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-OS::VideoMode OSUWP::get_default_video_mode() const {
-
- return video_mode;
-}
-
Size2 OSUWP::get_window_size() const {
Size2 size;
size.width = video_mode.width;
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index e46e4cc020..2931e9b07d 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -154,8 +154,6 @@ protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 01201beccb..0f62dbb9e8 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -146,11 +146,6 @@ const char *OS_Windows::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-OS::VideoMode OS_Windows::get_default_video_mode() const {
-
- return VideoMode(1024, 600, false);
-}
-
int OS_Windows::get_audio_driver_count() const {
return AudioDriverManager::get_driver_count();
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c9c00b5e36..fbd60e5f0d 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -142,8 +142,6 @@ protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
-
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index fbcc22c58e..f018145d82 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -82,10 +82,6 @@ const char *OS_X11::get_video_driver_name(int p_driver) const {
return "GLES3";
}
-OS::VideoMode OS_X11::get_default_video_mode() const {
- return OS::VideoMode(1024, 600, false);
-}
-
int OS_X11::get_audio_driver_count() const {
return AudioDriverManager::get_driver_count();
}
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index bfa8b5b375..0ea5bbfdb6 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -177,7 +177,6 @@ class OS_X11 : public OS_Unix {
protected:
virtual int get_video_driver_count() const;
virtual const char *get_video_driver_name(int p_driver) const;
- virtual VideoMode get_default_video_mode() const;
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 4e19214c59..040266843d 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -642,7 +642,7 @@ void ParticlesMaterial::_update_shader() {
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 += " VELOCITY = (rot*initial_linear_velocity+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\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
@@ -650,7 +650,7 @@ void ParticlesMaterial::_update_shader() {
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+rot*initial_linear_velocity_random*rand_from_seed(alt_seed));\n";
+ code += " VELOCITY = rot*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";
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 65a8350bd3..798acb9d52 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -526,6 +526,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor);
} else if (p_mode == PROCESS_POINTER) {
_process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, p_click_pos, r_click_item, r_click_char, r_outside);
+ if (r_click_item && *r_click_item) {
+ RETURN; // exit early
+ }
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index ee7762b668..7d200a799b 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -376,24 +376,116 @@ void TextEdit::_update_scrollbars() {
void TextEdit::_click_selection_held() {
if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) {
+ switch (selection.selecting_mode) {
+ case Selection::MODE_POINTER: {
+ _update_selection_mode_pointer();
+ } break;
+ case Selection::MODE_WORD: {
+ _update_selection_mode_word();
+ } break;
+ case Selection::MODE_LINE: {
+ _update_selection_mode_line();
+ } break;
+ default: {
+ break;
+ }
+ }
+ } else {
+ click_select_held->stop();
+ }
+}
- Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+void TextEdit::_update_selection_mode_pointer() {
+ Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
- int row, col;
- _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+ int row, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
- select(selection.selecting_line, selection.selecting_column, row, col);
+ select(selection.selecting_line, selection.selecting_column, row, col);
- cursor_set_line(row);
- cursor_set_column(col);
- update();
+ cursor_set_line(row);
+ cursor_set_column(col);
+ update();
+
+ click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_word() {
+ Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+
+ int row, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
- click_select_held->start();
+ String line = text[row];
+ int beg = CLAMP(col, 0, line.length());
+ // if its the first selection and on whitespace make sure we grab the word instead..
+ if (!selection.active) {
+ while (beg > 0 && line[beg] <= 32) {
+ beg--;
+ }
+ }
+ int end = beg;
+ bool symbol = beg < line.length() && _is_symbol(line[beg]);
+
+ // get the word end and begin points
+ while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) {
+ beg--;
+ }
+ while (end < line.length() && line[end + 1] > 32 && (symbol == _is_symbol(line[end + 1]))) {
+ end++;
+ }
+ if (end < line.length()) {
+ end += 1;
+ }
+ // inital selection
+ if (!selection.active) {
+ select(row, beg, row, end);
+ selection.selecting_column = beg;
+ selection.selected_word_beg = beg;
+ selection.selected_word_end = end;
+ selection.selected_word_origin = beg;
+ cursor_set_column(selection.to_column);
} else {
+ if ((col <= selection.selected_word_origin && row == selection.selecting_line) || row < selection.selecting_line) {
+ selection.selecting_column = selection.selected_word_end;
+ select(row, beg, selection.selecting_line, selection.selected_word_end);
+ cursor_set_column(selection.from_column);
+ } else {
+ selection.selecting_column = selection.selected_word_beg;
+ select(selection.selecting_line, selection.selected_word_beg, row, end);
+ cursor_set_column(selection.to_column);
+ }
+ }
+ cursor_set_line(row);
- click_select_held->stop();
+ update();
+ click_select_held->start();
+}
+
+void TextEdit::_update_selection_mode_line() {
+ Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position();
+
+ int row, col;
+ _get_mouse_pos(Point2i(mp.x, mp.y), row, col);
+
+ col = 0;
+ if (row < selection.selecting_line) {
+ // cursor is above us
+ cursor_set_line(row - 1);
+ selection.selecting_column = text[selection.selecting_line].length();
+ } else {
+ // cursor is below us
+ cursor_set_line(row + 1);
+ selection.selecting_column = 0;
+ col = text[row].length();
}
+ cursor_set_column(0);
+
+ select(selection.selecting_line, selection.selecting_column, row, col);
+ update();
+
+ click_select_held->start();
}
void TextEdit::_notification(int p_what) {
@@ -1759,36 +1851,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
//tripleclick select line
- select(cursor.line, 0, cursor.line, text[cursor.line].length());
- selection.selecting_column = 0;
+ selection.selecting_mode = Selection::MODE_LINE;
+ _update_selection_mode_line();
last_dblclk = 0;
} else if (mb->is_doubleclick() && text[cursor.line].length()) {
//doubleclick select world
- String s = text[cursor.line];
- int beg = CLAMP(cursor.column, 0, s.length());
- int end = beg;
-
- if (s[beg] > 32 || beg == s.length()) {
-
- bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
-
- while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) {
- beg--;
- }
- while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) {
- end++;
- }
-
- if (end < s.length())
- end += 1;
-
- select(cursor.line, beg, cursor.line, end);
-
- selection.selecting_column = beg;
- }
-
+ selection.selecting_mode = Selection::MODE_WORD;
+ _update_selection_mode_word();
last_dblclk = OS::get_singleton()->get_ticks_msec();
}
@@ -1833,21 +1904,21 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { //ignore if dragging
+ _reset_caret_blink_timer();
- if (selection.selecting_mode != Selection::MODE_NONE) {
-
- _reset_caret_blink_timer();
-
- int row, col;
- _get_mouse_pos(mm->get_position(), row, col);
-
- select(selection.selecting_line, selection.selecting_column, row, col);
-
- cursor_set_line(row);
- cursor_set_column(col);
- update();
-
- click_select_held->start();
+ switch (selection.selecting_mode) {
+ case Selection::MODE_POINTER: {
+ _update_selection_mode_pointer();
+ } break;
+ case Selection::MODE_WORD: {
+ _update_selection_mode_word();
+ } break;
+ case Selection::MODE_LINE: {
+ _update_selection_mode_line();
+ } break;
+ default: {
+ break;
+ }
}
}
}
@@ -2847,19 +2918,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (scancode_handled)
accept_event();
/*
- if (!scancode_handled && !k->get_command() && !k->get_alt()) {
+ if (!scancode_handled && !k->get_command() && !k->get_alt()) {
if (k->get_unicode()>=32) {
- if (readonly)
+ if (readonly)
break;
- accept_event();
+ accept_event();
} else {
- break;
+ break;
+ }
}
- }
*/
if (k->get_scancode() == KEY_INSERT) {
set_insert_mode(!insert_mode);
@@ -3251,11 +3322,11 @@ void TextEdit::adjust_viewport_to_cursor() {
update();
/*
- get_range()->set_max(text.size());
+ get_range()->set_max(text.size());
- get_range()->set_page(get_visible_rows());
+ get_range()->set_page(get_visible_rows());
- get_range()->set((int)cursor.line_ofs);
+ get_range()->set((int)cursor.line_ofs);
*/
}
@@ -4815,8 +4886,8 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(SEARCH_BACKWARDS);
/*
- ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char);
- ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line);
+ ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char);
+ ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line);
*/
ClassDB::bind_method(D_METHOD("set_text", "text"), &TextEdit::set_text);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index b4b14d0139..81310b7c10 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -51,11 +51,14 @@ class TextEdit : public Control {
MODE_NONE,
MODE_SHIFT,
- MODE_POINTER
+ MODE_POINTER,
+ MODE_WORD,
+ MODE_LINE
};
Mode selecting_mode;
int selecting_line, selecting_column;
+ int selected_word_beg, selected_word_end, selected_word_origin;
bool selecting_text;
bool active;
@@ -305,6 +308,10 @@ class TextEdit : public Control {
void _v_scroll_input();
void _click_selection_held();
+ void _update_selection_mode_pointer();
+ void _update_selection_mode_word();
+ void _update_selection_mode_line();
+
void _pre_shift_selection();
void _post_shift_selection();
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 467f059fd3..162edd0d1c 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -866,6 +866,18 @@ Rect2 AtlasTexture::get_margin() const {
return margin;
}
+void AtlasTexture::set_filter_clip(const bool p_enable) {
+
+ filter_clip = p_enable;
+ emit_changed();
+ _change_notify("filter_clip");
+}
+
+bool AtlasTexture::has_filter_clip() const {
+
+ return filter_clip;
+}
+
void AtlasTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_atlas", "atlas"), &AtlasTexture::set_atlas);
@@ -877,9 +889,13 @@ void AtlasTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &AtlasTexture::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &AtlasTexture::get_margin);
+ ClassDB::bind_method(D_METHOD("set_filter_clip", "enable"), &AtlasTexture::set_filter_clip);
+ ClassDB::bind_method(D_METHOD("has_filter_clip"), &AtlasTexture::has_filter_clip);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "atlas", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_atlas", "get_atlas");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region"), "set_region", "get_region");
ADD_PROPERTY(PropertyInfo(Variant::RECT2, "margin"), "set_margin", "get_margin");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_clip"), "set_filter_clip", "has_filter_clip");
}
void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
@@ -898,7 +914,7 @@ void AtlasTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_m
}
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(p_pos + margin.position, rc.size), atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, filter_clip);
}
void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
@@ -920,7 +936,7 @@ void AtlasTexture::draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile
Rect2 dr(p_rect.position + margin.position * scale, rc.size * scale);
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), rc, p_modulate, p_transpose, normal_rid, filter_clip);
}
void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map, bool p_clip_uv) const {
@@ -951,7 +967,7 @@ void AtlasTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons
Rect2 dr(p_rect.position + ofs * scale, src_c.size * scale);
RID normal_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
- VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, p_clip_uv);
+ VS::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, dr, atlas->get_rid(), src_c, p_modulate, p_transpose, normal_rid, filter_clip);
}
bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect, Rect2 &r_rect, Rect2 &r_src_rect) const {
@@ -987,6 +1003,7 @@ bool AtlasTexture::get_rect_region(const Rect2 &p_rect, const Rect2 &p_src_rect,
}
AtlasTexture::AtlasTexture() {
+ filter_clip = false;
}
//////////////////////////////////////////
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 207436e4a7..ee54156647 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -237,6 +237,7 @@ protected:
Ref<Texture> atlas;
Rect2 region;
Rect2 margin;
+ bool filter_clip;
static void _bind_methods();
@@ -259,6 +260,9 @@ public:
void set_margin(const Rect2 &p_margin);
Rect2 get_margin() const;
+ void set_filter_clip(const bool p_enable);
+ bool has_filter_clip() const;
+
virtual void draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
virtual void draw_rect(RID p_canvas_item, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>()) const;
virtual void draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_clip_uv = true) const;
diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp
index a289b4b0ca..ef54eb58cf 100644
--- a/servers/physics/body_pair_sw.cpp
+++ b/servers/physics/body_pair_sw.cpp
@@ -46,6 +46,7 @@
//#define ALLOWED_PENETRATION 0.01
#define RELAXATION_TIMESTEPS 3
#define MIN_VELOCITY 0.0001
+#define MAX_BIAS_ROTATION (Math_PI / 8)
void BodyPairSW::_contact_added_callback(const Vector3 &p_point_A, const Vector3 &p_point_B, void *p_userdata) {
@@ -71,6 +72,7 @@ void BodyPairSW::contact_added_callback(const Vector3 &p_point_A, const Vector3
contact.acc_normal_impulse = 0;
contact.acc_bias_impulse = 0;
+ contact.acc_bias_impulse_center_of_mass = 0;
contact.acc_tangent_impulse = Vector3();
contact.local_A = local_A;
contact.local_B = local_B;
@@ -82,12 +84,12 @@ void BodyPairSW::contact_added_callback(const Vector3 &p_point_A, const Vector3
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
- if (
- c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
+ if (c.local_A.distance_squared_to(local_A) < (contact_recycle_radius * contact_recycle_radius) &&
c.local_B.distance_squared_to(local_B) < (contact_recycle_radius * contact_recycle_radius)) {
contact.acc_normal_impulse = c.acc_normal_impulse;
contact.acc_bias_impulse = c.acc_bias_impulse;
+ contact.acc_bias_impulse_center_of_mass = c.acc_bias_impulse_center_of_mass;
contact.acc_tangent_impulse = c.acc_tangent_impulse;
new_index = i;
break;
@@ -325,9 +327,7 @@ bool BodyPairSW::setup(real_t p_step) {
A->apply_impulse(c.rA + A->get_center_of_mass(), -j_vec);
B->apply_impulse(c.rB + B->get_center_of_mass(), j_vec);
c.acc_bias_impulse = 0;
- Vector3 jb_vec = c.normal * c.acc_bias_impulse;
- A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb_vec);
- B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb_vec);
+ c.acc_bias_impulse_center_of_mass = 0;
c.bounce = MAX(A->get_bounce(), B->get_bounce());
if (c.bounce) {
@@ -356,7 +356,7 @@ void BodyPairSW::solve(real_t p_step) {
c.active = false; //try to deactivate, will activate itself if still needed
- //bias impule
+ //bias impulse
Vector3 crbA = A->get_biased_angular_velocity().cross(c.rA);
Vector3 crbB = B->get_biased_angular_velocity().cross(c.rB);
@@ -372,8 +372,26 @@ void BodyPairSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb);
- B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb);
+ A->apply_bias_impulse(c.rA + A->get_center_of_mass(), -jb, MAX_BIAS_ROTATION / p_step);
+ B->apply_bias_impulse(c.rB + B->get_center_of_mass(), jb, MAX_BIAS_ROTATION / p_step);
+
+ crbA = A->get_biased_angular_velocity().cross(c.rA);
+ crbB = B->get_biased_angular_velocity().cross(c.rB);
+ dbv = B->get_biased_linear_velocity() + crbB - A->get_biased_linear_velocity() - crbA;
+
+ vbn = dbv.dot(c.normal);
+
+ if (Math::abs(-vbn + c.bias) > MIN_VELOCITY) {
+
+ real_t jbn_com = (-vbn + c.bias) / (A->get_inv_mass() + B->get_inv_mass());
+ real_t jbnOld_com = c.acc_bias_impulse_center_of_mass;
+ c.acc_bias_impulse_center_of_mass = MAX(jbnOld_com + jbn_com, 0.0f);
+
+ Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
+
+ A->apply_bias_impulse(A->get_center_of_mass(), -jb_com, 0.0f);
+ B->apply_bias_impulse(B->get_center_of_mass(), jb_com, 0.0f);
+ }
c.active = true;
}
@@ -382,7 +400,7 @@ void BodyPairSW::solve(real_t p_step) {
Vector3 crB = B->get_angular_velocity().cross(c.rB);
Vector3 dv = B->get_linear_velocity() + crB - A->get_linear_velocity() - crA;
- //normal impule
+ //normal impulse
real_t vn = dv.dot(c.normal);
if (Math::abs(vn) > MIN_VELOCITY) {
@@ -399,7 +417,7 @@ void BodyPairSW::solve(real_t p_step) {
c.active = true;
}
- //friction impule
+ //friction impulse
real_t friction = A->get_friction() * B->get_friction();
diff --git a/servers/physics/body_pair_sw.h b/servers/physics/body_pair_sw.h
index f09c977950..74fda60998 100644
--- a/servers/physics/body_pair_sw.h
+++ b/servers/physics/body_pair_sw.h
@@ -59,6 +59,7 @@ class BodyPairSW : public ConstraintSW {
real_t acc_normal_impulse; // accumulated normal impulse (Pn)
Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt)
real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb)
+ real_t acc_bias_impulse_center_of_mass; // accumulated normal impulse for position bias applied to com
real_t mass_normal;
real_t bias;
real_t bounce;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index fc64ca5817..738d99c764 100644
--- a/servers/physics/body_sw.h
+++ b/servers/physics/body_sw.h
@@ -227,10 +227,16 @@ public:
angular_velocity += _inv_inertia_tensor.xform(p_j);
}
- _FORCE_INLINE_ void apply_bias_impulse(const Vector3 &p_pos, const Vector3 &p_j) {
+ _FORCE_INLINE_ void apply_bias_impulse(const Vector3 &p_pos, const Vector3 &p_j, real_t p_max_delta_av = -1.0) {
biased_linear_velocity += p_j * _inv_mass;
- biased_angular_velocity += _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
+ if (p_max_delta_av != 0.0) {
+ Vector3 delta_av = _inv_inertia_tensor.xform((p_pos - center_of_mass).cross(p_j));
+ if (p_max_delta_av > 0 && delta_av.length() > p_max_delta_av) {
+ delta_av = delta_av.normalized() * p_max_delta_av;
+ }
+ biased_angular_velocity += delta_av;
+ }
}
_FORCE_INLINE_ void apply_bias_torque_impulse(const Vector3 &p_j) {
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 6eaaaa777b..f9febd1093 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -626,13 +626,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
int amount = _cull_aabb_for_body(p_body, motion_aabb);
- for (int j = 0; j < p_body->get_shape_count(); j++) {
+ for (int body_shape_idx = 0; body_shape_idx < p_body->get_shape_count(); body_shape_idx++) {
- if (p_body->is_shape_set_as_disabled(j))
+ if (p_body->is_shape_set_as_disabled(body_shape_idx))
continue;
- Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j);
- Shape2DSW *body_shape = p_body->get_shape(j);
+ Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(body_shape_idx);
+ Shape2DSW *body_shape = p_body->get_shape(body_shape_idx);
bool stuck = false;
@@ -642,14 +642,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
for (int i = 0; i < amount; i++) {
const CollisionObject2DSW *col_obj = intersection_query_results[i];
- int shape_idx = intersection_query_subindex_results[i];
- Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
+ int col_shape_idx = intersection_query_subindex_results[i];
+ Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx);
bool excluded = false;
for (int k = 0; k < excluded_shape_pair_count; k++) {
- if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == shape_idx) {
+ if (excluded_shape_pairs[k].local_shape == body_shape && excluded_shape_pairs[k].against_object == col_obj && excluded_shape_pairs[k].against_shape_index == col_shape_idx) {
excluded = true;
break;
}
@@ -660,7 +660,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
continue;
}
- Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
//test initial overlap, does it collide if going all the way?
if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) {
continue;
@@ -669,7 +669,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//test initial overlap
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_xform, Vector2(), NULL, NULL, NULL, 0)) {
- if (col_obj->is_shape_set_as_one_way_collision(j)) {
+ if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
continue;
}
@@ -698,7 +698,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
}
}
- if (col_obj->is_shape_set_as_one_way_collision(j)) {
+ if (col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) {
Vector2 cd[2];
Physics2DServerSW::CollCbkData cbk;
@@ -710,7 +710,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.valid_depth = 10e20;
Vector2 sep = mnormal; //important optimization for this to work fast enough
- bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
+ bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_xform, Vector2(), Physics2DServerSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) {
continue;
}
@@ -726,7 +726,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
safe = 0;
unsafe = 0;
- best_shape = j; //sadly it's the best
+ best_shape = body_shape_idx; //sadly it's the best
break;
}
if (best_safe == 1.0) {
@@ -736,7 +736,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
safe = best_safe;
unsafe = best_unsafe;
- best_shape = j;
+ best_shape = body_shape_idx;
}
}
}
diff --git a/thirdparty/openssl/uwp.cpp b/thirdparty/openssl/uwp.cpp
index dcfd22b77f..e00c9d59db 100644
--- a/thirdparty/openssl/uwp.cpp
+++ b/thirdparty/openssl/uwp.cpp
@@ -103,12 +103,14 @@ extern "C"
{
return 0;
}
+#ifndef STD_ERROR_HANDLE
int __cdecl GetStdHandle(
_In_ DWORD nStdHandle
)
{
return 0;
}
+#endif
BOOL DeregisterEventSource(
_Inout_ HANDLE hEventLog
)