summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml37
-rw-r--r--SConstruct1
-rw-r--r--core/io/http_client.cpp135
-rw-r--r--core/io/http_client.h12
-rw-r--r--core/math/math_funcs.h1
-rw-r--r--doc/classes/@GDScript.xml5
-rw-r--r--doc/classes/@Global Scope.xml6
-rw-r--r--doc/classes/ARVRController.xml16
-rw-r--r--doc/classes/ARVRInterface.xml4
-rw-r--r--doc/classes/ARVRPositionalTracker.xml18
-rw-r--r--doc/classes/ARVRServer.xml25
-rw-r--r--doc/classes/AStar.xml44
-rw-r--r--doc/classes/Array.xml8
-rw-r--r--doc/classes/AtlasTexture.xml16
-rw-r--r--doc/classes/BulletPhysicsDirectBodyState.xml15
-rw-r--r--doc/classes/BulletPhysicsServer.xml (renamed from doc/classes/PhysicsDirectBodyStateSW.xml)2
-rw-r--r--doc/classes/Geometry.xml40
-rw-r--r--doc/classes/LineEdit.xml14
-rw-r--r--doc/classes/Physics2DServer.xml59
-rw-r--r--doc/classes/PhysicsServer.xml22
-rw-r--r--doc/classes/PhysicsServerSW.xml17
-rw-r--r--doc/classes/Polygon2D.xml14
-rw-r--r--doc/classes/String.xml6
-rw-r--r--doc/classes/StyleBoxLine.xml79
-rw-r--r--doc/classes/TextEdit.xml28
-rw-r--r--doc/classes/TileMap.xml16
-rw-r--r--doc/classes/ViewportContainer.xml16
-rw-r--r--doc/classes/VisualScriptBuiltinFunc.xml44
-rw-r--r--doc/classes/VisualScriptMathConstant.xml8
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp4
-rw-r--r--drivers/gles3/shaders/canvas.glsl3
-rw-r--r--editor/doc/doc_data.cpp47
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_help.cpp24
-rw-r--r--editor/editor_node.cpp18
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_resource_preview.cpp12
-rw-r--r--editor/editor_themes.cpp24
-rw-r--r--editor/editor_themes.h2
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp6
-rw-r--r--editor/import_dock.cpp74
-rw-r--r--editor/import_dock.h2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp8
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp23
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h3
-rw-r--r--editor/plugins/script_editor_plugin.cpp325
-rw-r--r--editor/plugins/script_editor_plugin.h14
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp17
-rw-r--r--editor/project_export.cpp2
-rw-r--r--editor/project_settings_editor.cpp5
-rw-r--r--editor/scene_tree_dock.cpp9
-rwxr-xr-xmisc/travis/android-tools-linux.sh107
-rwxr-xr-xmisc/travis/android-tools-osx.sh107
-rwxr-xr-xmisc/travis/ccache-osx.sh43
-rwxr-xr-xmisc/travis/scons-local-osx.sh18
-rw-r--r--modules/gdnative/SCsub6
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.cpp4
-rw-r--r--modules/gdnative/arvr/arvr_interface_gdnative.h2
-rw-r--r--modules/gdnative/include/arvr/godot_arvr.h2
-rw-r--r--modules/gdscript/gd_editor.cpp49
-rw-r--r--modules/gdscript/gd_parser.cpp7
-rw-r--r--modules/gdscript/gd_script.cpp2
-rw-r--r--modules/gdscript/gd_tokenizer.cpp3
-rw-r--r--modules/gdscript/gd_tokenizer.h1
-rw-r--r--modules/mobile_vr/mobile_interface.cpp13
-rw-r--r--modules/mobile_vr/mobile_interface.h2
-rw-r--r--modules/ogg/config.py3
-rw-r--r--modules/opus/SCsub11
-rw-r--r--modules/opus/config.py3
-rw-r--r--modules/opus/stub/register_types.cpp36
-rw-r--r--modules/opus/stub/register_types.h31
-rw-r--r--modules/theora/config.py3
-rw-r--r--modules/theora/register_types.cpp13
-rw-r--r--modules/theora/resource_importer_theora.cpp89
-rw-r--r--modules/theora/resource_importer_theora.h57
-rw-r--r--modules/theora/video_stream_theora.cpp46
-rw-r--r--modules/theora/video_stream_theora.h16
-rw-r--r--modules/visual_script/visual_script_editor.cpp17
-rw-r--r--modules/visual_script/visual_script_expression.cpp3
-rw-r--r--modules/visual_script/visual_script_nodes.cpp6
-rw-r--r--modules/visual_script/visual_script_nodes.h2
-rw-r--r--modules/vorbis/SCsub10
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp4
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h2
-rw-r--r--modules/vorbis/config.py3
-rw-r--r--modules/vorbis/stub/register_types.cpp36
-rw-r--r--modules/vorbis/stub/register_types.h31
-rw-r--r--modules/webm/config.py3
-rw-r--r--modules/webm/libvpx/SCsub4
-rw-r--r--modules/webm/register_types.cpp13
-rw-r--r--modules/webm/resource_importer_webm.cpp95
-rw-r--r--modules/webm/resource_importer_webm.h55
-rw-r--r--modules/webm/video_stream_webm.cpp153
-rw-r--r--modules/webm/video_stream_webm.h23
-rw-r--r--platform/android/detect.py11
-rw-r--r--platform/android/godot_android.cpp14
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java13
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotLib.java1
-rw-r--r--platform/android/java_glue.cpp7
-rw-r--r--platform/android/java_glue.h1
-rw-r--r--platform/android/os_android.cpp5
-rw-r--r--platform/android/os_android.h1
-rw-r--r--platform/iphone/detect.py21
-rw-r--r--platform/javascript/SCsub7
-rw-r--r--platform/javascript/http_client.h.inc48
-rw-r--r--platform/javascript/http_client_javascript.cpp282
-rw-r--r--platform/javascript/http_request.h72
-rw-r--r--platform/javascript/http_request.js145
-rw-r--r--platform/javascript/os_javascript.cpp7
-rw-r--r--platform/osx/detect.py11
-rw-r--r--platform/windows/context_gl_win.cpp2
-rw-r--r--scene/audio/audio_player.cpp50
-rw-r--r--scene/audio/audio_player.h1
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/scroll_container.cpp5
-rw-r--r--scene/gui/text_edit.cpp9
-rw-r--r--scene/gui/text_edit.h1
-rw-r--r--scene/gui/video_player.cpp144
-rw-r--r--scene/gui/video_player.h22
-rwxr-xr-xscene/main/node.cpp17
-rw-r--r--scene/main/node.h1
-rw-r--r--scene/resources/audio_stream_sample.cpp32
-rw-r--r--scene/resources/dynamic_font_stb.cpp5
-rw-r--r--scene/resources/environment.cpp3
-rw-r--r--scene/resources/mesh.cpp13
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/primitive_meshes.cpp38
-rw-r--r--scene/resources/primitive_meshes.h5
-rw-r--r--scene/resources/video_stream.h4
-rw-r--r--servers/arvr/arvr_interface.cpp2
-rw-r--r--servers/arvr/arvr_interface.h2
-rw-r--r--servers/arvr_server.cpp19
-rw-r--r--servers/arvr_server.h1
-rw-r--r--servers/audio/audio_rb_resampler.cpp210
-rw-r--r--servers/audio/audio_rb_resampler.h49
-rw-r--r--servers/audio_server.cpp2
-rw-r--r--servers/physics_server.cpp1
-rw-r--r--servers/visual/visual_server_viewport.cpp2
-rw-r--r--thirdparty/libsimplewebm/OpusVorbisDecoder.cpp37
-rw-r--r--thirdparty/libsimplewebm/OpusVorbisDecoder.hpp2
142 files changed, 2983 insertions, 829 deletions
diff --git a/.travis.yml b/.travis.yml
index 409c870e79..974ef93d3f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,12 +20,12 @@ matrix:
#- env: GODOT_TARGET=windows TOOLS=yes
# os: linux
# compiler: gcc
+ - env: GODOT_TARGET=android TOOLS=no
+ os: linux
+ compiler: gcc
- env: GODOT_TARGET=osx TOOLS=yes
os: osx
compiler: clang
- #- env: GODOT_TARGET=android TOOLS=no
- # os: osx
- # compiler: clang
#- env: GODOT_TARGET=iphone TOOLS=no
# os: osx
# compiler: clang
@@ -61,15 +61,29 @@ addons:
# For style checks.
- clang-format-3.9
+install:
+ - if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$GODOT_TARGET" = "android" ]; then
+ misc/travis/android-tools-linux.sh;
+ fi
+ - if [ "$TRAVIS_OS_NAME" = "osx" ]; then
+ misc/travis/scons-local-osx.sh;
+ misc/travis/ccache-osx.sh;
+ fi
+ - if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then
+ misc/travis/android-tools-osx.sh;
+ fi
+
before_script:
+ - if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+ export CCACHE="/usr/bin/ccache";
+ fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then
- brew update; brew install scons ccache;
+ export CCACHE="/usr/local/bin/ccache";
export PATH="/usr/local/opt/ccache/libexec:$PATH";
fi
- - if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then
- brew update; brew install -v android-sdk;
- brew install -v android-ndk | grep -v "inflating:" | grep -v "creating:";
- export ANDROID_HOME=/usr/local/opt/android-sdk; export ANDROID_NDK_ROOT=/usr/local/opt/android-ndk;
+ - if [ "$GODOT_TARGET" = "android" ]; then
+ export ANDROID_HOME=$TRAVIS_BUILD_DIR/godot-dev/build-tools/android-sdk;
+ export ANDROID_NDK_ROOT=$TRAVIS_BUILD_DIR/godot-dev/build-tools/android-ndk;
fi
script:
@@ -78,3 +92,10 @@ script:
else
scons -j2 CC=$CC CXX=$CXX platform=$GODOT_TARGET TOOLS=$TOOLS verbose=yes progress=no;
fi
+
+after_success:
+ - if [ "$STATIC_CHECKS" != "yes" ] && [ $(command -v ccache) ]; then
+ which ccache;
+ ccache --version | grep "ccache version";
+ ccache -s;
+ fi;
diff --git a/SConstruct b/SConstruct
index 9d536e0d16..7a28a1a64c 100644
--- a/SConstruct
+++ b/SConstruct
@@ -1,4 +1,3 @@
-
#!/usr/bin/env python
EnsureSConsVersion(0, 98, 1)
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 46d52384e5..5097898314 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -30,6 +30,7 @@
#include "http_client.h"
#include "io/stream_peer_ssl.h"
+#ifndef JAVASCRIPT_ENABLED
Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
close();
@@ -405,38 +406,6 @@ Error HTTPClient::poll() {
return OK;
}
-Dictionary HTTPClient::_get_response_headers_as_dictionary() {
-
- List<String> rh;
- get_response_headers(&rh);
- Dictionary ret;
- for (const List<String>::Element *E = rh.front(); E; E = E->next()) {
- String s = E->get();
- int sp = s.find(":");
- if (sp == -1)
- continue;
- String key = s.substr(0, sp).strip_edges();
- String value = s.substr(sp + 1, s.length()).strip_edges();
- ret[key] = value;
- }
-
- return ret;
-}
-
-PoolStringArray HTTPClient::_get_response_headers() {
-
- List<String> rh;
- get_response_headers(&rh);
- PoolStringArray ret;
- ret.resize(rh.size());
- int idx = 0;
- for (const List<String>::Element *E = rh.front(); E; E = E->next()) {
- ret.set(idx++, E->get());
- }
-
- return ret;
-}
-
int HTTPClient::get_response_body_length() const {
return body_size;
@@ -612,6 +581,74 @@ Error HTTPClient::_get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received
}
}
+void HTTPClient::set_read_chunk_size(int p_size) {
+ ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24));
+ read_chunk_size = p_size;
+}
+
+HTTPClient::HTTPClient() {
+
+ tcp_connection = StreamPeerTCP::create_ref();
+ resolving = IP::RESOLVER_INVALID_ID;
+ status = STATUS_DISCONNECTED;
+ conn_port = 80;
+ body_size = 0;
+ chunked = false;
+ body_left = 0;
+ chunk_left = 0;
+ response_num = 0;
+ ssl = false;
+ blocking = false;
+ read_chunk_size = 4096;
+}
+
+HTTPClient::~HTTPClient() {
+}
+
+#endif // #ifndef JAVASCRIPT_ENABLED
+
+String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
+ String query = "";
+ Array keys = p_dict.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ query += "&" + String(keys[i]).http_escape() + "=" + String(p_dict[keys[i]]).http_escape();
+ }
+ query.erase(0, 1);
+ return query;
+}
+
+Dictionary HTTPClient::_get_response_headers_as_dictionary() {
+
+ List<String> rh;
+ get_response_headers(&rh);
+ Dictionary ret;
+ for (const List<String>::Element *E = rh.front(); E; E = E->next()) {
+ String s = E->get();
+ int sp = s.find(":");
+ if (sp == -1)
+ continue;
+ String key = s.substr(0, sp).strip_edges();
+ String value = s.substr(sp + 1, s.length()).strip_edges();
+ ret[key] = value;
+ }
+
+ return ret;
+}
+
+PoolStringArray HTTPClient::_get_response_headers() {
+
+ List<String> rh;
+ get_response_headers(&rh);
+ PoolStringArray ret;
+ ret.resize(rh.size());
+ int idx = 0;
+ for (const List<String>::Element *E = rh.front(); E; E = E->next()) {
+ ret.set(idx++, E->get());
+ }
+
+ return ret;
+}
+
void HTTPClient::_bind_methods() {
ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(false), DEFVAL(true));
@@ -717,37 +754,3 @@ void HTTPClient::_bind_methods() {
BIND_ENUM_CONSTANT(RESPONSE_INSUFFICIENT_STORAGE);
BIND_ENUM_CONSTANT(RESPONSE_NOT_EXTENDED);
}
-
-void HTTPClient::set_read_chunk_size(int p_size) {
- ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24));
- read_chunk_size = p_size;
-}
-
-String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
- String query = "";
- Array keys = p_dict.keys();
- for (int i = 0; i < keys.size(); ++i) {
- query += "&" + String(keys[i]).http_escape() + "=" + String(p_dict[keys[i]]).http_escape();
- }
- query.erase(0, 1);
- return query;
-}
-
-HTTPClient::HTTPClient() {
-
- tcp_connection = StreamPeerTCP::create_ref();
- resolving = IP::RESOLVER_INVALID_ID;
- status = STATUS_DISCONNECTED;
- conn_port = 80;
- body_size = 0;
- chunked = false;
- body_left = 0;
- chunk_left = 0;
- response_num = 0;
- ssl = false;
- blocking = false;
- read_chunk_size = 4096;
-}
-
-HTTPClient::~HTTPClient() {
-}
diff --git a/core/io/http_client.h b/core/io/http_client.h
index f8a3349e6e..db5dd115bd 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -131,6 +131,7 @@ public:
};
private:
+#ifndef JAVASCRIPT_ENABLED
Status status;
IP::ResolverID resolving;
int conn_port;
@@ -152,13 +153,18 @@ private:
int response_num;
Vector<String> response_headers;
+ int read_chunk_size;
+
+ Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received);
+
+#else
+#include "platform/javascript/http_client.h.inc"
+#endif
- static void _bind_methods();
PoolStringArray _get_response_headers();
Dictionary _get_response_headers_as_dictionary();
- int read_chunk_size;
- Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received);
+ static void _bind_methods();
public:
//Error connect_and_get(const String& p_url,bool p_verify_host=true); //connects to a full url and perform request
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index d5135fe414..bc0b3717ed 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -39,6 +39,7 @@
#include <math.h>
#define Math_PI 3.14159265358979323846
+#define Math_TAU 6.28318530717958647692
#define Math_SQRT12 0.7071067811865475244008443621048490
#define Math_LN2 0.693147180559945309417
#define Math_INF INFINITY
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 9c1d9a1aa2..47003d08e0 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -1117,7 +1117,10 @@
</methods>
<constants>
<constant name="PI" value="3.141593" enum="">
- Constant that represents how many times the diameter of a circumference fits around its perimeter.
+ Constant that represents how many times the diameter of a circle fits around its perimeter.
+ </constant>
+ <constant name="TAU" value="6.283185" enum="">
+ The circle constant, the circumference of the unit circle.
</constant>
<constant name="INF" value="inf" enum="">
A positive infinity. (For negative infinity, use -INF).
diff --git a/doc/classes/@Global Scope.xml b/doc/classes/@Global Scope.xml
index 20f323bb4f..5e571e0284 100644
--- a/doc/classes/@Global Scope.xml
+++ b/doc/classes/@Global Scope.xml
@@ -1038,7 +1038,11 @@
<constant name="JOY_AXIS_7" value="7">
Joypad Right Trigger Analog Axis
</constant>
- <constant name="JOY_AXIS_MAX" value="8">
+ <constant name="JOY_AXIS_8" value="8">
+ </constant>
+ <constant name="JOY_AXIS_9" value="9">
+ </constant>
+ <constant name="JOY_AXIS_MAX" value="10">
</constant>
<constant name="JOY_ANALOG_LX" value="0">
Joypad Left Stick Horizontal Axis
diff --git a/doc/classes/ARVRController.xml b/doc/classes/ARVRController.xml
index af1deda2f0..2e6afe47cf 100644
--- a/doc/classes/ARVRController.xml
+++ b/doc/classes/ARVRController.xml
@@ -57,6 +57,12 @@
Returns the ID of the joystick object bound to this. Every controller tracked by the ARVR Server that has buttons and axis will also be registered as a joystick within Godot. This means that all the normal joystick tracking and input mapping will work for buttons and axis found on the AR/VR controllers. This ID is purely offered as information so you can link up the controller with its joystick entry.
</description>
</method>
+ <method name="get_rumble" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="is_button_pressed" qualifiers="const">
<return type="int">
</return>
@@ -75,11 +81,21 @@
Changes the id that identifies the controller bound to this node. The first controller that the ARVR Server detects will have id 1, the second id 2, the third id 3, etc. When a controller is turned off that slot is freed ensuring that controllers will keep the same id while it is turned on even when controllers with lower ids are turned off.
</description>
</method>
+ <method name="set_rumble">
+ <return type="void">
+ </return>
+ <argument index="0" name="rumble" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="controller_id" type="int" setter="set_controller_id" getter="get_controller_id">
The controller's id. The first controller that the [ARVRServer] detects will have id 1, the second id 2, the third id 3, etc. When a controller is turned off, it's slot is freed. This ensures controllers will keep the same id even when controllers with lower ids are turned off.
</member>
+ <member name="rumble" type="float" setter="set_rumble" getter="get_rumble">
+ </member>
</members>
<signals>
<signal name="button_pressed">
diff --git a/doc/classes/ARVRInterface.xml b/doc/classes/ARVRInterface.xml
index 9aed6c96ef..d7962ae5c3 100644
--- a/doc/classes/ARVRInterface.xml
+++ b/doc/classes/ARVRInterface.xml
@@ -33,7 +33,7 @@
Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc).
</description>
</method>
- <method name="get_recommended_render_targetsize">
+ <method name="get_render_targetsize">
<return type="Vector2">
</return>
<description>
@@ -139,7 +139,7 @@
This interface support AR (video background and real world tracking).
</constant>
<constant name="ARVR_EXTERNAL" value="8">
- This interface outputs to an external device, if the main viewport is used the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of get_recommended_render_targetsize. Using a seperate viewport node frees up the main viewport for other purposes.
+ This interface outputs to an external device, if the main viewport is used the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of get_render_targetsize. Using a seperate viewport node frees up the main viewport for other purposes.
</constant>
<constant name="EYE_MONO" value="0">
Mono output, this is mostly used internally when retrieving positioning information for our camera node or when stereo scopic rendering is not supported.
diff --git a/doc/classes/ARVRPositionalTracker.xml b/doc/classes/ARVRPositionalTracker.xml
index 686ac1db77..dbb676f88c 100644
--- a/doc/classes/ARVRPositionalTracker.xml
+++ b/doc/classes/ARVRPositionalTracker.xml
@@ -48,6 +48,12 @@
Returns the position of the controller adjusted by world scale.
</description>
</method>
+ <method name="get_rumble" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_tracks_orientation" qualifiers="const">
<return type="bool">
</return>
@@ -78,7 +84,19 @@
Type of tracker.
</description>
</method>
+ <method name="set_rumble">
+ <return type="void">
+ </return>
+ <argument index="0" name="rumble" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
+ <members>
+ <member name="rumble" type="float" setter="set_rumble" getter="get_rumble">
+ </member>
+ </members>
<constants>
<constant name="TRACKER_HAND_UNKNOWN" value="0">
The hand this tracker is held in is unknown or not applicable.
diff --git a/doc/classes/ARVRServer.xml b/doc/classes/ARVRServer.xml
index bb7ac2c052..705abf2e94 100644
--- a/doc/classes/ARVRServer.xml
+++ b/doc/classes/ARVRServer.xml
@@ -11,15 +11,6 @@
<demos>
</demos>
<methods>
- <method name="add_interface">
- <return type="void">
- </return>
- <argument index="0" name="interface" type="ARVRInterface">
- </argument>
- <description>
- Mostly exposed for GDNative based interfaces, this is called to register an available interface with the AR/VR server.
- </description>
- </method>
<method name="center_on_hmd">
<return type="void">
</return>
@@ -61,6 +52,13 @@
Get the number of interfaces currently registered with the AR/VR server. If you're game supports multiple AR/VR platforms you can look throught the available interface and either present the user with a selection or simply try an initialize each interface and use the first one that returns true.
</description>
</method>
+ <method name="get_interfaces" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Returns a list of available interfaces with both id and name of the interface.
+ </description>
+ </method>
<method name="get_reference_frame" qualifiers="const">
<return type="Transform">
</return>
@@ -91,15 +89,6 @@
Returns our world scale (see ARVROrigin for more information).
</description>
</method>
- <method name="remove_interface">
- <return type="void">
- </return>
- <argument index="0" name="interface" type="ARVRInterface">
- </argument>
- <description>
- Removes a registered interface, again exposed mostly for GDNative based interfaces.
- </description>
- </method>
<method name="set_primary_interface">
<return type="void">
</return>
diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml
index 10ca3035fb..a2199c8f01 100644
--- a/doc/classes/AStar.xml
+++ b/doc/classes/AStar.xml
@@ -168,6 +168,28 @@
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
</description>
</method>
+ <method name="get_point_connections">
+ <return type="PoolIntArray">
+ </return>
+ <argument index="0" name="arg0" type="int">
+ </argument>
+ <description>
+ Returns an array with the ids of the points that form the connect with the given point.
+ [codeblock]
+ var as = AStar.new()
+
+ as.add_point(1, Vector3(0,0,0))
+ as.add_point(2, Vector3(0,1,0))
+ as.add_point(3, Vector3(1,1,0))
+ as.add_point(4, Vector3(2,0,0))
+
+ as.connect_points(1, 2, true)
+ as.connect_points(1, 3, true)
+
+ var neighbors = as.get_point_connections(1) # returns [2, 3]
+ [/codeblock]
+ </description>
+ </method>
<method name="get_point_path">
<return type="PoolVector3Array">
</return>
@@ -243,28 +265,6 @@
Sets the [code]weight_scale[/code] for the point with the given id.
</description>
</method>
- <method name="get_point_connections">
- <return type="PoolIntArray">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Returns an array with the ids of the points that form the connect with the given point.
- [codeblock]
- var as = AStar.new()
-
- as.add_point(1, Vector3(0,0,0))
- as.add_point(2, Vector3(0,1,0))
- as.add_point(3, Vector3(1,1,0))
- as.add_point(4, Vector3(2,0,0))
-
- as.connect_points(1, 2, true)
- as.connect_points(1, 3, true)
-
- var neighbors = as.get_point_connections(1) # returns [2, 3]
- [/codeblock]
- </description>
- </method>
</methods>
<constants>
</constants>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 7c1d72333b..05a571fb5e 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -82,6 +82,8 @@
</description>
</method>
<method name="back">
+ <return type="var">
+ </return>
<description>
Returns the last element of the array if the array is not empty (size&gt;0).
</description>
@@ -142,6 +144,8 @@
</description>
</method>
<method name="front">
+ <return type="var">
+ </return>
<description>
Returns the first element of the array if the array is not empty (size&gt;0).
</description>
@@ -183,11 +187,15 @@
</description>
</method>
<method name="pop_back">
+ <return type="var">
+ </return>
<description>
Remove the last element of the array.
</description>
</method>
<method name="pop_front">
+ <return type="var">
+ </return>
<description>
Remove the first element of the array.
</description>
diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml
index 179f78f16f..924dae8495 100644
--- a/doc/classes/AtlasTexture.xml
+++ b/doc/classes/AtlasTexture.xml
@@ -30,6 +30,12 @@
<description>
</description>
</method>
+ <method name="has_filter_clip" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="set_atlas">
<return type="void">
</return>
@@ -38,6 +44,14 @@
<description>
</description>
</method>
+ <method name="set_filter_clip">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_margin">
<return type="void">
</return>
@@ -59,6 +73,8 @@
<member name="atlas" type="Texture" setter="set_atlas" getter="get_atlas">
The texture that contains the atlas. Can be any [Texture] subtype.
</member>
+ <member name="filter_clip" type="bool" setter="set_filter_clip" getter="has_filter_clip">
+ </member>
<member name="margin" type="Rect2" setter="set_margin" getter="get_margin">
The margin around the region. The [Rect2]'s 'size' parameter ('w' and 'h' in the editor) resizes the texture so it fits within the margin.
</member>
diff --git a/doc/classes/BulletPhysicsDirectBodyState.xml b/doc/classes/BulletPhysicsDirectBodyState.xml
new file mode 100644
index 0000000000..3d7be54e19
--- /dev/null
+++ b/doc/classes/BulletPhysicsDirectBodyState.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/PhysicsDirectBodyStateSW.xml b/doc/classes/BulletPhysicsServer.xml
index 6d283f307e..ac5d510486 100644
--- a/doc/classes/PhysicsDirectBodyStateSW.xml
+++ b/doc/classes/BulletPhysicsServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsDirectBodyStateSW" inherits="PhysicsDirectBodyState" category="Core" version="3.0.alpha.custom_build">
+<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.0.alpha.custom_build">
<brief_description>
</brief_description>
<description>
diff --git a/doc/classes/Geometry.xml b/doc/classes/Geometry.xml
index 1589a9a906..283d77c954 100644
--- a/doc/classes/Geometry.xml
+++ b/doc/classes/Geometry.xml
@@ -50,6 +50,26 @@
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="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>
+ <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="get_closest_point_to_segment">
<return type="Vector3">
</return>
@@ -280,26 +300,6 @@
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>
<constants>
</constants>
diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml
index bf81d90efe..a9626d945c 100644
--- a/doc/classes/LineEdit.xml
+++ b/doc/classes/LineEdit.xml
@@ -114,7 +114,7 @@
Return the text in the [code]LineEdit[/code].
</description>
</method>
- <method name="is_context_menu_enabled" qualifiers="const">
+ <method name="is_context_menu_enabled">
<return type="bool">
</return>
<description>
@@ -180,7 +180,7 @@
<method name="set_context_menu_enabled">
<return type="void">
</return>
- <argument index="0" name="enabled" type="bool">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
Set the status of the context menu. When enabled, the context menu will appear when the [code]LineEdit[/code] is right clicked.
@@ -268,6 +268,9 @@
<member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed">
Duration (in seconds) of a caret's blinking cycle.
</member>
+ <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled">
+ If [code]true[/code] the context menu will appear when right clicked.
+ </member>
<member name="editable" type="bool" setter="set_editable" getter="is_editable">
If [code]false[/code] existing text cannot be modified and new text cannot be added.
</member>
@@ -292,9 +295,6 @@
<member name="text" type="String" setter="set_text" getter="get_text">
String value of the [LineEdit].
</member>
- <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled">
- If [code]true[/code] the context menu will appear when right clicked.
- </member>
</members>
<signals>
<signal name="text_changed">
@@ -343,7 +343,9 @@
<constant name="MENU_UNDO" value="5">
Undoes the previous action.
</constant>
- <constant name="MENU_MAX" value="6">
+ <constant name="MENU_REDO" value="6">
+ </constant>
+ <constant name="MENU_MAX" value="7">
</constant>
</constants>
<theme_items>
diff --git a/doc/classes/Physics2DServer.xml b/doc/classes/Physics2DServer.xml
index 6e3381c200..764f18c427 100644
--- a/doc/classes/Physics2DServer.xml
+++ b/doc/classes/Physics2DServer.xml
@@ -338,10 +338,6 @@
<method name="body_create">
<return type="RID">
</return>
- <argument index="0" name="mode" type="int" enum="Physics2DServer.BodyMode" default="2">
- </argument>
- <argument index="1" name="init_sleeping" type="bool" default="false">
- </argument>
<description>
Creates a physics body. The first parameter can be any value from constants BODY_MODE*, for the type of body created. Additionally, the body can be created in sleeping state to save processing time.
</description>
@@ -725,6 +721,30 @@
Returns whether a body can move from a given point in a given direction. Apart from the boolean return value, a [Physics2DTestMotionResult] can be passed to return additional information in.
</description>
</method>
+ <method name="capsule_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="circle_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="concave_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="convex_polygon_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="damped_spring_joint_create">
<return type="RID">
</return>
@@ -832,6 +852,12 @@
Sets a joint parameter. Parameters are explained in the JOINT_PARAM* constants.
</description>
</method>
+ <method name="line_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="pin_joint_create">
<return type="RID">
</return>
@@ -845,22 +871,31 @@
Creates a pin joint between two bodies. If not specified, the second body is assumed to be the joint itself.
</description>
</method>
- <method name="set_active">
- <return type="void">
+ <method name="ray_shape_create">
+ <return type="RID">
</return>
- <argument index="0" name="active" type="bool">
- </argument>
<description>
- Activates or deactivates the 2D physics engine.
</description>
</method>
- <method name="shape_create">
+ <method name="rectangle_shape_create">
<return type="RID">
</return>
- <argument index="0" name="type" type="int" enum="Physics2DServer.ShapeType">
+ <description>
+ </description>
+ </method>
+ <method name="segment_shape_create">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_active">
+ <return type="void">
+ </return>
+ <argument index="0" name="active" type="bool">
</argument>
<description>
- Creates a shape of type SHAPE_*. Does not assign it to a body or an area. To do so, you must use [method area_set_shape] or [method body_set_shape].
+ Activates or deactivates the 2D physics engine.
</description>
</method>
<method name="shape_get_data" qualifiers="const">
diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml
index b0f42b83a3..c165ee3c1e 100644
--- a/doc/classes/PhysicsServer.xml
+++ b/doc/classes/PhysicsServer.xml
@@ -388,6 +388,14 @@
Returns the [PhysicsDirectBodyState] of the body.
</description>
</method>
+ <method name="body_get_kinematic_safe_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
@@ -598,6 +606,16 @@
Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force integration]).
</description>
</method>
+ <method name="body_set_kinematic_safe_margin">
+ <return type="void">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="body_set_max_contacts_reported">
<return type="void">
</return>
@@ -1422,7 +1440,9 @@
<constant name="BODY_MODE_RIGID" value="2">
Constant for rigid bodies.
</constant>
- <constant name="BODY_MODE_CHARACTER" value="3">
+ <constant name="BODY_MODE_SOFT" value="3">
+ </constant>
+ <constant name="BODY_MODE_CHARACTER" value="4">
Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics.
</constant>
<constant name="BODY_PARAM_BOUNCE" value="0">
diff --git a/doc/classes/PhysicsServerSW.xml b/doc/classes/PhysicsServerSW.xml
deleted file mode 100644
index 53e1c0057e..0000000000
--- a/doc/classes/PhysicsServerSW.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PhysicsServerSW" inherits="PhysicsServer" category="Core" version="3.0.alpha.custom_build">
- <brief_description>
- Software implementation of [PhysicsServer].
- </brief_description>
- <description>
- This class exposes no new methods or properties and should not be used, as [PhysicsServer] automatically selects the best implementation available.
- </description>
- <tutorials>
- </tutorials>
- <demos>
- </demos>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml
index 5aa7146ff7..57494fe6d6 100644
--- a/doc/classes/Polygon2D.xml
+++ b/doc/classes/Polygon2D.xml
@@ -73,6 +73,12 @@
Return the rotation in radians of the texture polygon.
</description>
</method>
+ <method name="get_texture_rotation_degrees" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_texture_scale" qualifiers="const">
<return type="Vector2">
</return>
@@ -173,6 +179,14 @@
Set the amount of rotation of the polygon texture, [code]texture_rotation[/code] is specified in radians and clockwise rotation.
</description>
</method>
+ <method name="set_texture_rotation_degrees">
+ <return type="void">
+ </return>
+ <argument index="0" name="texture_rotation" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_texture_scale">
<return type="void">
</return>
diff --git a/doc/classes/String.xml b/doc/classes/String.xml
index 546712f223..8c8fbc620c 100644
--- a/doc/classes/String.xml
+++ b/doc/classes/String.xml
@@ -273,6 +273,12 @@
Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]+1[/code] if greater than, or [code]0[/code] if equal.
</description>
</method>
+ <method name="dedent">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="empty">
<return type="bool">
</return>
diff --git a/doc/classes/StyleBoxLine.xml b/doc/classes/StyleBoxLine.xml
new file mode 100644
index 0000000000..83d87176f2
--- /dev/null
+++ b/doc/classes/StyleBoxLine.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="StyleBoxLine" inherits="StyleBox" category="Core" version="3.0.alpha.custom_build">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <demos>
+ </demos>
+ <methods>
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_grow" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_thickness" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_vertical" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_color">
+ <return type="void">
+ </return>
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_grow">
+ <return type="void">
+ </return>
+ <argument index="0" name="grow" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_thickness">
+ <return type="void">
+ </return>
+ <argument index="0" name="thickness" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_vertical">
+ <return type="void">
+ </return>
+ <argument index="0" name="vertical" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="color" type="Color" setter="set_color" getter="get_color">
+ </member>
+ <member name="thickness" type="int" setter="set_thickness" getter="get_thickness">
+ </member>
+ <member name="vertical" type="bool" setter="set_vertical" getter="is_vertical">
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index e7f94b5826..43c7e02fbf 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -232,19 +232,18 @@
Insert a given text at the cursor position.
</description>
</method>
- <method name="is_highlight_all_occurrences_enabled" qualifiers="const">
+ <method name="is_context_menu_enabled">
<return type="bool">
</return>
<description>
- Returns true if highlight all occurrences is enabled.
+ Returns true if the context menu is enabled.
</description>
</method>
- </method>
- <method name="is_context_menu_enabled" qualifiers="const">
+ <method name="is_highlight_all_occurrences_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
- Returns true if the context menu is enabled.
+ Returns true if highlight all occurrences is enabled.
</description>
</method>
<method name="is_highlight_current_line_enabled" qualifiers="const">
@@ -259,6 +258,13 @@
<description>
</description>
</method>
+ <method name="is_readonly" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return true if the text editor is in read-only mode (see [method set_readonly]).
+ </description>
+ </method>
<method name="is_selection_active" qualifiers="const">
<return type="bool">
</return>
@@ -348,7 +354,7 @@
<method name="set_context_menu_enabled">
<return type="void">
</return>
- <argument index="0" name="enabled" type="bool">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
Set the status of the context menu. When enabled, the context menu will appear when the [code]TextEdit[/code] is right clicked.
@@ -464,20 +470,26 @@
</member>
<member name="caret_block_mode" type="bool" setter="cursor_set_block_mode" getter="cursor_is_block_mode">
</member>
+ <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled">
+ </member>
<member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled">
</member>
<member name="highlight_current_line" type="bool" setter="set_highlight_current_line" getter="is_highlight_current_line_enabled">
</member>
<member name="override_selected_font_color" type="bool" setter="set_override_selected_font_color" getter="is_overriding_selected_font_color">
</member>
- <member name="show_line_numbers" type="bool" setter="set_show_line_numbers" getter="is_show_line_numbers_enabled">
+ <member name="readonly" type="bool" setter="set_readonly" getter="is_readonly">
+ If [code]true[/code] read-only mode is enabled. Existing text cannot be modified and new text cannot be added.
</member>
- <member name="context_menu_enabled" type="bool" setter="set_context_menu_enabled" getter="is_context_menu_enabled">
+ <member name="show_line_numbers" type="bool" setter="set_show_line_numbers" getter="is_show_line_numbers_enabled">
</member>
<member name="smooth_scrolling" type="bool" setter="set_smooth_scroll_enable" getter="is_smooth_scroll_enabled">
</member>
<member name="syntax_highlighting" type="bool" setter="set_syntax_coloring" getter="is_syntax_coloring_enabled">
</member>
+ <member name="text" type="String" setter="set_text" getter="get_text">
+ String value of the [TextEdit].
+ </member>
<member name="v_scroll_speed" type="float" setter="set_v_scroll_speed" getter="get_v_scroll_speed">
</member>
</members>
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index c44fa500cd..49eaf5bc31 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -59,6 +59,12 @@
Return true if tiles are to be centered in y coordinate (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
+ <method name="get_clip_uv" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="get_collision_bounce" qualifiers="const">
<return type="float">
</return>
@@ -298,6 +304,14 @@
Set tiles to be centered in y coordinate. (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
+ <method name="set_clip_uv">
+ <return type="void">
+ </return>
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="set_collision_bounce">
<return type="void">
</return>
@@ -450,6 +464,8 @@
</method>
</methods>
<members>
+ <member name="cell_clip_uv" type="bool" setter="set_clip_uv" getter="get_clip_uv">
+ </member>
<member name="cell_custom_transform" type="Transform2D" setter="set_custom_transform" getter="get_custom_transform">
The custom [Transform2D] to be applied to the TileMap's cells.
</member>
diff --git a/doc/classes/ViewportContainer.xml b/doc/classes/ViewportContainer.xml
index d4d42ad4fb..8d5feaec68 100644
--- a/doc/classes/ViewportContainer.xml
+++ b/doc/classes/ViewportContainer.xml
@@ -9,6 +9,12 @@
<demos>
</demos>
<methods>
+ <method name="get_stretch_shrink" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="is_stretch_enabled" qualifiers="const">
<return type="bool">
</return>
@@ -23,10 +29,20 @@
<description>
</description>
</method>
+ <method name="set_stretch_shrink">
+ <return type="void">
+ </return>
+ <argument index="0" name="amount" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="stretch" type="bool" setter="set_stretch" getter="is_stretch_enabled">
</member>
+ <member name="stretch_shrink" type="int" setter="set_stretch_shrink" getter="get_stretch_shrink">
+ </member>
</members>
<constants>
</constants>
diff --git a/doc/classes/VisualScriptBuiltinFunc.xml b/doc/classes/VisualScriptBuiltinFunc.xml
index 5891b24bfd..c896ff6410 100644
--- a/doc/classes/VisualScriptBuiltinFunc.xml
+++ b/doc/classes/VisualScriptBuiltinFunc.xml
@@ -151,64 +151,68 @@
<constant name="MATH_DB2LINEAR" value="39">
Convert the input from decibel volume to linear volume.
</constant>
- <constant name="LOGIC_MAX" value="40">
+ <constant name="MATH_WRAP" value="40">
+ </constant>
+ <constant name="MATH_WRAPF" value="41">
+ </constant>
+ <constant name="LOGIC_MAX" value="42">
Return the greater of the two numbers, also known as their maximum.
</constant>
- <constant name="LOGIC_MIN" value="41">
+ <constant name="LOGIC_MIN" value="43">
Return the lesser of the two numbers, also known as their minimum.
</constant>
- <constant name="LOGIC_CLAMP" value="42">
+ <constant name="LOGIC_CLAMP" value="44">
Return the input clamped inside the given range, ensuring the result is never outside it. Equivalent to `min(max(input, range_low), range_high)`
</constant>
- <constant name="LOGIC_NEAREST_PO2" value="43">
+ <constant name="LOGIC_NEAREST_PO2" value="45">
Return the nearest power of 2 to the input.
</constant>
- <constant name="OBJ_WEAKREF" value="44">
+ <constant name="OBJ_WEAKREF" value="46">
Create a [WeakRef] from the input.
</constant>
- <constant name="FUNC_FUNCREF" value="45">
+ <constant name="FUNC_FUNCREF" value="47">
Create a [FuncRef] from the input.
</constant>
- <constant name="TYPE_CONVERT" value="46">
+ <constant name="TYPE_CONVERT" value="48">
Convert between types.
</constant>
- <constant name="TYPE_OF" value="47">
+ <constant name="TYPE_OF" value="49">
Return the type of the input as an integer. Check [enum Variant.Type] for the integers that might be returned.
</constant>
- <constant name="TYPE_EXISTS" value="48">
+ <constant name="TYPE_EXISTS" value="50">
Checks if a type is registered in the [ClassDB].
</constant>
- <constant name="TEXT_CHAR" value="49">
+ <constant name="TEXT_CHAR" value="51">
Return a character with the given ascii value.
</constant>
- <constant name="TEXT_STR" value="50">
+ <constant name="TEXT_STR" value="52">
Convert the input to a string.
</constant>
- <constant name="TEXT_PRINT" value="51">
+ <constant name="TEXT_PRINT" value="53">
Print the given string to the output window.
</constant>
- <constant name="TEXT_PRINTERR" value="52">
+ <constant name="TEXT_PRINTERR" value="54">
Print the given string to the standard error output.
</constant>
- <constant name="TEXT_PRINTRAW" value="53">
+ <constant name="TEXT_PRINTRAW" value="55">
Print the given string to the standard output, without adding a newline.
</constant>
- <constant name="VAR_TO_STR" value="54">
+ <constant name="VAR_TO_STR" value="56">
Serialize a [Variant] to a string.
</constant>
- <constant name="STR_TO_VAR" value="55">
+ <constant name="STR_TO_VAR" value="57">
Deserialize a [Variant] from a string serialized using [VAR_TO_STR].
</constant>
- <constant name="VAR_TO_BYTES" value="56">
+ <constant name="VAR_TO_BYTES" value="58">
Serialize a [Variant] to a [PoolByteArray].
</constant>
- <constant name="BYTES_TO_VAR" value="57">
+ <constant name="BYTES_TO_VAR" value="59">
Deserialize a [Variant] from a [PoolByteArray] serialized using [VAR_TO_BYTES].
</constant>
- <constant name="COLORN" value="58">
+ <constant name="COLORN" value="60">
Return the [Color] with the given name and alpha ranging from 0 to 1. Note: names are defined in color_names.inc.
</constant>
- <constant name="FUNC_MAX" value="59">
+ <constant name="FUNC_MAX" value="61">
The maximum value the [member function] property can have.
</constant>
</constants>
diff --git a/doc/classes/VisualScriptMathConstant.xml b/doc/classes/VisualScriptMathConstant.xml
index 86744e5caf..c753c16218 100644
--- a/doc/classes/VisualScriptMathConstant.xml
+++ b/doc/classes/VisualScriptMathConstant.xml
@@ -42,12 +42,12 @@
<constant name="MATH_CONSTANT_PI" value="1">
Pi: [code]3.141593[/code]
</constant>
- <constant name="MATH_CONSTANT_2PI" value="2">
- Pi times two: [code]6.283185[/code]
- </constant>
- <constant name="MATH_CONSTANT_HALF_PI" value="3">
+ <constant name="MATH_CONSTANT_HALF_PI" value="2">
Pi divided by two: [code]1.570796[/code]
</constant>
+ <constant name="MATH_CONSTANT_TAU" value="3">
+ Tau: [code]6.283185[/code]
+ </constant>
<constant name="MATH_CONSTANT_E" value="4">
Natural log: [code]2.718282[/code]
</constant>
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 72a3c3256b..220a3533b7 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -168,9 +168,11 @@ void RasterizerGLES3::initialize() {
#ifdef __APPLE__
// FIXME glDebugMessageCallbackARB does not seem to work on Mac OS X and opengl 3, this may be an issue with our opengl canvas..
#else
- glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- glDebugMessageCallbackARB(_gl_debug_print, NULL);
- glEnable(_EXT_DEBUG_OUTPUT);
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ glDebugMessageCallbackARB(_gl_debug_print, NULL);
+ glEnable(_EXT_DEBUG_OUTPUT);
+ }
#endif
#endif
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 9a92e63c0c..0c57e4e9cf 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -4282,7 +4282,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
if (i > 0) {
glEnable(GL_BLEND);
}
- _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL);
+ _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, false, false, i > 0, shadow_atlas != NULL);
}
}
@@ -4345,7 +4345,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
} else {
for (int i = 0; i < state.directional_light_count; i++) {
directional_light = directional_lights[i];
- _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL);
+ _setup_directional_light(i, p_cam_transform.affine_inverse(), shadow_atlas != NULL && shadow_atlas->size > 0);
_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, env_radiance_tex, false, true, false, i > 0, shadow_atlas != NULL);
}
}
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 731d6968ce..4bbb18ce42 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -381,8 +381,7 @@ void main() {
if (clip_rect_uv) {
- vec2 half_texpixel = color_texpixel_size * 0.5;
- uv = clamp(uv,src_rect.xy+half_texpixel,src_rect.xy+abs(src_rect.zw)-color_texpixel_size);
+ uv = clamp(uv,src_rect.xy,src_rect.xy+abs(src_rect.zw));
}
#endif
diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp
index 057b2d827d..533ed48d15 100644
--- a/editor/doc/doc_data.cpp
+++ b/editor/doc/doc_data.cpp
@@ -615,11 +615,6 @@ void DocData::generate(bool p_basic_types) {
}
}
-static String _format_description(const String &string) {
-
- return string.dedent().strip_edges().replace("\n", "\n\n");
-}
-
static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &methods) {
String section = parser->get_node_name();
@@ -666,7 +661,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- method.description = _format_description(parser->get_node_data());
+ method.description = parser->get_node_data();
}
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == element)
@@ -781,20 +776,20 @@ Error DocData::_load(Ref<XMLParser> parser) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.brief_description = _format_description(parser->get_node_data());
+ c.brief_description = parser->get_node_data();
} else if (name == "description") {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.description = _format_description(parser->get_node_data());
+ c.description = parser->get_node_data();
} else if (name == "tutorials") {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.tutorials = parser->get_node_data().strip_edges();
+ c.tutorials = parser->get_node_data();
} else if (name == "demos") {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- c.demos = parser->get_node_data().strip_edges();
+ c.demos = parser->get_node_data();
} else if (name == "methods") {
Error err = _parse_methods(parser, c.methods);
@@ -828,7 +823,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
prop.enumeration = parser->get_attribute_value("enum");
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- prop.description = _format_description(parser->get_node_data());
+ prop.description = parser->get_node_data();
c.properties.push_back(prop);
} else {
ERR_EXPLAIN("Invalid tag in doc file: " + name);
@@ -857,7 +852,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
prop.type = parser->get_attribute_value("type");
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- prop.description = parser->get_node_data().strip_edges();
+ prop.description = parser->get_node_data();
c.theme_properties.push_back(prop);
} else {
ERR_EXPLAIN("Invalid tag in doc file: " + name);
@@ -888,7 +883,7 @@ Error DocData::_load(Ref<XMLParser> parser) {
}
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT)
- constant.description = parser->get_node_data().strip_edges();
+ constant.description = parser->get_node_data();
c.constants.push_back(constant);
} else {
ERR_EXPLAIN("Invalid tag in doc file: " + name);
@@ -915,6 +910,8 @@ Error DocData::_load(Ref<XMLParser> parser) {
static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) {
+ if (p_string == "")
+ return;
String tab;
for (int i = 0; i < p_tablevel; i++)
tab += "\t";
@@ -957,20 +954,16 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
header += ">";
_write_string(f, 0, header);
_write_string(f, 1, "<brief_description>");
- if (c.brief_description != "")
- _write_string(f, 2, c.brief_description.xml_escape());
+ _write_string(f, 2, c.brief_description.strip_edges().xml_escape());
_write_string(f, 1, "</brief_description>");
_write_string(f, 1, "<description>");
- if (c.description != "")
- _write_string(f, 2, c.description.xml_escape());
+ _write_string(f, 2, c.description.strip_edges().xml_escape());
_write_string(f, 1, "</description>");
_write_string(f, 1, "<tutorials>");
- if (c.tutorials != "")
- _write_string(f, 2, c.tutorials.xml_escape());
+ _write_string(f, 2, c.tutorials.strip_edges().xml_escape());
_write_string(f, 1, "</tutorials>");
_write_string(f, 1, "<demos>");
- if (c.demos != "")
- _write_string(f, 2, c.demos.xml_escape());
+ _write_string(f, 2, c.demos.strip_edges().xml_escape());
_write_string(f, 1, "</demos>");
_write_string(f, 1, "<methods>");
@@ -1014,8 +1007,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
}
_write_string(f, 3, "<description>");
- if (m.description != "")
- _write_string(f, 4, m.description.xml_escape());
+ _write_string(f, 4, m.description.strip_edges().xml_escape());
_write_string(f, 3, "</description>");
_write_string(f, 2, "</method>");
@@ -1036,8 +1028,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
}
PropertyDoc &p = c.properties[i];
_write_string(f, 2, "<member name=\"" + p.name + "\" type=\"" + p.type + "\" setter=\"" + p.setter + "\" getter=\"" + p.getter + "\"" + enum_text + ">");
- if (p.description != "")
- _write_string(f, 3, p.description.xml_escape());
+ _write_string(f, 3, p.description.strip_edges().xml_escape());
_write_string(f, 2, "</member>");
}
_write_string(f, 1, "</members>");
@@ -1060,8 +1051,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
}
_write_string(f, 3, "<description>");
- if (m.description != "")
- _write_string(f, 4, m.description.xml_escape());
+ _write_string(f, 4, m.description.strip_edges().xml_escape());
_write_string(f, 3, "</description>");
_write_string(f, 2, "</signal>");
@@ -1080,8 +1070,7 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri
} else {
_write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
}
- if (k.description != "")
- _write_string(f, 3, k.description.xml_escape());
+ _write_string(f, 3, k.description.strip_edges().xml_escape());
_write_string(f, 2, "</constant>");
}
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index a6fc8dcddf..9e002bc73d 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -821,8 +821,6 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
scan_actions.push_back(ia);
}
}
-
- EditorResourcePreview::get_singleton()->check_for_invalidation(p_dir->get_file_path(i));
}
for (int i = 0; i < p_dir->subdirs.size(); i++) {
@@ -1266,7 +1264,6 @@ void EditorFileSystem::update_file(const String &p_file) {
fs->files[cpos]->deps = _get_dependencies(p_file);
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
- EditorResourcePreview::get_singleton()->call_deferred("check_for_invalidation", p_file);
call_deferred("emit_signal", "filesystem_changed"); //update later
}
@@ -1436,6 +1433,8 @@ void EditorFileSystem::_reimport_file(const String &p_file) {
r->set_import_last_modified_time(0);
}
}
+
+ EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
}
void EditorFileSystem::reimport_files(const Vector<String> &p_files) {
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 03cd2c9b6b..bdb621a258 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -1478,9 +1478,10 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
Color font_color_hl = p_rt->get_color("headline_color", "EditorHelp");
Color link_color = p_rt->get_color("accent_color", "Editor").linear_interpolate(font_color_hl, 0.8);
- String bbcode = p_bbcode.replace("\t", " ").replace("\r", " ").strip_edges();
+ String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
List<String> tag_stack;
+ bool code_tag = false;
int pos = 0;
while (pos < bbcode.length()) {
@@ -1491,7 +1492,10 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
brk_pos = bbcode.length();
if (brk_pos > pos) {
- p_rt->add_text(bbcode.substr(pos, brk_pos - pos));
+ String text = bbcode.substr(pos, brk_pos - pos);
+ if (!code_tag)
+ text = text.replace("\n", "\n\n");
+ p_rt->add_text(text);
}
if (brk_pos == bbcode.length())
@@ -1500,7 +1504,11 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
int brk_end = bbcode.find("]", brk_pos + 1);
if (brk_end == -1) {
- p_rt->add_text(bbcode.substr(brk_pos, bbcode.length() - brk_pos));
+
+ String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
+ if (!code_tag)
+ text = text.replace("\n", "\n\n");
+ p_rt->add_text(text);
break;
}
@@ -1509,20 +1517,23 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
if (tag.begins_with("/")) {
bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
- if (tag_stack.size()) {
- }
if (!tag_ok) {
p_rt->add_text("[");
- pos++;
+ pos = brk_pos + 1;
continue;
}
tag_stack.pop_front();
pos = brk_end + 1;
+ code_tag = false;
if (tag != "/img")
p_rt->pop();
+ } else if (code_tag) {
+
+ p_rt->add_text("[");
+ pos = brk_pos + 1;
} else if (tag.begins_with("method ")) {
@@ -1559,6 +1570,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
//use monospace font
p_rt->push_font(doc_code_font);
+ code_tag = true;
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "center") {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0675cf2c75..e0cae7de57 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -284,9 +284,10 @@ void EditorNode::_notification(int p_what) {
if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/editor/always_show_close_button_in_scene_tabs", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY));
property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true)));
- Ref<Theme> theme = create_editor_theme(theme_base->get_theme());
+ Ref<Theme> theme = create_custom_theme(theme_base->get_theme());
theme_base->set_theme(theme);
+ gui_base->set_theme(theme);
gui_base->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles"));
play_button_panel->add_style_override("panel", gui_base->get_stylebox("PlayButtonPanel", "EditorStyles"));
@@ -871,7 +872,7 @@ void EditorNode::_find_node_types(Node *p_node, int &count_2d, int &count_3d) {
_find_node_types(p_node->get_child(i), count_2d, count_3d);
}
-void EditorNode::_save_scene_with_preview(String p_file) {
+void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
EditorProgress save("save", TTR("Saving Scene"), 4);
save.step(TTR("Analyzing"), 0);
@@ -937,7 +938,7 @@ void EditorNode::_save_scene_with_preview(String p_file) {
}
save.step(TTR("Saving Scene"), 4);
- _save_scene(p_file);
+ _save_scene(p_file, p_idx);
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
}
@@ -1095,10 +1096,7 @@ void EditorNode::_dialog_action(String p_file) {
if (file->get_mode() == EditorFileDialog::MODE_SAVE_FILE) {
_save_default_environment();
- if (scene_idx != editor_data.get_edited_scene())
- _save_scene(p_file, scene_idx);
- else
- _save_scene_with_preview(p_file);
+ _save_scene_with_preview(p_file, scene_idx);
if (scene_idx != -1)
_discard_changes();
@@ -1825,7 +1823,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if (scene && scene->get_filename() != "") {
if (scene_idx != editor_data.get_edited_scene())
- _save_scene(scene->get_filename(), scene_idx);
+ _save_scene_with_preview(scene->get_filename(), scene_idx);
else
_save_scene_with_preview(scene->get_filename());
@@ -4691,9 +4689,9 @@ EditorNode::EditorNode() {
theme_base->add_child(gui_base);
gui_base->set_anchors_and_margins_preset(Control::PRESET_WIDE);
- Ref<Theme> theme = create_editor_theme();
+ Ref<Theme> theme = create_custom_theme();
theme_base->set_theme(theme);
- gui_base->set_theme(create_custom_theme());
+ gui_base->set_theme(theme);
gui_base->add_style_override("panel", gui_base->get_stylebox("Background", "EditorStyles"));
resource_preview = memnew(EditorResourcePreview);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 7d0649cef3..81ff886228 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -503,7 +503,7 @@ private:
void _mark_unsaved_scenes();
void _find_node_types(Node *p_node, int &count_2d, int &count_3d);
- void _save_scene_with_preview(String p_file);
+ void _save_scene_with_preview(String p_file, int p_idx = -1);
Map<String, Set<String> > dependency_errors;
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index f92962a4cb..5b4bdb59d3 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -86,7 +86,6 @@ void EditorResourcePreview::_thread_func(void *ud) {
void EditorResourcePreview::_preview_ready(const String &p_str, const Ref<Texture> &p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud) {
- //print_line("preview is ready");
preview_mutex->lock();
String path = p_str;
@@ -121,7 +120,6 @@ Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, c
type = p_item.resource->get_class();
else
type = ResourceLoader::get_resource_type(p_item.path);
- //print_line("resource type is: "+type);
if (type == "")
return Ref<Texture>(); //could not guess type
@@ -144,7 +142,6 @@ Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, c
if (!p_item.resource.is_valid()) {
// cache the preview in case it's a resource on disk
if (generated.is_valid()) {
- //print_line("was generated");
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
//wow it generated a preview... save cache
@@ -164,15 +161,11 @@ Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem &p_item, c
void EditorResourcePreview::_thread() {
- //print_line("begin thread");
while (!exit) {
- //print_line("wait for semaphore");
preview_sem->wait();
preview_mutex->lock();
- //print_line("blue team go");
-
if (queue.size()) {
QueueItem item = queue.front()->get();
@@ -189,12 +182,11 @@ void EditorResourcePreview::_thread() {
preview_mutex->unlock();
} else {
+
preview_mutex->unlock();
Ref<ImageTexture> texture;
- //print_line("pop from queue "+item.path);
-
int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size");
thumbnail_size *= EDSCALE;
@@ -304,7 +296,6 @@ void EditorResourcePreview::queue_edited_resource_preview(const Ref<Resource> &p
cache.erase(path_id); //erase if exists, since it will be regen
- //print_line("send to thread "+p_path);
QueueItem item;
item.function = p_receiver_func;
item.id = p_receiver->get_instance_id();
@@ -328,7 +319,6 @@ void EditorResourcePreview::queue_resource_preview(const String &p_path, Object
return;
}
- //print_line("send to thread "+p_path);
QueueItem item;
item.function = p_receiver_func;
item.id = p_receiver->get_instance_id();
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index ffa978e194..0f9f50095d 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -582,7 +582,22 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color_disabled", "CheckButton", font_color_disabled);
theme->set_color("icon_color_hover", "CheckButton", font_color_hl);
+ theme->set_constant("hseparation", "CheckButton", 4 * EDSCALE);
+ theme->set_constant("check_vadjust", "CheckButton", 0 * EDSCALE);
+
// Checkbox
+ Ref<StyleBoxFlat> sb_checkbox = style_menu->duplicate();
+ // HACK, in reality, the checkbox draws the text over the icon by default, so the margin compensates that.
+ const int cb_w = theme->get_icon("GuiChecked", "EditorIcons")->get_width() + default_margin_size;
+ sb_checkbox->set_default_margin(MARGIN_LEFT, cb_w * EDSCALE);
+ sb_checkbox->set_default_margin(MARGIN_RIGHT, default_margin_size * EDSCALE);
+ sb_checkbox->set_default_margin(MARGIN_TOP, default_margin_size * EDSCALE);
+ sb_checkbox->set_default_margin(MARGIN_BOTTOM, default_margin_size * EDSCALE);
+
+ theme->set_stylebox("normal", "CheckBox", sb_checkbox);
+ theme->set_stylebox("pressed", "CheckBox", sb_checkbox);
+ theme->set_stylebox("disabled", "CheckBox", sb_checkbox);
+ theme->set_stylebox("hover", "CheckBox", sb_checkbox);
theme->set_icon("checked", "CheckBox", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "CheckBox", theme->get_icon("GuiUnchecked", "EditorIcons"));
theme->set_icon("radio_checked", "CheckBox", theme->get_icon("GuiRadioChecked", "EditorIcons"));
@@ -594,6 +609,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_color_disabled", "CheckBox", font_color_disabled);
theme->set_color("icon_color_hover", "CheckBox", font_color_hl);
+ theme->set_constant("hseparation", "CheckBox", 4 * EDSCALE);
+ theme->set_constant("check_vadjust", "CheckBox", 0 * EDSCALE);
+
// PopupMenu
Ref<StyleBoxFlat> style_popup_menu = style_popup;
theme->set_stylebox("panel", "PopupMenu", style_popup_menu);
@@ -1049,12 +1067,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
return theme;
}
-Ref<Theme> create_custom_theme() {
- Ref<Theme> theme = create_editor_theme();
+Ref<Theme> create_custom_theme(const Ref<Theme> p_theme) {
+ Ref<Theme> theme;
String custom_theme = EditorSettings::get_singleton()->get("interface/theme/custom_theme");
if (custom_theme != "") {
theme = ResourceLoader::load(custom_theme);
+ } else {
+ theme = create_editor_theme(p_theme);
}
String global_font = EditorSettings::get_singleton()->get("interface/editor/custom_font");
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index a644c5936f..6f3b83e0b0 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -34,6 +34,6 @@
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = NULL);
-Ref<Theme> create_custom_theme();
+Ref<Theme> create_custom_theme(Ref<Theme> p_theme = NULL);
#endif
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 9314839768..7abddb9f67 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -333,7 +333,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) {
} else if (dirAccess->dir_exists(p_path)) {
path = p_path;
} else {
- ERR_EXPLAIN(TTR("Cannot navigate to '" + p_path + "' as it has not been found in the file system!"));
+ ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path));
ERR_FAIL();
}
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index 831eb74b66..397bb6ad68 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -1,5 +1,6 @@
#include "editor_scene_importer_gltf.h"
#include "io/json.h"
+#include "math_defs.h"
#include "os/file_access.h"
#include "os/os.h"
#include "scene/3d/camera.h"
@@ -1378,8 +1379,8 @@ Error EditorSceneImporterGLTF::_parse_skins(GLTFState &state) {
state.nodes[skin_node]->skeleton_children.push_back(i);
}
- state.skins.push_back(skin);
}
+ state.skins.push_back(skin);
}
print_line("total skins: " + itos(state.skins.size()));
@@ -1419,7 +1420,8 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) {
camera.perspective = true;
if (d.has("perspective")) {
Dictionary ppt = d["perspective"];
- camera.fov_size = ppt["yfov"];
+ // GLTF spec is in radians, Godot's camera is in degrees.
+ camera.fov_size = (double)ppt["yfov"] * 180.0 / Math_PI;
camera.zfar = ppt["zfar"];
camera.znear = ppt["znear"];
} else {
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index e52f3bab72..84d55b4d14 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -87,23 +87,7 @@ void ImportDock::set_edit_path(const String &p_path) {
return;
}
- List<ResourceImporter::ImportOption> options;
- params->importer->get_import_options(&options);
-
- params->properties.clear();
- params->values.clear();
-
- for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
-
- params->properties.push_back(E->get().option);
- if (config->has_section_key("params", E->get().option.name)) {
- params->values[E->get().option.name] = config->get_value("params", E->get().option.name);
- } else {
- params->values[E->get().option.name] = E->get().default_value;
- }
- }
-
- params->update();
+ _update_options(config);
List<Ref<ResourceImporter> > importers;
ResourceFormatImporter::get_singleton()->get_importers_for_extension(p_path.get_extension(), &importers);
@@ -125,6 +109,34 @@ void ImportDock::set_edit_path(const String &p_path) {
}
}
+ params->paths.clear();
+ params->paths.push_back(p_path);
+ import->set_disabled(false);
+ import_as->set_disabled(false);
+
+ imported->set_text(p_path.get_file());
+}
+
+void ImportDock::_update_options(const Ref<ConfigFile> &p_config) {
+
+ List<ResourceImporter::ImportOption> options;
+ params->importer->get_import_options(&options);
+
+ params->properties.clear();
+ params->values.clear();
+
+ for (List<ResourceImporter::ImportOption>::Element *E = options.front(); E; E = E->next()) {
+
+ params->properties.push_back(E->get().option);
+ if (p_config.is_valid() && p_config->has_section_key("params", E->get().option.name)) {
+ params->values[E->get().option.name] = p_config->get_value("params", E->get().option.name);
+ } else {
+ params->values[E->get().option.name] = E->get().default_value;
+ }
+ }
+
+ params->update();
+
preset->get_popup()->clear();
if (params->importer->get_preset_count() == 0) {
@@ -142,13 +154,6 @@ void ImportDock::set_edit_path(const String &p_path) {
preset->get_popup()->add_separator();
preset->get_popup()->add_item(vformat(TTR("Clear Default for '%s'"), params->importer->get_visible_name()), ITEM_CLEAR_DEFAULT);
}
-
- params->paths.clear();
- params->paths.push_back(p_path);
- import->set_disabled(false);
- import_as->set_disabled(false);
-
- imported->set_text(p_path.get_file());
}
void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
@@ -263,6 +268,24 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) {
imported->set_text(itos(p_paths.size()) + TTR(" Files"));
}
+void ImportDock::_importer_selected(int i_idx) {
+ String name = import_as->get_selected_metadata();
+ Ref<ResourceImporter> importer = ResourceFormatImporter::get_singleton()->get_importer_by_name(name);
+ ERR_FAIL_COND(importer.is_null());
+
+ params->importer = importer;
+
+ Ref<ConfigFile> config;
+ if (params->paths.size()) {
+ config.instance();
+ Error err = config->load(params->paths[0] + ".import");
+ if (err != OK) {
+ config.unref();
+ }
+ }
+ _update_options(config);
+}
+
void ImportDock::_preset_selected(int p_idx) {
int item_id = preset->get_popup()->get_item_id(p_idx);
@@ -336,6 +359,7 @@ void ImportDock::_reimport() {
Error err = config->load(params->paths[i] + ".import");
ERR_CONTINUE(err != OK);
+ config->set_value("remap", "importer", params->importer->get_importer_name());
config->erase_section("params");
for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) {
@@ -367,6 +391,7 @@ void ImportDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_reimport"), &ImportDock::_reimport);
ClassDB::bind_method(D_METHOD("_preset_selected"), &ImportDock::_preset_selected);
+ ClassDB::bind_method(D_METHOD("_importer_selected"), &ImportDock::_importer_selected);
}
void ImportDock::initialize_import_options() const {
@@ -384,6 +409,7 @@ ImportDock::ImportDock() {
HBoxContainer *hb = memnew(HBoxContainer);
add_margin_child(TTR("Import As:"), hb);
import_as = memnew(OptionButton);
+ import_as->connect("item_selected", this, "_importer_selected");
hb->add_child(import_as);
import_as->set_h_size_flags(SIZE_EXPAND_FILL);
preset = memnew(MenuButton);
diff --git a/editor/import_dock.h b/editor/import_dock.h
index 029c458320..28c29e4b20 100644
--- a/editor/import_dock.h
+++ b/editor/import_dock.h
@@ -54,6 +54,8 @@ class ImportDock : public VBoxContainer {
ImportDockParameters *params;
void _preset_selected(int p_idx);
+ void _importer_selected(int i_idx);
+ void _update_options(const Ref<ConfigFile> &p_config = Ref<ConfigFile>());
void _reimport();
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index f2f913d2b3..736e176ab8 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -563,6 +563,14 @@ void AbstractPolygon2DEditor::forward_draw_over_canvas(Control *p_canvas) {
const Vector2 next_point = xform.xform(p2);
vpc->draw_line(point, next_point, col, 2);
}
+ }
+
+ for (int i = 0; i < n_points; i++) {
+
+ const Vertex vertex(j, i);
+
+ const Vector2 p = (vertex == edited_point) ? edited_point.pos : (points[i] + offset);
+ const Vector2 point = xform.xform(p);
Ref<Texture> handle = vertex == active_point ? selected_handle : default_handle;
vpc->draw_texture(handle, point - handle->get_size() * 0.5);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 16564ce45f..38467369db 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -4373,11 +4373,11 @@ void CanvasItemEditorViewport::_on_mouse_exit() {
void CanvasItemEditorViewport::_on_select_type(Object *selected) {
CheckBox *check = Object::cast_to<CheckBox>(selected);
String type = check->get_text();
- selector_label->set_text(vformat(TTR("Add %s"), type));
+ selector->set_title(vformat(TTR("Add %s"), type));
label->set_text(vformat(TTR("Adding %s..."), type));
}
-void CanvasItemEditorViewport::_on_change_type() {
+void CanvasItemEditorViewport::_on_change_type_confirmed() {
if (!button_group->get_pressed_button())
return;
@@ -4387,6 +4387,11 @@ void CanvasItemEditorViewport::_on_change_type() {
selector->hide();
}
+void CanvasItemEditorViewport::_on_change_type_closed() {
+
+ _remove_preview();
+}
+
void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) const {
label->set_position(get_global_position() + Point2(14, 14) * EDSCALE);
label_desc->set_position(label->get_position() + Point2(0, label->get_size().height));
@@ -4698,7 +4703,7 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
CheckBox *check = Object::cast_to<CheckBox>(btn_list[i]);
check->set_pressed(check->get_text() == default_type);
}
- selector_label->set_text(vformat(TTR("Add %s"), default_type));
+ selector->set_title(vformat(TTR("Add %s"), default_type));
selector->popup_centered_minsize();
} else {
_perform_drop_data();
@@ -4721,7 +4726,8 @@ void CanvasItemEditorViewport::_notification(int p_what) {
void CanvasItemEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("_on_select_type"), &CanvasItemEditorViewport::_on_select_type);
- ClassDB::bind_method(D_METHOD("_on_change_type"), &CanvasItemEditorViewport::_on_change_type);
+ ClassDB::bind_method(D_METHOD("_on_change_type_confirmed"), &CanvasItemEditorViewport::_on_change_type_confirmed);
+ ClassDB::bind_method(D_METHOD("_on_change_type_closed"), &CanvasItemEditorViewport::_on_change_type_closed);
ClassDB::bind_method(D_METHOD("_on_mouse_exit"), &CanvasItemEditorViewport::_on_mouse_exit);
}
@@ -4749,7 +4755,8 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
selector = memnew(AcceptDialog);
editor->get_gui_base()->add_child(selector);
selector->set_title(TTR("Change default type"));
- selector->connect("confirmed", this, "_on_change_type");
+ selector->connect("confirmed", this, "_on_change_type_confirmed");
+ selector->connect("popup_hide", this, "_on_change_type_closed");
VBoxContainer *vbc = memnew(VBoxContainer);
selector->add_child(vbc);
@@ -4757,12 +4764,6 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
vbc->set_v_size_flags(SIZE_EXPAND_FILL);
vbc->set_custom_minimum_size(Size2(200, 260) * EDSCALE);
- selector_label = memnew(Label);
- vbc->add_child(selector_label);
- selector_label->set_align(Label::ALIGN_CENTER);
- selector_label->set_valign(Label::VALIGN_BOTTOM);
- selector_label->set_custom_minimum_size(Size2(0, 30) * EDSCALE);
-
btn_group = memnew(VBoxContainer);
vbc->add_child(btn_group);
btn_group->set_h_size_flags(0);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 97e3b03569..457833e1a7 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -568,7 +568,8 @@ class CanvasItemEditorViewport : public Control {
void _on_mouse_exit();
void _on_select_type(Object *selected);
- void _on_change_type();
+ void _on_change_type_confirmed();
+ void _on_change_type_closed();
void _create_preview(const Vector<String> &files) const;
void _remove_preview();
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index a1183307fb..607ccaa4e7 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -865,20 +865,7 @@ void ScriptEditor::_menu_option(int p_option) {
} break;
case SEARCH_CLASSES: {
- String current;
-
- if (tab_container->get_tab_count() > 0) {
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(tab_container->get_current_tab()));
- if (eh) {
- current = eh->get_class();
- }
- }
-
help_index->popup();
-
- if (current != "") {
- help_index->call_deferred("select_class", current);
- }
} break;
case SEARCH_WEBSITE: {
@@ -890,8 +877,13 @@ void ScriptEditor::_menu_option(int p_option) {
_history_forward();
} break;
case WINDOW_PREV: {
+
_history_back();
} break;
+ case WINDOW_SORT: {
+ _sort_list_on_update = true;
+ _update_script_names();
+ } break;
case DEBUG_SHOW: {
if (debugger) {
bool visible = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(DEBUG_SHOW));
@@ -926,10 +918,6 @@ void ScriptEditor::_menu_option(int p_option) {
if (current) {
switch (p_option) {
- case FILE_NEW: {
- script_create_dialog->config("Node", ".gd");
- script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE);
- } break;
case FILE_SAVE: {
if (_test_script_times_on_disk())
@@ -1041,26 +1029,22 @@ void ScriptEditor::_menu_option(int p_option) {
debugger->debug_continue();
} break;
- case WINDOW_MOVE_LEFT: {
+ case WINDOW_MOVE_UP: {
if (tab_container->get_current_tab() > 0) {
- tab_container->call_deferred("set_current_tab", tab_container->get_current_tab() - 1);
- script_list->call_deferred("select", tab_container->get_current_tab() - 1);
tab_container->move_child(current, tab_container->get_current_tab() - 1);
+ tab_container->set_current_tab(tab_container->get_current_tab() - 1);
_update_script_names();
}
} break;
- case WINDOW_MOVE_RIGHT: {
+ case WINDOW_MOVE_DOWN: {
if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
- tab_container->call_deferred("set_current_tab", tab_container->get_current_tab() + 1);
- script_list->call_deferred("select", tab_container->get_current_tab() + 1);
tab_container->move_child(current, tab_container->get_current_tab() + 1);
+ tab_container->set_current_tab(tab_container->get_current_tab() + 1);
_update_script_names();
}
-
} break;
-
default: {
if (p_option >= WINDOW_SELECT_BASE) {
@@ -1077,6 +1061,11 @@ void ScriptEditor::_menu_option(int p_option) {
switch (p_option) {
+ case SEARCH_CLASSES: {
+
+ help_index->popup();
+ help_index->call_deferred("select_class", help->get_class());
+ } break;
case HELP_SEARCH_FIND: {
help->popup_search();
} break;
@@ -1092,6 +1081,22 @@ void ScriptEditor::_menu_option(int p_option) {
case CLOSE_ALL: {
_close_all_tabs();
} break;
+ case WINDOW_MOVE_UP: {
+
+ if (tab_container->get_current_tab() > 0) {
+ tab_container->move_child(help, tab_container->get_current_tab() - 1);
+ tab_container->set_current_tab(tab_container->get_current_tab() - 1);
+ _update_script_names();
+ }
+ } break;
+ case WINDOW_MOVE_DOWN: {
+
+ if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
+ tab_container->move_child(help, tab_container->get_current_tab() + 1);
+ tab_container->set_current_tab(tab_container->get_current_tab() + 1);
+ _update_script_names();
+ }
+ } break;
}
}
}
@@ -1361,6 +1366,7 @@ struct _ScriptEditorItemData {
String tooltip;
bool used;
int category;
+ Node *ref;
bool operator<(const _ScriptEditorItemData &id) const {
@@ -1526,6 +1532,7 @@ void ScriptEditor::_update_script_names() {
sd.index = i;
sd.used = used.has(se->get_edited_script());
sd.category = 0;
+ sd.ref = se;
switch (sort_by) {
case SORT_BY_NAME: {
@@ -1565,16 +1572,38 @@ void ScriptEditor::_update_script_names() {
_ScriptEditorItemData sd;
sd.icon = icon;
sd.name = name;
- sd.sort_key = name;
+ sd.sort_key = name.to_lower();
sd.tooltip = tooltip;
sd.index = i;
sd.used = false;
sd.category = split_script_help ? 1 : 0;
+ sd.ref = eh;
+
sedata.push_back(sd);
}
}
- sedata.sort();
+ if (_sort_list_on_update) {
+ sedata.sort();
+
+ // change actual order of tab_container so that the order can be rearranged by user
+ int cur_tab = tab_container->get_current_tab();
+ int prev_tab = tab_container->get_previous_tab();
+ int new_cur_tab = -1;
+ int new_prev_tab = -1;
+ for (int i = 0; i < sedata.size(); i++) {
+ tab_container->move_child(sedata[i].ref, i);
+ if (new_prev_tab == -1 && sedata[i].index == prev_tab) {
+ new_prev_tab = i;
+ }
+ if (new_cur_tab == -1 && sedata[i].index == cur_tab) {
+ new_cur_tab = i;
+ }
+ }
+ tab_container->call_deferred("set_current_tab", new_prev_tab);
+ tab_container->call_deferred("set_current_tab", new_cur_tab);
+ _sort_list_on_update = false;
+ }
for (int i = 0; i < sedata.size(); i++) {
@@ -1903,8 +1932,171 @@ void ScriptEditor::_script_split_dragged(float) {
_save_layout();
}
+Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+
+ // return Variant(); // return this if drag disabled
+
+ Node *cur_node = tab_container->get_child(tab_container->get_current_tab());
+
+ HBoxContainer *drag_preview = memnew(HBoxContainer);
+ String preview_name = "";
+ Ref<Texture> preview_icon;
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(cur_node);
+ if (se) {
+ preview_name = se->get_name();
+ preview_icon = se->get_icon();
+ }
+ EditorHelp *eh = Object::cast_to<EditorHelp>(cur_node);
+ if (eh) {
+ preview_name = eh->get_class();
+ preview_icon = get_icon("Help", "EditorIcons");
+ }
+
+ if (!preview_icon.is_null()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(preview_icon);
+ drag_preview->add_child(tf);
+ }
+ Label *label = memnew(Label(preview_name));
+ drag_preview->add_child(label);
+ set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "script_list_element"; // using a custom type because node caused problems when dragging to scene tree
+ drag_data["script_list_element"] = cur_node;
+
+ return drag_data;
+}
+
+bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return false;
+
+ if (String(d["type"]) == "script_list_element") {
+
+ Node *node = d["script_list_element"];
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
+ if (se) {
+ return true;
+ }
+ EditorHelp *eh = Object::cast_to<EditorHelp>(node);
+ if (eh) {
+ return true;
+ }
+ }
+
+ if (String(d["type"]) == "nodes") {
+
+ Array nodes = d["nodes"];
+ if (nodes.size() == 0)
+ return false;
+ Node *node = get_node((nodes[0]));
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
+ if (se) {
+ return true;
+ }
+ EditorHelp *eh = Object::cast_to<EditorHelp>(node);
+ if (eh) {
+ return true;
+ }
+ }
+
+ if (String(d["type"]) == "files") {
+
+ Vector<String> files = d["files"];
+
+ if (files.size() == 0)
+ return false; //weird
+
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (file == "" || !FileAccess::exists(file))
+ continue;
+ Ref<Script> scr = ResourceLoader::load(file);
+ if (scr.is_valid()) {
+ return true;
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
+
+ if (!can_drop_data_fw(p_point, p_data, p_from))
+ return;
+
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return;
+
+ if (String(d["type"]) == "script_list_element") {
+
+ Node *node = d["script_list_element"];
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
+ EditorHelp *eh = Object::cast_to<EditorHelp>(node);
+ if (se || eh) {
+ int new_index = script_list->get_item_at_position(p_point);
+ tab_container->move_child(node, new_index);
+ tab_container->set_current_tab(new_index);
+ _update_script_names();
+ }
+ }
+
+ if (String(d["type"]) == "nodes") {
+
+ Array nodes = d["nodes"];
+ if (nodes.size() == 0)
+ return;
+ Node *node = get_node(nodes[0]);
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(node);
+ EditorHelp *eh = Object::cast_to<EditorHelp>(node);
+ if (se || eh) {
+ int new_index = script_list->get_item_at_position(p_point);
+ tab_container->move_child(node, new_index);
+ tab_container->set_current_tab(new_index);
+ _update_script_names();
+ }
+ }
+
+ if (String(d["type"]) == "files") {
+
+ Vector<String> files = d["files"];
+
+ int new_index = script_list->get_item_at_position(p_point);
+ int num_tabs_before = tab_container->get_child_count();
+ for (int i = 0; i < files.size(); i++) {
+ String file = files[i];
+ if (file == "" || !FileAccess::exists(file))
+ continue;
+ Ref<Script> scr = ResourceLoader::load(file);
+ if (scr.is_valid()) {
+ edit(scr);
+ if (tab_container->get_child_count() > num_tabs_before) {
+ tab_container->move_child(tab_container->get_child(tab_container->get_child_count() - 1), new_index);
+ num_tabs_before = tab_container->get_child_count();
+ } else {
+ tab_container->move_child(tab_container->get_child(tab_container->get_current_tab()), new_index);
+ }
+ }
+ }
+ tab_container->set_current_tab(new_index);
+ _update_script_names();
+ }
+}
+
void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
- if (p_event->is_pressed() || !is_visible_in_tree()) return;
+ if (!is_visible_in_tree() || !p_event->is_pressed() || p_event->is_echo())
+ return;
if (ED_IS_SHORTCUT("script_editor/next_script", p_event)) {
int next_tab = script_list->get_current() + 1;
next_tab %= script_list->get_item_count();
@@ -1917,6 +2109,62 @@ void ScriptEditor::_unhandled_input(const Ref<InputEvent> &p_event) {
_go_to_tab(script_list->get_item_metadata(next_tab));
_update_script_names();
}
+ if (ED_IS_SHORTCUT("script_editor/window_move_up", p_event)) {
+ _menu_option(WINDOW_MOVE_UP);
+ }
+ if (ED_IS_SHORTCUT("script_editor/window_move_down", p_event)) {
+ _menu_option(WINDOW_MOVE_DOWN);
+ }
+}
+
+void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) {
+
+ Ref<InputEventMouseButton> mb = ev;
+ if (mb.is_valid() && mb->get_button_index() == BUTTON_RIGHT && mb->is_pressed()) {
+
+ _make_script_list_context_menu();
+ }
+}
+
+void ScriptEditor::_make_script_list_context_menu() {
+
+ context_menu->clear();
+
+ int selected = tab_container->get_current_tab();
+ if (selected < 0 || selected >= tab_container->get_child_count())
+ return;
+
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
+ if (se) {
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save"), FILE_SAVE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save_as"), FILE_SAVE_AS);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE);
+ context_menu->add_separator();
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT);
+
+ Ref<Script> scr = se->get_edited_script();
+ if (!scr.is_null() && scr->is_tool()) {
+ context_menu->add_separator();
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN);
+ }
+ } else {
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE);
+ }
+
+ EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected));
+ if (eh) {
+ // nothing
+ }
+
+ context_menu->add_separator();
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_down"), WINDOW_MOVE_DOWN);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_sort"), WINDOW_SORT);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL);
+
+ context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+ context_menu->set_size(Vector2(1, 1));
+ context_menu->popup();
}
void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
@@ -2243,9 +2491,14 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method("_history_back", &ScriptEditor::_history_back);
ClassDB::bind_method("_live_auto_reload_running_scripts", &ScriptEditor::_live_auto_reload_running_scripts);
ClassDB::bind_method("_unhandled_input", &ScriptEditor::_unhandled_input);
+ ClassDB::bind_method("_script_list_gui_input", &ScriptEditor::_script_list_gui_input);
ClassDB::bind_method("_script_changed", &ScriptEditor::_script_changed);
ClassDB::bind_method("_update_recent_scripts", &ScriptEditor::_update_recent_scripts);
+ ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ScriptEditor::get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ScriptEditor::can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("drop_data_fw"), &ScriptEditor::drop_data_fw);
+
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
@@ -2287,6 +2540,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
script_split->set_split_offset(140);
//list_split->set_split_offset(500);
+ _sort_list_on_update = true;
+ script_list->connect("gui_input", this, "_script_list_gui_input");
+ script_list->set_allow_rmb_select(true);
+ script_list->set_drag_forwarding(this);
+
+ context_menu = memnew(PopupMenu);
+ add_child(context_menu);
+ context_menu->connect("id_pressed", this, "_menu_option");
+
members_overview = memnew(ItemList);
list_split->add_child(members_overview);
members_overview->set_custom_minimum_size(Size2(0, 100)); //need to give a bit of limit to avoid it from disappearing
@@ -2303,8 +2565,11 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
- ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_GREATER);
- ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_LESS);
+ ED_SHORTCUT("script_editor/window_sort", TTR("Sort"));
+ ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP);
+ ED_SHORTCUT("script_editor/window_move_down", TTR("Move Down"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_DOWN);
+ ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_PERIOD); // these should be KEY_GREATER and KEY_LESS but those don't work
+ ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_COLON);
set_process_unhandled_input(true);
file_menu = memnew(MenuButton);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 03fc4da7ce..b8317f9e86 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -150,10 +150,11 @@ class ScriptEditor : public PanelContainer {
SEARCH_WEBSITE,
HELP_SEARCH_FIND,
HELP_SEARCH_FIND_NEXT,
- WINDOW_MOVE_LEFT,
- WINDOW_MOVE_RIGHT,
+ WINDOW_MOVE_UP,
+ WINDOW_MOVE_DOWN,
WINDOW_NEXT,
WINDOW_PREV,
+ WINDOW_SORT,
WINDOW_SELECT_BASE = 100
};
@@ -173,6 +174,7 @@ class ScriptEditor : public PanelContainer {
MenuButton *edit_menu;
MenuButton *script_search_menu;
MenuButton *debug_menu;
+ PopupMenu *context_menu;
Timer *autosave_timer;
uint64_t idle;
@@ -292,6 +294,7 @@ class ScriptEditor : public PanelContainer {
void _update_members_overview_visibility();
void _update_members_overview();
void _update_script_names();
+ bool _sort_list_on_update;
void _members_overview_selected(int p_idx);
void _script_selected(int p_idx);
@@ -306,8 +309,15 @@ class ScriptEditor : public PanelContainer {
void _script_split_dragged(float);
+ Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
+ bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
+
void _unhandled_input(const Ref<InputEvent> &p_event);
+ void _script_list_gui_input(const Ref<InputEvent> &ev);
+ void _make_script_list_context_menu();
+
void _help_search(String p_text);
void _help_index(String p_text);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index e8714cece6..b87084e392 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -1255,7 +1255,6 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 motion_mask;
Plane plane;
- bool plane_mv;
switch (_edit.plane) {
case TRANSFORM_VIEW:
@@ -1300,7 +1299,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && motion_mask != Vector3()); // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1309,10 +1308,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 motion_snapped = motion;
motion_snapped.snap(Vector3(snap, snap, snap));
- set_message(TTR("Scaling XYZ: ") + motion_snapped);
+ set_message(TTR("Scaling: ") + motion_snapped);
} else {
- set_message(TTR("Scaling XYZ: ") + motion);
+ set_message(TTR("Scaling: ") + motion);
}
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
@@ -1376,7 +1375,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
Vector3 motion_mask;
Plane plane;
- bool plane_mv;
+ bool plane_mv = false;
switch (_edit.plane) {
case TRANSFORM_VIEW:
@@ -1426,7 +1425,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && motion_mask != Vector3()); // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1536,7 +1535,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = spatial_editor->are_local_coords_enabled();
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
@@ -2917,7 +2916,9 @@ bool SpatialEditorViewport::_create_instance(Node *parent, String &path, const P
}
}
- instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
+ if (scene != NULL) {
+ instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path));
+ }
editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene);
editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene());
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index eac5720b43..dda2851166 100644
--- a/editor/project_export.cpp
+++ b/editor/project_export.cpp
@@ -308,7 +308,7 @@ void ProjectExportDialog::_patch_button_pressed(Object *p_item, int p_column, in
if (p_id == 0) {
Vector<String> patches = current->get_patches();
ERR_FAIL_INDEX(patch_index, patches.size());
- patch_erase->set_text(vformat(TTR("Delete patch '" + patches[patch_index].get_file() + "' from list?")));
+ patch_erase->set_text(vformat(TTR("Delete patch '%s' from list?"), patches[patch_index].get_file()));
patch_erase->popup_centered_minsize();
} else {
patch_dialog->popup_centered_ratio();
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 340ea708b4..b07280a4cd 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -785,12 +785,12 @@ void ProjectSettingsEditor::_item_del() {
String property = globals_editor->get_current_section().plus_file(path);
if (!ProjectSettings::get_singleton()->has_setting(property)) {
- EditorNode::get_singleton()->show_warning(TTR("No property '" + property + "' exists."));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("No property '%s' exists."), property));
return;
}
if (ProjectSettings::get_singleton()->get_order(property) < ProjectSettings::NO_BUILTIN_ORDER_BASE) {
- EditorNode::get_singleton()->show_warning(TTR("Setting '" + property + "' is internal, and it can't be deleted."));
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Setting '%s' is internal, and it can't be deleted."), property));
return;
}
@@ -1782,6 +1782,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
tab_container->add_child(translations);
//remap for properly select language in popup
translation_locales_idxs_remap = Vector<int>();
+ translation_locales_list_created = false;
{
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 58f70ce11e..7ada335007 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -860,6 +860,14 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node *, Node *> &duplimap) {
node->set(name, value);
}
+ List<Connection> conns;
+ p_node->get_all_signal_connections(&conns);
+ for (List<Connection>::Element *E = conns.front(); E; E = E->next()) {
+ if (E->get().flags & CONNECT_PERSIST) {
+ node->connect(E->get().signal, E->get().target, E->get().method, E->get().binds, E->get().flags);
+ }
+ }
+
List<Node::GroupInfo> group_info;
p_node->get_groups(&group_info);
for (List<Node::GroupInfo>::Element *E = group_info.front(); E; E = E->next()) {
@@ -1296,6 +1304,7 @@ void SceneTreeDock::_delete_confirm() {
editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", (Object *)NULL);
editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", edited_scene);
editor_data->get_undo_redo().add_undo_method(edited_scene, "set_owner", edited_scene->get_owner());
+ editor_data->get_undo_redo().add_undo_method(scene_tree, "update_tree");
editor_data->get_undo_redo().add_undo_reference(edited_scene);
} else {
diff --git a/misc/travis/android-tools-linux.sh b/misc/travis/android-tools-linux.sh
new file mode 100755
index 0000000000..04fb2eee21
--- /dev/null
+++ b/misc/travis/android-tools-linux.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+# SDK
+# https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
+# SHA-256 444e22ce8ca0f67353bda4b85175ed3731cae3ffa695ca18119cbacef1c1bea0
+# latest version available here: https://developer.android.com/studio/index.html
+
+# NDK
+# https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip
+# SHA-1 0bf02d4e8b85fd770fd7b9b2cdec57f9441f27a2
+# latest version available here: https://developer.android.com/ndk/downloads/index.html
+
+BASH_RC=~/.bashrc
+GODOT_BUILD_TOOLS_PATH=./godot-dev/build-tools
+mkdir -p $GODOT_BUILD_TOOLS_PATH
+cd $GODOT_BUILD_TOOLS_PATH
+
+ANDROID_BASE_URL=http://dl.google.com/android/repository
+
+ANDROID_SDK_RELEASE=3859397
+ANDROID_SDK_DIR=android-sdk
+ANDROID_SDK_FILENAME=sdk-tools-linux-$ANDROID_SDK_RELEASE.zip
+ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME
+ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR
+ANDROID_SDK_SHA256=444e22ce8ca0f67353bda4b85175ed3731cae3ffa695ca18119cbacef1c1bea0
+
+ANDROID_NDK_RELEASE=r15c
+ANDROID_NDK_DIR=android-ndk
+ANDROID_NDK_FILENAME=android-ndk-$ANDROID_NDK_RELEASE-linux-x86_64.zip
+ANDROID_NDK_URL=$ANDROID_BASE_URL/$ANDROID_NDK_FILENAME
+ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR
+ANDROID_NDK_SHA1=0bf02d4e8b85fd770fd7b9b2cdec57f9441f27a2
+
+echo
+echo "Download and install Android development tools ..."
+echo
+
+if [ ! -e $ANDROID_SDK_FILENAME ]; then
+ echo "Downloading: Android SDK ..."
+ curl -L -O $ANDROID_SDK_URL
+else
+ echo $ANDROID_SDK_SHA1 $ANDROID_SDK_FILENAME > $ANDROID_SDK_FILENAME.sha1
+ if [ $(shasum -a 256 < $ANDROID_SDK_FILENAME | awk '{print $1;}') != $ANDROID_SDK_SHA1 ]; then
+ echo "Downloading: Android SDK ..."
+ curl -L -O $ANDROID_SDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_SDK_DIR ]; then
+ echo "Extracting: Android SDK ..."
+ unzip -qq $ANDROID_SDK_FILENAME -d $ANDROID_SDK_DIR
+ echo
+fi
+
+if [ ! -e $ANDROID_NDK_FILENAME ]; then
+ echo "Downloading: Android NDK ..."
+ curl -L -O $ANDROID_NDK_URL
+else
+ echo $ANDROID_NDK_MD5 $ANDROID_NDK_FILENAME > $ANDROID_NDK_FILENAME.md5
+ if [ $(shasum -a 1 < $ANDROID_NDK_FILENAME | awk '{print $1;}') != $ANDROID_NDK_SHA1 ]; then
+ echo "Downloading: Android NDK ..."
+ curl -L -O $ANDROID_NDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_NDK_DIR ]; then
+ echo "Extracting: Android NDK ..."
+ unzip -qq $ANDROID_NDK_FILENAME
+ mv android-ndk-$ANDROID_NDK_RELEASE $ANDROID_NDK_DIR
+ echo
+fi
+
+echo "Installing: Android Tools ..."
+#$ANDROID_SDK_DIR/tools/bin/sdkmanager --all
+yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager --licenses > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'tools' > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'platform-tools' > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'build-tools;26.0.2' > /dev/null
+echo
+
+EXPORT_VAL="export ANDROID_HOME=$ANDROID_SDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export ANDROID_NDK_ROOT=$ANDROID_NDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export PATH=$PATH:$ANDROID_SDK_PATH/tools"
+if ! grep -q "^export PATH=.*$ANDROID_SDK_PATH/tools.*" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export PATH=$PATH:$ANDROID_SDK_PATH/tools/bin"
+if ! grep -q "^export PATH=.*$ANDROID_SDK_PATH/tools/bin.*" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+echo
+echo "Done!"
+echo
diff --git a/misc/travis/android-tools-osx.sh b/misc/travis/android-tools-osx.sh
new file mode 100755
index 0000000000..96125a3a3f
--- /dev/null
+++ b/misc/travis/android-tools-osx.sh
@@ -0,0 +1,107 @@
+#!/bin/bash
+
+# SDK
+# https://dl.google.com/android/repository/sdk-tools-darwin-3859397.zip
+# SHA-256 4a81754a760fce88cba74d69c364b05b31c53d57b26f9f82355c61d5fe4b9df9
+# latest version available here: https://developer.android.com/studio/index.html
+
+# NDK
+# https://dl.google.com/android/repository/android-ndk-r15c-darwin-x86_64.zip
+# SHA-1 ea4b5d76475db84745aa8828000d009625fc1f98
+# latest version available here: https://developer.android.com/ndk/downloads/index.html
+
+BASH_RC=~/.bashrc
+GODOT_BUILD_TOOLS_PATH=./godot-dev/build-tools
+mkdir -p $GODOT_BUILD_TOOLS_PATH
+cd $GODOT_BUILD_TOOLS_PATH
+
+ANDROID_BASE_URL=http://dl.google.com/android/repository
+
+ANDROID_SDK_RELEASE=3859397
+ANDROID_SDK_DIR=android-sdk
+ANDROID_SDK_FILENAME=sdk-tools-darwin-$ANDROID_SDK_RELEASE.zip
+ANDROID_SDK_URL=$ANDROID_BASE_URL/$ANDROID_SDK_FILENAME
+ANDROID_SDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_SDK_DIR
+ANDROID_SDK_SHA256=4a81754a760fce88cba74d69c364b05b31c53d57b26f9f82355c61d5fe4b9df9
+
+ANDROID_NDK_RELEASE=r15c
+ANDROID_NDK_DIR=android-ndk
+ANDROID_NDK_FILENAME=android-ndk-$ANDROID_NDK_RELEASE-darwin-x86_64.zip
+ANDROID_NDK_URL=$ANDROID_BASE_URL/$ANDROID_NDK_FILENAME
+ANDROID_NDK_PATH=$GODOT_BUILD_TOOLS_PATH/$ANDROID_NDK_DIR
+ANDROID_NDK_SHA1=ea4b5d76475db84745aa8828000d009625fc1f98
+
+echo
+echo "Download and install Android development tools ..."
+echo
+
+if [ ! -e $ANDROID_SDK_FILENAME ]; then
+ echo "Downloading: Android SDK ..."
+ curl -L -O $ANDROID_SDK_URL
+else
+ echo $ANDROID_SDK_SHA1 $ANDROID_SDK_FILENAME > $ANDROID_SDK_FILENAME.sha1
+ if [ $(shasum -a 256 < $ANDROID_SDK_FILENAME | awk '{print $1;}') != $ANDROID_SDK_SHA1 ]; then
+ echo "Downloading: Android SDK ..."
+ curl -L -O $ANDROID_SDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_SDK_DIR ]; then
+ echo "Extracting: Android SDK ..."
+ mkdir -p $ANDROID_SDK_DIR && tar -xf $ANDROID_SDK_FILENAME -C $ANDROID_SDK_DIR
+ echo
+fi
+
+if [ ! -e $ANDROID_NDK_FILENAME ]; then
+ echo "Downloading: Android NDK ..."
+ curl -L -O $ANDROID_NDK_URL
+else
+ echo $ANDROID_NDK_MD5 $ANDROID_NDK_FILENAME > $ANDROID_NDK_FILENAME.md5
+ if [ $(shasum -a 1 < $ANDROID_NDK_FILENAME | awk '{print $1;}') != $ANDROID_NDK_SHA1 ]; then
+ echo "Downloading: Android NDK ..."
+ curl -L -O $ANDROID_NDK_URL
+ fi
+fi
+
+if [ ! -d $ANDROID_NDK_DIR ]; then
+ echo "Extracting: Android NDK ..."
+ tar -xf $ANDROID_NDK_FILENAME
+ mv android-ndk-$ANDROID_NDK_RELEASE $ANDROID_NDK_DIR
+ echo
+fi
+
+echo "Installing: Android Tools ..."
+#$ANDROID_SDK_DIR/tools/bin/sdkmanager --all
+yes | $ANDROID_SDK_DIR/tools/bin/sdkmanager --licenses > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'tools' > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'platform-tools' > /dev/null
+$ANDROID_SDK_DIR/tools/bin/sdkmanager 'build-tools;26.0.2' > /dev/null
+echo
+
+EXPORT_VAL="export ANDROID_HOME=$ANDROID_SDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export ANDROID_NDK_ROOT=$ANDROID_NDK_PATH"
+if ! grep -q "^$EXPORT_VAL" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export PATH=$PATH:$ANDROID_SDK_PATH/tools"
+if ! grep -q "^export PATH=.*$ANDROID_SDK_PATH/tools.*" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+EXPORT_VAL="export PATH=$PATH:$ANDROID_SDK_PATH/tools/bin"
+if ! grep -q "^export PATH=.*$ANDROID_SDK_PATH/tools/bin.*" $BASH_RC; then
+ echo $EXPORT_VAL >> $BASH_RC
+fi
+#eval $EXPORT_VAL
+
+echo
+echo "Done!"
+echo
diff --git a/misc/travis/ccache-osx.sh b/misc/travis/ccache-osx.sh
new file mode 100755
index 0000000000..5ce7a80cbc
--- /dev/null
+++ b/misc/travis/ccache-osx.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+echo
+echo "Download and install ccache ..."
+echo
+
+echo "Downloading sources ..."
+curl -L -O https://www.samba.org/ftp/ccache/ccache-3.3.4.tar.gz # latest version available here: https://ccache.samba.org/download.html
+
+echo "Extracting to build directory ..."
+tar xzf ccache-3.3.4.tar.gz
+cd ccache-3.3.4
+
+echo "Compiling sources ..."
+./configure --prefix=/usr/local --with-bundled-zlib > /dev/null
+make
+
+echo "Installing ..."
+
+mkdir /usr/local/opt/ccache
+
+mkdir /usr/local/opt/ccache/bin
+cp ccache /usr/local/opt/ccache/bin
+ln -s /usr/local/opt/ccache/bin/ccache /usr/local/bin/ccache
+
+mkdir /usr/local/opt/ccache/libexec
+links=(
+ clang
+ clang++
+ cc
+ gcc gcc2 gcc3 gcc-3.3 gcc-4.0 gcc-4.2 gcc-4.3 gcc-4.4 gcc-4.5 gcc-4.6 gcc-4.7 gcc-4.8 gcc-4.9 gcc-5 gcc-6 gcc-7
+ c++ c++3 c++-3.3 c++-4.0 c++-4.2 c++-4.3 c++-4.4 c++-4.5 c++-4.6 c++-4.7 c++-4.8 c++-4.9 c++-5 c++-6 c++-7
+ g++ g++2 g++3 g++-3.3 g++-4.0 g++-4.2 g++-4.3 g++-4.4 g++-4.5 g++-4.6 g++-4.7 g++-4.8 g++-4.9 g++-5 g++-6 g++-7
+)
+for link in "${links[@]}"; do
+ ln -s ../bin/ccache /usr/local/opt/ccache/libexec/$link
+done
+#/usr/local/bin/ccache -M 2G
+cd $TRAVIS_BUILD_DIR
+
+echo
+echo "Done!"
+echo
diff --git a/misc/travis/scons-local-osx.sh b/misc/travis/scons-local-osx.sh
new file mode 100755
index 0000000000..d9d7d98b38
--- /dev/null
+++ b/misc/travis/scons-local-osx.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+echo
+echo "Download and install Scons local package ..."
+echo
+
+echo "Downloading sources ..."
+curl -L -O http://prdownloads.sourceforge.net/scons/scons-local-3.0.0.zip # latest version available here: http://scons.org/pages/download.html
+
+echo "Extracting to build directory ..."
+unzip -qq -n scons-local-3.0.0.zip -d $TRAVIS_BUILD_DIR/scons-local
+
+echo "Installing symlinks ..."
+ln -s $TRAVIS_BUILD_DIR/scons-local/scons.py /usr/local/bin/scons
+
+echo
+echo "Done!"
+echo
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index 88588417d1..2755930a55 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -40,11 +40,13 @@ def _build_gdnative_api_struct_header(api):
'\tunsigned int minor;',
'} godot_gdnative_api_version;',
'',
- 'typedef struct godot_gdnative_api_struct {',
+ 'typedef struct godot_gdnative_api_struct godot_gdnative_api_struct;',
+ '',
+ 'struct godot_gdnative_api_struct {',
'\tunsigned int type;',
'\tgodot_gdnative_api_version version;',
'\tconst godot_gdnative_api_struct *next;',
- '} godot_gdnative_api_struct;',
+ '};',
'',
'enum GDNATIVE_API_TYPES {',
'\tGDNATIVE_' + api['core']['type'] + ','
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.cpp b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
index e2a7019fa4..02f2ee7424 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.cpp
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.cpp
@@ -166,11 +166,11 @@ void ARVRInterfaceGDNative::uninitialize() {
interface->uninitialize(data);
}
-Size2 ARVRInterfaceGDNative::get_recommended_render_targetsize() {
+Size2 ARVRInterfaceGDNative::get_render_targetsize() {
ERR_FAIL_COND_V(interface == NULL, Size2());
- godot_vector2 result = interface->get_recommended_render_targetsize(data);
+ godot_vector2 result = interface->get_render_targetsize(data);
Vector2 *vec = (Vector2 *)&result;
return *vec;
diff --git a/modules/gdnative/arvr/arvr_interface_gdnative.h b/modules/gdnative/arvr/arvr_interface_gdnative.h
index e45b51e070..96f7b580d5 100644
--- a/modules/gdnative/arvr/arvr_interface_gdnative.h
+++ b/modules/gdnative/arvr/arvr_interface_gdnative.h
@@ -68,7 +68,7 @@ public:
virtual void set_anchor_detection_is_enabled(bool p_enable);
/** rendering and internal **/
- virtual Size2 get_recommended_render_targetsize();
+ virtual Size2 get_render_targetsize();
virtual bool is_stereo();
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
diff --git a/modules/gdnative/include/arvr/godot_arvr.h b/modules/gdnative/include/arvr/godot_arvr.h
index c12251439d..be13ac954b 100644
--- a/modules/gdnative/include/arvr/godot_arvr.h
+++ b/modules/gdnative/include/arvr/godot_arvr.h
@@ -47,7 +47,7 @@ typedef struct {
godot_bool (*is_initialized)(const void *);
godot_bool (*initialize)(void *);
void (*uninitialize)(void *);
- godot_vector2 (*get_recommended_render_targetsize)(const void *);
+ godot_vector2 (*get_render_targetsize)(const void *);
godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *);
void (*fill_projection_for_eye)(void *, godot_real *, godot_int, godot_real, godot_real, godot_real);
void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index de8e35c406..655e785174 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -337,6 +337,11 @@ void GDScriptLanguage::get_public_constants(List<Pair<String, Variant> > *p_cons
pi.second = Math_PI;
p_constants->push_back(pi);
+ Pair<String, Variant> tau;
+ tau.first = "TAU";
+ tau.second = Math_TAU;
+ p_constants->push_back(tau);
+
Pair<String, Variant> infinity;
infinity.first = "INF";
infinity.second = Math_INF;
@@ -360,7 +365,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
}
s += " ";
}
- s += "):\n\tpass # replace with function body\n";
+ s += "):\n" + _get_indentation() + "pass # replace with function body\n";
return s;
}
@@ -2771,31 +2776,31 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol
}
//global
- for (Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) {
- if (E->key() == p_symbol) {
-
- Variant value = GDScriptLanguage::get_singleton()->get_global_array()[E->get()];
- if (value.get_type() == Variant::OBJECT) {
- Object *obj = value;
- if (obj) {
-
- if (Object::cast_to<GDNativeClass>(obj)) {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
- r_result.class_name = Object::cast_to<GDNativeClass>(obj)->get_name();
-
- } else {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
- r_result.class_name = obj->get_class();
- }
- return OK;
+ Map<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map();
+ if (classes.has(p_symbol)) {
+ Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]];
+ if (value.get_type() == Variant::OBJECT) {
+ Object *obj = value;
+ if (obj) {
+ if (Object::cast_to<GDNativeClass>(obj)) {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name = Object::cast_to<GDNativeClass>(obj)->get_name();
+ } else {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name = obj->get_class();
}
- } else {
- r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
- r_result.class_name = "@Global Scope";
- r_result.class_member = p_symbol;
+ // proxy class remove the underscore.
+ if (r_result.class_name.begins_with("_")) {
+ r_result.class_name = r_result.class_name.right(1);
+ }
return OK;
}
+ } else {
+ r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name = "@Global Scope";
+ r_result.class_member = p_symbol;
+ return OK;
}
}
}
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 94385dc0d0..d7e83c3a33 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -362,6 +362,13 @@ GDParser::Node *GDParser::_parse_expression(Node *p_parent, bool p_static, bool
constant->value = Math_PI;
tokenizer->advance();
expr = constant;
+ } else if (tokenizer->get_token() == GDTokenizer::TK_CONST_TAU) {
+
+ //constant defined by tokenizer
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ constant->value = Math_TAU;
+ tokenizer->advance();
+ expr = constant;
} else if (tokenizer->get_token() == GDTokenizer::TK_CONST_INF) {
//constant defined by tokenizer
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 3f3818ffb9..e5016c59bd 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -1324,6 +1324,7 @@ void GDScriptLanguage::init() {
}
_add_global(StaticCString::create("PI"), Math_PI);
+ _add_global(StaticCString::create("TAU"), Math_TAU);
_add_global(StaticCString::create("INF"), Math_INF);
_add_global(StaticCString::create("NAN"), Math_NAN);
@@ -1700,6 +1701,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"bool",
"null",
"PI",
+ "TAU",
"INF",
"NAN",
"self",
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index 5f85158232..98ac0f473d 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -123,6 +123,7 @@ const char *GDTokenizer::token_names[TK_MAX] = {
"'$'",
"'\\n'",
"PI",
+ "TAU",
"_",
"INF",
"NAN",
@@ -217,6 +218,7 @@ static const _kws _keyword_list[] = {
{ GDTokenizer::TK_CF_PASS, "pass" },
{ GDTokenizer::TK_SELF, "self" },
{ GDTokenizer::TK_CONST_PI, "PI" },
+ { GDTokenizer::TK_CONST_TAU, "TAU" },
{ GDTokenizer::TK_WILDCARD, "_" },
{ GDTokenizer::TK_CONST_INF, "INF" },
{ GDTokenizer::TK_CONST_NAN, "NAN" },
@@ -280,6 +282,7 @@ bool GDTokenizer::is_token_literal(int p_offset, bool variable_safe) const {
case TK_CF_PASS:
case TK_SELF:
case TK_CONST_PI:
+ case TK_CONST_TAU:
case TK_WILDCARD:
case TK_CONST_INF:
case TK_CONST_NAN:
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index c935ce45a1..f4b579def4 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -128,6 +128,7 @@ public:
TK_DOLLAR,
TK_NEWLINE,
TK_CONST_PI,
+ TK_CONST_TAU,
TK_WILDCARD,
TK_CONST_INF,
TK_CONST_NAN,
diff --git a/modules/mobile_vr/mobile_interface.cpp b/modules/mobile_vr/mobile_interface.cpp
index 93d5c22ef8..3a0b83d534 100644
--- a/modules/mobile_vr/mobile_interface.cpp
+++ b/modules/mobile_vr/mobile_interface.cpp
@@ -156,17 +156,6 @@ void MobileVRInterface::set_position_from_sensors() {
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
- // On Android x and z axis seem inverted
- gyro.x = -gyro.x;
- gyro.z = -gyro.z;
- grav.x = -grav.x;
- grav.z = -grav.z;
- magneto.x = -magneto.x;
- magneto.z = -magneto.z;
-#endif
-
if (has_gyro) {
// start with applying our gyro (do NOT smooth our gyro!)
Basis rotate;
@@ -334,7 +323,7 @@ void MobileVRInterface::uninitialize() {
};
};
-Size2 MobileVRInterface::get_recommended_render_targetsize() {
+Size2 MobileVRInterface::get_render_targetsize() {
_THREAD_SAFE_METHOD_
// we use half our window size
diff --git a/modules/mobile_vr/mobile_interface.h b/modules/mobile_vr/mobile_interface.h
index 747377ae46..b652edc1c6 100644
--- a/modules/mobile_vr/mobile_interface.h
+++ b/modules/mobile_vr/mobile_interface.h
@@ -137,7 +137,7 @@ public:
virtual bool initialize();
virtual void uninitialize();
- virtual Size2 get_recommended_render_targetsize();
+ virtual Size2 get_render_targetsize();
virtual bool is_stereo();
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform);
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
diff --git a/modules/ogg/config.py b/modules/ogg/config.py
index ef5daca05c..fb920482f5 100644
--- a/modules/ogg/config.py
+++ b/modules/ogg/config.py
@@ -1,7 +1,6 @@
def can_build(platform):
-# return True
- return False
+ return True
def configure(env):
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index fee06bd267..6f643ef08c 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -3,6 +3,9 @@
Import('env')
Import('env_modules')
+
+stub = True
+
env_opus = env_modules.Clone()
# Thirdparty source files
@@ -212,5 +215,9 @@ if env['builtin_opus']:
if env['builtin_libogg']:
env_opus.Append(CPPPATH=["#thirdparty/libogg"])
-# Module files
-env_opus.add_source_files(env.modules_sources, "*.cpp")
+if not stub:
+ # Module files
+ env_opus.add_source_files(env.modules_sources, "*.cpp")
+else:
+ # Module files
+ env_opus.add_source_files(env.modules_sources, "stub/register_types.cpp")
diff --git a/modules/opus/config.py b/modules/opus/config.py
index ef5daca05c..fb920482f5 100644
--- a/modules/opus/config.py
+++ b/modules/opus/config.py
@@ -1,7 +1,6 @@
def can_build(platform):
-# return True
- return False
+ return True
def configure(env):
diff --git a/modules/opus/stub/register_types.cpp b/modules/opus/stub/register_types.cpp
new file mode 100644
index 0000000000..c5ae3e274e
--- /dev/null
+++ b/modules/opus/stub/register_types.cpp
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "register_types.h"
+
+// Dummy module as libvorbis is needed by other modules (theora ...)
+
+void register_opus_types() {}
+
+void unregister_opus_types() {}
diff --git a/modules/opus/stub/register_types.h b/modules/opus/stub/register_types.h
new file mode 100644
index 0000000000..4517dc5df7
--- /dev/null
+++ b/modules/opus/stub/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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. */
+/*************************************************************************/
+void register_opus_types();
+void unregister_opus_types();
diff --git a/modules/theora/config.py b/modules/theora/config.py
index 8eefe81288..fb920482f5 100644
--- a/modules/theora/config.py
+++ b/modules/theora/config.py
@@ -1,7 +1,6 @@
def can_build(platform):
-# return True
- return False
+ return True
def configure(env):
diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp
index ae6961b3da..c51b87b8fc 100644
--- a/modules/theora/register_types.cpp
+++ b/modules/theora/register_types.cpp
@@ -28,19 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
-
+#include "resource_importer_theora.h"
#include "video_stream_theora.h"
-static ResourceFormatLoaderVideoStreamTheora *theora_stream_loader = NULL;
-
void register_theora_types() {
- theora_stream_loader = memnew(ResourceFormatLoaderVideoStreamTheora);
- ResourceLoader::add_resource_format_loader(theora_stream_loader);
+#ifdef TOOLS_ENABLED
+ Ref<ResourceImporterTheora> theora_import;
+ theora_import.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(theora_import);
+#endif
ClassDB::register_class<VideoStreamTheora>();
}
void unregister_theora_types() {
-
- memdelete(theora_stream_loader);
}
diff --git a/modules/theora/resource_importer_theora.cpp b/modules/theora/resource_importer_theora.cpp
new file mode 100644
index 0000000000..c25c0e7427
--- /dev/null
+++ b/modules/theora/resource_importer_theora.cpp
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/* resource_importer_theora.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "resource_importer_theora.h"
+
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+#include "scene/resources/texture.h"
+
+String ResourceImporterTheora::get_importer_name() const {
+
+ return "Theora";
+}
+
+String ResourceImporterTheora::get_visible_name() const {
+
+ return "Theora";
+}
+void ResourceImporterTheora::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("ogv");
+ p_extensions->push_back("ogm");
+}
+
+String ResourceImporterTheora::get_save_extension() const {
+ return "ogvstr";
+}
+
+String ResourceImporterTheora::get_resource_type() const {
+
+ return "VideoStreamTheora";
+}
+
+bool ResourceImporterTheora::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+
+ return true;
+}
+
+int ResourceImporterTheora::get_preset_count() const {
+ return 0;
+}
+String ResourceImporterTheora::get_preset_name(int p_idx) const {
+
+ return String();
+}
+
+void ResourceImporterTheora::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
+}
+
+Error ResourceImporterTheora::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
+
+ VideoStreamTheora *stream = memnew(VideoStreamTheora);
+ stream->set_file(p_source_file);
+
+ Ref<VideoStreamTheora> ogv_stream = Ref<VideoStreamTheora>(stream);
+
+ return ResourceSaver::save(p_save_path + ".ogvstr", ogv_stream);
+}
+
+ResourceImporterTheora::ResourceImporterTheora() {
+}
diff --git a/modules/theora/resource_importer_theora.h b/modules/theora/resource_importer_theora.h
new file mode 100644
index 0000000000..8bf0ad38c4
--- /dev/null
+++ b/modules/theora/resource_importer_theora.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* resource_importer_theora.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 RESOURCEIMPORTEROGGTHEORA_H
+#define RESOURCEIMPORTEROGGTHEORA_H
+
+#include "video_stream_theora.h"
+
+#include "core/io/resource_import.h"
+
+class ResourceImporterTheora : public ResourceImporter {
+ GDCLASS(ResourceImporterTheora, ResourceImporter)
+public:
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL);
+
+ ResourceImporterTheora();
+};
+
+#endif // RESOURCEIMPORTEROGGTHEORA_H
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index c75bec31df..bc8ca23d60 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -406,20 +406,19 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
ogg_packet op;
bool no_theora = false;
+ bool buffer_full = false;
- while (vorbis_p) {
+ while (vorbis_p && !audio_done && !buffer_full) {
int ret;
float **pcm;
- bool buffer_full = false;
-
/* if there's pending, decoded audio, grab it */
ret = vorbis_synthesis_pcmout(&vd, &pcm);
if (ret > 0) {
const int AUXBUF_LEN = 4096;
int to_read = ret;
- int16_t aux_buffer[AUXBUF_LEN];
+ float aux_buffer[AUXBUF_LEN];
while (to_read) {
@@ -429,11 +428,7 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
for (int j = 0; j < m; j++) {
for (int i = 0; i < vi.channels; i++) {
-
- int val = Math::fast_ftoi(pcm[i][j] * 32767.f);
- if (val > 32767) val = 32767;
- if (val < -32768) val = -32768;
- aux_buffer[count++] = val;
+ aux_buffer[count++] = pcm[i][j];
}
}
@@ -602,10 +597,9 @@ bool VideoStreamPlaybackTheora::is_playing() const {
void VideoStreamPlaybackTheora::set_paused(bool p_paused) {
paused = p_paused;
- //pau = !p_paused;
};
-bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const {
+bool VideoStreamPlaybackTheora::is_paused() const {
return paused;
};
@@ -733,32 +727,10 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
memdelete(file);
};
-RES ResourceFormatLoaderVideoStreamTheora::load(const String &p_path, const String &p_original_path, Error *r_error) {
- if (r_error)
- *r_error = ERR_FILE_CANT_OPEN;
-
- VideoStreamTheora *stream = memnew(VideoStreamTheora);
- stream->set_file(p_path);
-
- if (r_error)
- *r_error = OK;
-
- return Ref<VideoStreamTheora>(stream);
-}
+void VideoStreamTheora::_bind_methods() {
-void ResourceFormatLoaderVideoStreamTheora::get_recognized_extensions(List<String> *p_extensions) const {
+ ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamTheora::set_file);
+ ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamTheora::get_file);
- p_extensions->push_back("ogm");
- p_extensions->push_back("ogv");
-}
-bool ResourceFormatLoaderVideoStreamTheora::handles_type(const String &p_type) const {
- return (p_type == "VideoStream" || p_type == "VideoStreamTheora");
-}
-
-String ResourceFormatLoaderVideoStreamTheora::get_resource_type(const String &p_path) const {
-
- String exl = p_path.get_extension().to_lower();
- if (exl == "ogm" || exl == "ogv")
- return "VideoStreamTheora";
- return "";
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_file", "get_file");
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 484a1a7fb9..ec0e5aa34a 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -36,6 +36,7 @@
#include "os/thread.h"
#include "ring_buffer.h"
#include "scene/resources/video_stream.h"
+#include "servers/audio_server.h"
#include <theora/theoradec.h>
#include <vorbis/codec.h>
@@ -129,7 +130,7 @@ public:
virtual bool is_playing() const;
virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
+ virtual bool is_paused() const;
virtual void set_loop(bool p_enable);
virtual bool has_loop() const;
@@ -161,10 +162,14 @@ public:
class VideoStreamTheora : public VideoStream {
GDCLASS(VideoStreamTheora, VideoStream);
+ RES_BASE_EXTENSION("ogvstr");
String file;
int audio_track;
+protected:
+ static void _bind_methods();
+
public:
Ref<VideoStreamPlayback> instance_playback() {
Ref<VideoStreamPlaybackTheora> pb = memnew(VideoStreamPlaybackTheora);
@@ -174,17 +179,10 @@ public:
}
void set_file(const String &p_file) { file = p_file; }
+ String get_file() { return file; }
void set_audio_track(int p_track) { audio_track = p_track; }
VideoStreamTheora() { audio_track = 0; }
};
-class ResourceFormatLoaderVideoStreamTheora : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
#endif
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 03015df844..15e20effc0 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -2764,6 +2764,23 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y));
default_value_edit->set_size(Size2(1, 1));
+
+ if (pinfo.type == Variant::NODE_PATH) {
+
+ Node *edited_scene = get_tree()->get_edited_scene_root();
+ Node *script_node = _find_script_node(edited_scene, edited_scene, script);
+
+ if (script_node) {
+ //pick a node relative to the script, IF the script exists
+ pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
+ pinfo.hint_string = script_node->get_path();
+ } else {
+ //pick a path relative to edited scene
+ pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;
+ pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path();
+ }
+ }
+
if (default_value_edit->edit(NULL, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {
if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT)
default_value_edit->popup_centered_ratio();
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index 897e910f20..07dca4b904 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -564,6 +564,9 @@ Error VisualScriptExpression::_get_token(Token &r_token) {
} else if (id == "PI") {
r_token.type = TK_CONSTANT;
r_token.value = Math_PI;
+ } else if (id == "TAU") {
+ r_token.type = TK_CONSTANT;
+ r_token.value = Math_TAU;
} else if (id == "INF") {
r_token.type = TK_CONSTANT;
r_token.value = Math_INF;
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index d3cd839cf3..3863fa7e1c 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -1776,8 +1776,8 @@ VisualScriptBasicTypeConstant::VisualScriptBasicTypeConstant() {
const char *VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX] = {
"One",
"PI",
- "PIx2",
"PI/2",
+ "TAU",
"E",
"Sqrt2",
"INF",
@@ -1787,8 +1787,8 @@ const char *VisualScriptMathConstant::const_name[MATH_CONSTANT_MAX] = {
double VisualScriptMathConstant::const_value[MATH_CONSTANT_MAX] = {
1.0,
Math_PI,
- Math_PI * 2,
Math_PI * 0.5,
+ Math_TAU,
2.71828182845904523536,
Math::sqrt(2.0),
Math_INF,
@@ -1886,8 +1886,8 @@ void VisualScriptMathConstant::_bind_methods() {
BIND_ENUM_CONSTANT(MATH_CONSTANT_ONE);
BIND_ENUM_CONSTANT(MATH_CONSTANT_PI);
- BIND_ENUM_CONSTANT(MATH_CONSTANT_2PI);
BIND_ENUM_CONSTANT(MATH_CONSTANT_HALF_PI);
+ BIND_ENUM_CONSTANT(MATH_CONSTANT_TAU);
BIND_ENUM_CONSTANT(MATH_CONSTANT_E);
BIND_ENUM_CONSTANT(MATH_CONSTANT_SQRT2);
BIND_ENUM_CONSTANT(MATH_CONSTANT_INF);
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index 421409b265..6648f57e7b 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -474,8 +474,8 @@ public:
enum MathConstant {
MATH_CONSTANT_ONE,
MATH_CONSTANT_PI,
- MATH_CONSTANT_2PI,
MATH_CONSTANT_HALF_PI,
+ MATH_CONSTANT_TAU,
MATH_CONSTANT_E,
MATH_CONSTANT_SQRT2,
MATH_CONSTANT_INF,
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index 9d2d0feb92..55a112585b 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -5,6 +5,8 @@ Import('env_modules')
env_vorbis = env_modules.Clone()
+stub = True
+
# Thirdparty source files
if env['builtin_libvorbis']:
thirdparty_dir = "#thirdparty/libvorbis/"
@@ -45,5 +47,9 @@ if env['builtin_libvorbis']:
if env['builtin_libogg']:
env_vorbis.Append(CPPPATH=["#thirdparty/libogg"])
-# Godot source files
-env_vorbis.add_source_files(env.modules_sources, "*.cpp")
+if not stub:
+ # Module files
+ env_vorbis.add_source_files(env.modules_sources, "*.cpp")
+else:
+ # Module files
+ env_vorbis.add_source_files(env.modules_sources, "stub/register_types.cpp")
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index 6235799fc2..9fb6fa8197 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -106,8 +106,6 @@ int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) {
break;
}
-//printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t));
-
#ifdef BIG_ENDIAN_ENABLED
long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, &current_section);
#else
@@ -359,7 +357,7 @@ void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) {
paused = p_paused;
}
-bool AudioStreamPlaybackOGGVorbis::is_paused(bool p_paused) const {
+bool AudioStreamPlaybackOGGVorbis::is_paused() const {
return paused;
}
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
index 79eadec56e..5000d03fd4 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/vorbis/audio_stream_ogg_vorbis.h
@@ -85,7 +85,7 @@ public:
virtual void set_loop_restart_time(float p_time) { loop_restart_time = p_time; }
virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
+ virtual bool is_paused() const;
virtual void set_loop(bool p_enable);
virtual bool has_loop() const;
diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py
index ef5daca05c..fb920482f5 100644
--- a/modules/vorbis/config.py
+++ b/modules/vorbis/config.py
@@ -1,7 +1,6 @@
def can_build(platform):
-# return True
- return False
+ return True
def configure(env):
diff --git a/modules/vorbis/stub/register_types.cpp b/modules/vorbis/stub/register_types.cpp
new file mode 100644
index 0000000000..b93d890436
--- /dev/null
+++ b/modules/vorbis/stub/register_types.cpp
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "register_types.h"
+
+// Dummy module as libvorbis is needed by other modules (theora ...)
+
+void register_vorbis_types() {}
+
+void unregister_vorbis_types() {}
diff --git a/modules/vorbis/stub/register_types.h b/modules/vorbis/stub/register_types.h
new file mode 100644
index 0000000000..e7cde7a66c
--- /dev/null
+++ b/modules/vorbis/stub/register_types.h
@@ -0,0 +1,31 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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. */
+/*************************************************************************/
+void register_vorbis_types();
+void unregister_vorbis_types();
diff --git a/modules/webm/config.py b/modules/webm/config.py
index ef5daca05c..fb920482f5 100644
--- a/modules/webm/config.py
+++ b/modules/webm/config.py
@@ -1,7 +1,6 @@
def can_build(platform):
-# return True
- return False
+ return True
def configure(env):
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
index fd8d762a5e..73ba17d184 100644
--- a/modules/webm/libvpx/SCsub
+++ b/modules/webm/libvpx/SCsub
@@ -298,7 +298,7 @@ if webm_cpu_x86:
if not yasm_found:
webm_cpu_x86 = False
- print "YASM is necessary for WebM SIMD optimizations."
+ print("YASM is necessary for WebM SIMD optimizations.")
webm_simd_optimizations = False
@@ -345,7 +345,7 @@ if webm_cpu_arm:
webm_simd_optimizations = True
if webm_simd_optimizations == False:
- print "WebM SIMD optimizations are disabled. Check if your CPU architecture, CPU bits or platform are supported!"
+ print("WebM SIMD optimizations are disabled. Check if your CPU architecture, CPU bits or platform are supported!")
env_libvpx.add_source_files(env.modules_sources, libvpx_sources)
diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp
index 892d1b8420..669c9997f1 100644
--- a/modules/webm/register_types.cpp
+++ b/modules/webm/register_types.cpp
@@ -28,19 +28,18 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
-
+#include "resource_importer_webm.h"
#include "video_stream_webm.h"
-static ResourceFormatLoaderVideoStreamWebm *webm_stream_loader = NULL;
-
void register_webm_types() {
- webm_stream_loader = memnew(ResourceFormatLoaderVideoStreamWebm);
- ResourceLoader::add_resource_format_loader(webm_stream_loader);
+#ifdef TOOLS_ENABLED
+ Ref<ResourceImporterWebm> webm_import;
+ webm_import.instance();
+ ResourceFormatImporter::get_singleton()->add_importer(webm_import);
+#endif
ClassDB::register_class<VideoStreamWebm>();
}
void unregister_webm_types() {
-
- memdelete(webm_stream_loader);
}
diff --git a/modules/webm/resource_importer_webm.cpp b/modules/webm/resource_importer_webm.cpp
new file mode 100644
index 0000000000..5db3d4df2e
--- /dev/null
+++ b/modules/webm/resource_importer_webm.cpp
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* resource_importer_webm.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "resource_importer_webm.h"
+
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+#include "scene/resources/texture.h"
+#include "video_stream_webm.h"
+
+String ResourceImporterWebm::get_importer_name() const {
+
+ return "Webm";
+}
+
+String ResourceImporterWebm::get_visible_name() const {
+
+ return "Webm";
+}
+void ResourceImporterWebm::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("webm");
+}
+
+String ResourceImporterWebm::get_save_extension() const {
+ return "webmstr";
+}
+
+String ResourceImporterWebm::get_resource_type() const {
+
+ return "VideoStreamWebm";
+}
+
+bool ResourceImporterWebm::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
+
+ return true;
+}
+
+int ResourceImporterWebm::get_preset_count() const {
+ return 0;
+}
+String ResourceImporterWebm::get_preset_name(int p_idx) const {
+
+ return String();
+}
+
+void ResourceImporterWebm::get_import_options(List<ImportOption> *r_options, int p_preset) const {
+
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "loop"), true));
+}
+
+Error ResourceImporterWebm::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files) {
+
+ FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
+ if (!f) {
+ ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ }
+ memdelete(f);
+
+ VideoStreamWebm *stream = memnew(VideoStreamWebm);
+ stream->set_file(p_source_file);
+
+ Ref<VideoStreamWebm> webm_stream = Ref<VideoStreamWebm>(stream);
+
+ return ResourceSaver::save(p_save_path + ".webmstr", webm_stream);
+}
+
+ResourceImporterWebm::ResourceImporterWebm() {
+}
diff --git a/modules/webm/resource_importer_webm.h b/modules/webm/resource_importer_webm.h
new file mode 100644
index 0000000000..4cedd1598d
--- /dev/null
+++ b/modules/webm/resource_importer_webm.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* resource_importer_webm.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 RESOURCEIMPORTERWEBM_H
+#define RESOURCEIMPORTERWEBM_H
+
+#include "io/resource_import.h"
+
+class ResourceImporterWebm : public ResourceImporter {
+ GDCLASS(ResourceImporterWebm, ResourceImporter)
+public:
+ virtual String get_importer_name() const;
+ virtual String get_visible_name() const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual String get_save_extension() const;
+ virtual String get_resource_type() const;
+
+ virtual int get_preset_count() const;
+ virtual String get_preset_name(int p_idx) const;
+
+ virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const;
+ virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const;
+
+ virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = NULL);
+
+ ResourceImporterWebm();
+};
+
+#endif // RESOURCEIMPORTERWEBM_H
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 2ec6b27471..0fc9df5b58 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -35,10 +35,13 @@
#include "mkvparser/mkvparser.h"
#include "os/file_access.h"
+#include "os/os.h"
#include "project_settings.h"
#include "thirdparty/misc/yuv2rgb.h"
+#include "servers/audio_server.h"
+
#include <string.h>
class MkvReader : public mkvparser::IMkvReader {
@@ -47,6 +50,8 @@ public:
MkvReader(const String &p_file) {
file = FileAccess::open(p_file, FileAccess::READ);
+
+ ERR_EXPLAIN("Failed loading resource: '" + p_file + "';");
ERR_FAIL_COND(!file);
}
~MkvReader() {
@@ -113,14 +118,14 @@ bool VideoStreamPlaybackWebm::open_file(const String &p_file) {
webm = memnew(WebMDemuxer(new MkvReader(file_name), 0, audio_track));
if (webm->isOpen()) {
- video = memnew(VPXDecoder(*webm, 8)); //TODO: Detect CPU threads
+ video = memnew(VPXDecoder(*webm, OS::get_singleton()->get_processor_count()));
if (video->isOpen()) {
audio = memnew(OpusVorbisDecoder(*webm));
if (audio->isOpen()) {
audio_frame = memnew(WebMFrame);
- pcm = (int16_t *)memalloc(sizeof(int16_t) * audio->getBufferSamples() * webm->getChannels());
+ pcm = (float *)memalloc(sizeof(float) * audio->getBufferSamples() * webm->getChannels());
} else {
memdelete(audio);
@@ -183,7 +188,7 @@ void VideoStreamPlaybackWebm::set_paused(bool p_paused) {
paused = p_paused;
}
-bool VideoStreamPlaybackWebm::is_paused(bool p_paused) const {
+bool VideoStreamPlaybackWebm::is_paused() const {
return paused;
}
@@ -222,11 +227,18 @@ Ref<Texture> VideoStreamPlaybackWebm::get_texture() {
return texture;
}
+
void VideoStreamPlaybackWebm::update(float p_delta) {
if ((!playing || paused) || !video)
return;
+ time += p_delta;
+
+ if (time < video_pos) {
+ return;
+ }
+
bool audio_buffer_full = false;
if (samples_offset > -1) {
@@ -245,13 +257,15 @@ void VideoStreamPlaybackWebm::update(float p_delta) {
}
const bool hasAudio = (audio && mix_callback);
- while ((hasAudio && (!audio_buffer_full || !has_enough_video_frames())) || (!hasAudio && video_frames_pos == 0)) {
+ while ((hasAudio && !audio_buffer_full && !has_enough_video_frames()) ||
+ (!hasAudio && video_frames_pos == 0)) {
- if (hasAudio && !audio_buffer_full && audio_frame->isValid() && audio->getPCMS16(*audio_frame, pcm, num_decoded_samples) && num_decoded_samples > 0) {
+ if (hasAudio && !audio_buffer_full && audio_frame->isValid() &&
+ audio->getPCMF(*audio_frame, pcm, num_decoded_samples) && num_decoded_samples > 0) {
const int mixed = mix_callback(mix_udata, pcm, num_decoded_samples);
- if (mixed != num_decoded_samples) {
+ if (mixed != num_decoded_samples) {
samples_offset = mixed;
audio_buffer_full = true;
}
@@ -273,72 +287,61 @@ void VideoStreamPlaybackWebm::update(float p_delta) {
++video_frames_pos;
};
- const double video_delay = video->getFramesDelay() * video_frame_delay;
-
- bool want_this_frame = false;
- while (video_frames_pos > 0 && !want_this_frame) {
+ bool video_frame_done = false;
+ while (video_frames_pos > 0 && !video_frame_done) {
WebMFrame *video_frame = video_frames[0];
- if (video_frame->time <= time + video_delay) {
- if (video->decode(*video_frame)) {
+ // It seems VPXDecoder::decode has to be executed even though we might skip this frame
+ if (video->decode(*video_frame)) {
- VPXDecoder::IMAGE_ERROR err;
- VPXDecoder::Image image;
+ VPXDecoder::IMAGE_ERROR err;
+ VPXDecoder::Image image;
- while ((err = video->getImage(image)) != VPXDecoder::NO_FRAME) {
+ if (should_process(*video_frame)) {
- want_this_frame = (time - video_frame->time <= video_frame_delay);
+ if ((err = video->getImage(image)) != VPXDecoder::NO_FRAME) {
- if (want_this_frame) {
+ if (err == VPXDecoder::NO_ERROR && image.w == webm->getWidth() && image.h == webm->getHeight()) {
- if (err == VPXDecoder::NO_ERROR && image.w == webm->getWidth() && image.h == webm->getHeight()) {
+ PoolVector<uint8_t>::Write w = frame_data.write();
+ bool converted = false;
- PoolVector<uint8_t>::Write w = frame_data.write();
- bool converted = false;
+ if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
- if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
+ yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ // libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
+ converted = true;
+ } else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {
- yuv420_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
- // libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {
+ yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ // libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
+ converted = true;
+ } else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {
- yuv422_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
- // libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {
+ yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
+ // libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
+ converted = true;
+ } else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {
- yuv444_2_rgb8888(w.ptr(), image.planes[0], image.planes[2], image.planes[1], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2, 0);
- // libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {
-
- // libyuv::I411ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- // converted = true;
- }
-
- if (converted)
- texture->set_data(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data)); //Zero copy send to visual server
+ // libyuv::I411ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
+ // converted = true;
}
- break;
+ if (converted) {
+ Ref<Image> img = memnew(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data));
+ texture->set_data(img); //Zero copy send to visual server
+ video_frame_done = true;
+ }
}
}
}
-
- video_frame_delay = video_frame->time - video_pos;
- video_pos = video_frame->time;
-
- memmove(video_frames, video_frames + 1, (--video_frames_pos) * sizeof(void *));
- video_frames[video_frames_pos] = video_frame;
- } else {
-
- break;
}
- }
- time += p_delta;
+ video_pos = video_frame->time;
+ memmove(video_frames, video_frames + 1, (--video_frames_pos) * sizeof(void *));
+ video_frames[video_frames_pos] = video_frame;
+ }
if (video_frames_pos == 0 && webm->isEOS())
stop();
@@ -372,6 +375,11 @@ inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const {
return false;
}
+bool VideoStreamPlaybackWebm::should_process(WebMFrame &video_frame) {
+ const double audio_delay = AudioServer::get_singleton()->get_output_delay();
+ return video_frame.time >= time + audio_delay + delay_compensation;
+}
+
void VideoStreamPlaybackWebm::delete_pointers() {
if (pcm)
@@ -395,34 +403,6 @@ void VideoStreamPlaybackWebm::delete_pointers() {
/**/
-RES ResourceFormatLoaderVideoStreamWebm::load(const String &p_path, const String &p_original_path, Error *r_error) {
-
- Ref<VideoStreamWebm> stream = memnew(VideoStreamWebm);
- stream->set_file(p_path);
- if (r_error)
- *r_error = OK;
- return stream;
-}
-
-void ResourceFormatLoaderVideoStreamWebm::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("webm");
-}
-bool ResourceFormatLoaderVideoStreamWebm::handles_type(const String &p_type) const {
-
- return (p_type == "VideoStream" || p_type == "VideoStreamWebm");
-}
-
-String ResourceFormatLoaderVideoStreamWebm::get_resource_type(const String &p_path) const {
-
- const String exl = p_path.get_extension().to_lower();
- if (exl == "webm")
- return "VideoStreamWebm";
- return "";
-}
-
-/**/
-
VideoStreamWebm::VideoStreamWebm()
: audio_track(0) {}
@@ -439,6 +419,19 @@ void VideoStreamWebm::set_file(const String &p_file) {
file = p_file;
}
+String VideoStreamWebm::get_file() {
+
+ return file;
+}
+
+void VideoStreamWebm::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamWebm::set_file);
+ ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamWebm::get_file);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_file", "get_file");
+}
+
void VideoStreamWebm::set_audio_track(int p_track) {
audio_track = p_track;
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
index fc0720967a..f7dd16a38f 100644
--- a/modules/webm/video_stream_webm.h
+++ b/modules/webm/video_stream_webm.h
@@ -60,7 +60,7 @@ class VideoStreamPlaybackWebm : public VideoStreamPlayback {
PoolVector<uint8_t> frame_data;
Ref<ImageTexture> texture;
- int16_t *pcm;
+ float *pcm;
public:
VideoStreamPlaybackWebm();
@@ -74,7 +74,7 @@ public:
virtual bool is_playing() const;
virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
+ virtual bool is_paused() const;
virtual void set_loop(bool p_enable);
virtual bool has_loop() const;
@@ -95,6 +95,7 @@ public:
private:
inline bool has_enough_video_frames() const;
+ bool should_process(WebMFrame &video_frame);
void delete_pointers();
};
@@ -103,27 +104,21 @@ private:
class VideoStreamWebm : public VideoStream {
- GDCLASS(VideoStreamWebm, VideoStream)
+ GDCLASS(VideoStreamWebm, VideoStream);
+ RES_BASE_EXTENSION("webmstr");
String file;
int audio_track;
+protected:
+ static void _bind_methods();
+
public:
VideoStreamWebm();
virtual Ref<VideoStreamPlayback> instance_playback();
virtual void set_file(const String &p_file);
+ String get_file();
virtual void set_audio_track(int p_track);
};
-
-/**/
-
-class ResourceFormatLoaderVideoStreamWebm : public ResourceFormatLoader {
-
-public:
- virtual RES load(const String &p_path, const String &p_original_path, Error *r_error);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 966de832e8..a3ada5cf51 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -173,8 +173,15 @@ def configure(env):
# For Clang to find NDK tools in preference of those system-wide
env.PrependENVPath('PATH', tools_path)
- env['CC'] = compiler_path + '/clang'
- env['CXX'] = compiler_path + '/clang++'
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = compiler_path + '/clang'
+ env['CXX'] = compiler_path + '/clang++'
+ else:
+ # there aren't any ccache wrappers available for Android,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + compiler_path + '/clang'
+ env['CXX'] = ccache_path + ' ' + compiler_path + '/clang++'
env['AR'] = tools_path + "/ar"
env['RANLIB'] = tools_path + "/ranlib"
env['AS'] = tools_path + "/as"
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
index 8235683496..abe5e3b77a 100644
--- a/platform/android/godot_android.cpp
+++ b/platform/android/godot_android.cpp
@@ -669,6 +669,14 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
ASensorEventQueue_setEventRate(engine->sensorEventQueue,
engine->accelerometerSensor, (1000L / 60) * 1000);
}
+ // start monitoring gravity
+ if (engine->gravitySensor != NULL) {
+ ASensorEventQueue_enableSensor(engine->sensorEventQueue,
+ engine->gravitySensor);
+ // We'd like to get 60 events per second (in us).
+ ASensorEventQueue_setEventRate(engine->sensorEventQueue,
+ engine->gravitySensor, (1000L / 60) * 1000);
+ }
// Also start monitoring the magnetometer.
if (engine->magnetometerSensor != NULL) {
ASensorEventQueue_enableSensor(engine->sensorEventQueue,
@@ -694,6 +702,10 @@ static void engine_handle_cmd(struct android_app *app, int32_t cmd) {
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
engine->accelerometerSensor);
}
+ if (engine->gravitySensor != NULL) {
+ ASensorEventQueue_disableSensor(engine->sensorEventQueue,
+ engine->gravitySensor);
+ }
if (engine->magnetometerSensor != NULL) {
ASensorEventQueue_disableSensor(engine->sensorEventQueue,
engine->magnetometerSensor);
@@ -729,6 +741,8 @@ void android_main(struct android_app *app) {
engine.sensorManager = ASensorManager_getInstance();
engine.accelerometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
ASENSOR_TYPE_ACCELEROMETER);
+ engine.gravitySensor = ASensorManager_getDefaultSensor(engine.sensorManager,
+ ASENSOR_TYPE_GRAVITY);
engine.magnetometerSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
ASENSOR_TYPE_MAGNETIC_FIELD);
engine.gyroscopeSensor = ASensorManager_getDefaultSensor(engine.sensorManager,
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index 59fefc498f..41dcba5c2c 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -219,6 +219,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
private SensorManager mSensorManager;
private Sensor mAccelerometer;
+ private Sensor mGravity;
private Sensor mMagnetometer;
private Sensor mGyroscope;
@@ -435,6 +436,8 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mGravity = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
+ mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
@@ -667,6 +670,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
}
});
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+ mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME);
mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME);
@@ -734,13 +738,16 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
@Override
public void run() {
if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) {
- GodotLib.accelerometer(x,y,z);
+ GodotLib.accelerometer(-x,y,-z);
+ }
+ if (typeOfSensor == Sensor.TYPE_GRAVITY) {
+ GodotLib.gravity(-x,y,-z);
}
if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) {
- GodotLib.magnetometer(x,y,z);
+ GodotLib.magnetometer(-x,y,-z);
}
if (typeOfSensor == Sensor.TYPE_GYROSCOPE) {
- GodotLib.gyroscope(x,y,z);
+ GodotLib.gyroscope(x,-y,z);
}
}
});
diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java
index e0ed4cd38c..6b84ad6555 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java
@@ -53,6 +53,7 @@ public class GodotLib {
public static native void step();
public static native void touch(int what,int pointer,int howmany, int[] arr);
public static native void accelerometer(float x, float y, float z);
+ public static native void gravity(float x, float y, float z);
public static native void magnetometer(float x, float y, float z);
public static native void gyroscope(float x, float y, float z);
public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 0b193f5882..87f20bee91 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -608,6 +608,7 @@ static bool resized = false;
static bool resized_reload = false;
static Size2 new_size;
static Vector3 accelerometer;
+static Vector3 gravity;
static Vector3 magnetometer;
static Vector3 gyroscope;
static HashMap<String, JNISingleton *> jni_singletons;
@@ -1012,6 +1013,8 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, job
os_android->process_accelerometer(accelerometer);
+ os_android->process_gravity(gravity);
+
os_android->process_magnetometer(magnetometer);
os_android->process_gyroscope(gyroscope);
@@ -1386,6 +1389,10 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv
accelerometer = Vector3(x, y, z);
}
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
+ gravity = Vector3(x, y, z);
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z) {
magnetometer = Vector3(x, y, z);
}
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
index 0aa2489813..4790c65617 100644
--- a/platform/android/java_glue.h
+++ b/platform/android/java_glue.h
@@ -50,6 +50,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jobject obj, jint p_device, jboolean p_connected, jstring p_name);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jobject obj);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env, jobject obj, jfloat x, jfloat y, jfloat z);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jobject obj);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 970e0cdf68..a36df0675c 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -490,6 +490,11 @@ void OS_Android::process_accelerometer(const Vector3 &p_accelerometer) {
input->set_accelerometer(p_accelerometer);
}
+void OS_Android::process_gravity(const Vector3 &p_gravity) {
+
+ input->set_gravity(p_gravity);
+}
+
void OS_Android::process_magnetometer(const Vector3 &p_magnetometer) {
input->set_magnetometer(p_magnetometer);
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index fee91b9a55..750afa7a14 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -219,6 +219,7 @@ public:
virtual String get_system_dir(SystemDir p_dir) const;
void process_accelerometer(const Vector3 &p_accelerometer);
+ void process_gravity(const Vector3 &p_gravity);
void process_magnetometer(const Vector3 &p_magnetometer);
void process_gyroscope(const Vector3 &p_gyroscope);
void process_touch(int p_what, int p_pointer, const Vector<TouchPos> &p_points);
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index 993a93ff89..d426b478bf 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -76,11 +76,22 @@ def configure(env):
env['ENV']['PATH'] = env['IPHONEPATH'] + "/Developer/usr/bin/:" + env['ENV']['PATH']
- env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang'
- env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++'
- env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar'
- env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib'
- env['S_compiler'] = '$IPHONEPATH/Developer/usr/bin/gcc'
+ compiler_path = '$IPHONEPATH/usr/bin/${ios_triple}'
+ s_compiler_path = '$IPHONEPATH/Developer/usr/bin/'
+
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = compiler_path + 'clang'
+ env['CXX'] = compiler_path + 'clang++'
+ env['S_compiler'] = s_compiler_path + 'gcc'
+ else:
+ # there aren't any ccache wrappers available for iOS,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + compiler_path + 'clang'
+ env['CXX'] = ccache_path + ' ' + compiler_path + 'clang++'
+ env['S_compiler'] = ccache_path + ' ' + s_compiler_path + 'gcc'
+ env['AR'] = compiler_path + 'ar'
+ env['RANLIB'] = compiler_path + 'ranlib'
## Compile flags
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index cfc0741318..e3015d87b9 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -7,6 +7,7 @@ javascript_files = [
"audio_driver_javascript.cpp",
"javascript_main.cpp",
"power_javascript.cpp",
+ "http_client_javascript.cpp",
"javascript_eval.cpp",
]
@@ -42,6 +43,12 @@ else:
js = env.Program(['#bin/godot'] + implicit_targets, javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js')[0];
zip_files.append(InstallAs(zip_dir.File('godot.js'), js))
+js_libraries = []
+js_libraries.append(env.File('http_request.js'))
+for lib in js_libraries:
+ env.Append(LINKFLAGS=['--js-library', lib.path])
+env.Depends(js, js_libraries)
+
postjs = env.File('engine.js')
env.Depends(js, [prejs, postjs])
env.Append(LINKFLAGS=['--pre-js', prejs.path])
diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc
new file mode 100644
index 0000000000..9e4edf7848
--- /dev/null
+++ b/platform/javascript/http_client.h.inc
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* http_client.h.inc */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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. */
+/*************************************************************************/
+
+// HTTPClient's additional private members in the javascript platform
+
+Error prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers);
+
+int xhr_id;
+int read_limit;
+int response_read_offset;
+Status status;
+
+String host;
+int port;
+bool use_tls;
+String username;
+String password;
+
+int polled_response_code;
+String polled_response_header;
+PoolByteArray polled_response;
diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp
new file mode 100644
index 0000000000..0b105dcb40
--- /dev/null
+++ b/platform/javascript/http_client_javascript.cpp
@@ -0,0 +1,282 @@
+/*************************************************************************/
+/* http_client_javascript.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 "http_request.h"
+#include "io/http_client.h"
+
+Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) {
+
+ close();
+ if (p_ssl && !p_verify_host) {
+ WARN_PRINT("Disabling HTTPClient's host verification is not supported for the HTML5 platform, host will be verified");
+ }
+
+ host = p_host;
+ if (host.begins_with("http://")) {
+ host.replace_first("http://", "");
+ } else if (host.begins_with("https://")) {
+ host.replace_first("https://", "");
+ }
+
+ status = host.is_valid_ip_address() ? STATUS_CONNECTING : STATUS_RESOLVING;
+ port = p_port;
+ use_tls = p_ssl;
+ return OK;
+}
+
+void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
+
+ ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform");
+ ERR_FAIL();
+}
+
+Ref<StreamPeer> HTTPClient::get_connection() const {
+
+ ERR_EXPLAIN("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform");
+ ERR_FAIL_V(REF());
+}
+
+Error HTTPClient::prepare_request(Method p_method, const String &p_url, const Vector<String> &p_headers) {
+
+ ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(host.empty(), ERR_UNCONFIGURED);
+ ERR_FAIL_COND_V(port < 0, ERR_UNCONFIGURED);
+
+ static const char *_methods[HTTPClient::METHOD_MAX] = {
+ "GET",
+ "HEAD",
+ "POST",
+ "PUT",
+ "DELETE",
+ "OPTIONS",
+ "TRACE",
+ "CONNECT"
+ };
+
+ String url = (use_tls ? "https://" : "http://") + host + ":" + itos(port) + "/" + p_url;
+ godot_xhr_reset(xhr_id);
+ godot_xhr_open(xhr_id, _methods[p_method], url.utf8().get_data(),
+ username.empty() ? NULL : username.utf8().get_data(),
+ password.empty() ? NULL : password.utf8().get_data());
+
+ for (int i = 0; i < p_headers.size(); i++) {
+ int header_separator = p_headers[i].find(": ");
+ ERR_FAIL_COND_V(header_separator < 0, ERR_INVALID_PARAMETER);
+ godot_xhr_set_request_header(xhr_id,
+ p_headers[i].left(header_separator).utf8().get_data(),
+ p_headers[i].right(header_separator + 2).utf8().get_data());
+ }
+ response_read_offset = 0;
+ status = STATUS_REQUESTING;
+ return OK;
+}
+
+Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const PoolVector<uint8_t> &p_body) {
+
+ Error err = prepare_request(p_method, p_url, p_headers);
+ if (err != OK)
+ return err;
+ PoolByteArray::Read read = p_body.read();
+ godot_xhr_send_data(xhr_id, read.ptr(), p_body.size());
+ return OK;
+}
+
+Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
+
+ Error err = prepare_request(p_method, p_url, p_headers);
+ if (err != OK)
+ return err;
+ godot_xhr_send_string(xhr_id, p_body.utf8().get_data());
+ return OK;
+}
+
+void HTTPClient::close() {
+
+ host = "";
+ port = -1;
+ use_tls = false;
+ status = STATUS_DISCONNECTED;
+ polled_response.resize(0);
+ polled_response_code = 0;
+ polled_response_header = String();
+ godot_xhr_reset(xhr_id);
+}
+
+HTTPClient::Status HTTPClient::get_status() const {
+
+ return status;
+}
+
+bool HTTPClient::has_response() const {
+
+ return !polled_response_header.empty();
+}
+
+bool HTTPClient::is_response_chunked() const {
+
+ // TODO evaluate using moz-chunked-arraybuffer, fetch & ReadableStream
+ return false;
+}
+
+int HTTPClient::get_response_code() const {
+
+ return polled_response_code;
+}
+
+Error HTTPClient::get_response_headers(List<String> *r_response) {
+
+ if (!polled_response_header.size())
+ return ERR_INVALID_PARAMETER;
+
+ Vector<String> header_lines = polled_response_header.split("\r\n", false);
+ for (int i = 0; i < header_lines.size(); ++i) {
+ r_response->push_back(header_lines[i]);
+ }
+ polled_response_header = String();
+ return OK;
+}
+
+int HTTPClient::get_response_body_length() const {
+
+ return polled_response.size();
+}
+
+PoolByteArray HTTPClient::read_response_body_chunk() {
+
+ ERR_FAIL_COND_V(status != STATUS_BODY, PoolByteArray());
+
+ int to_read = MIN(read_limit, polled_response.size() - response_read_offset);
+ PoolByteArray chunk;
+ chunk.resize(to_read);
+ PoolByteArray::Write write = chunk.write();
+ PoolByteArray::Read read = polled_response.read();
+ memcpy(write.ptr(), read.ptr() + response_read_offset, to_read);
+ write = PoolByteArray::Write();
+ read = PoolByteArray::Read();
+ response_read_offset += to_read;
+
+ if (response_read_offset == polled_response.size()) {
+ status = STATUS_CONNECTED;
+ polled_response.resize(0);
+ polled_response_code = 0;
+ polled_response_header = String();
+ godot_xhr_reset(xhr_id);
+ }
+
+ return chunk;
+}
+
+void HTTPClient::set_blocking_mode(bool p_enable) {
+
+ ERR_EXPLAIN("HTTPClient blocking mode is not supported for the HTML5 platform");
+ ERR_FAIL_COND(p_enable);
+}
+
+bool HTTPClient::is_blocking_mode_enabled() const {
+
+ return false;
+}
+
+void HTTPClient::set_read_chunk_size(int p_size) {
+
+ read_limit = p_size;
+}
+
+Error HTTPClient::poll() {
+
+ switch (status) {
+
+ case STATUS_DISCONNECTED:
+ return ERR_UNCONFIGURED;
+
+ case STATUS_RESOLVING:
+ status = STATUS_CONNECTING;
+ return OK;
+
+ case STATUS_CONNECTING:
+ status = STATUS_CONNECTED;
+ return OK;
+
+ case STATUS_CONNECTED:
+ case STATUS_BODY:
+ return OK;
+
+ case STATUS_CONNECTION_ERROR:
+ return ERR_CONNECTION_ERROR;
+
+ case STATUS_REQUESTING:
+ polled_response_code = godot_xhr_get_status(xhr_id);
+ int response_length = godot_xhr_get_response_length(xhr_id);
+ if (response_length == 0) {
+ godot_xhr_ready_state_t ready_state = godot_xhr_get_ready_state(xhr_id);
+ if (ready_state == XHR_READY_STATE_HEADERS_RECEIVED || ready_state == XHR_READY_STATE_LOADING) {
+ return OK;
+ } else {
+ status = STATUS_CONNECTION_ERROR;
+ return ERR_CONNECTION_ERROR;
+ }
+ }
+
+ status = STATUS_BODY;
+
+ PoolByteArray bytes;
+ int len = godot_xhr_get_response_headers_length(xhr_id);
+ bytes.resize(len);
+ PoolByteArray::Write write = bytes.write();
+ godot_xhr_get_response_headers(xhr_id, reinterpret_cast<char *>(write.ptr()), len);
+ write = PoolByteArray::Write();
+
+ PoolByteArray::Read read = bytes.read();
+ polled_response_header = String::utf8(reinterpret_cast<const char *>(read.ptr()));
+ read = PoolByteArray::Read();
+
+ polled_response.resize(response_length);
+ write = polled_response.write();
+ godot_xhr_get_response(xhr_id, write.ptr(), response_length);
+ write = PoolByteArray::Write();
+ break;
+ }
+ return OK;
+}
+
+HTTPClient::HTTPClient() {
+
+ xhr_id = godot_xhr_new();
+ read_limit = 4096;
+ status = STATUS_DISCONNECTED;
+ port = -1;
+ use_tls = false;
+ polled_response_code = 0;
+}
+
+HTTPClient::~HTTPClient() {
+
+ godot_xhr_free(xhr_id);
+}
diff --git a/platform/javascript/http_request.h b/platform/javascript/http_request.h
new file mode 100644
index 0000000000..80ff3f0ba8
--- /dev/null
+++ b/platform/javascript/http_request.h
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* http_request.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.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 HTTP_REQUEST_H
+#define HTTP_REQUEST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ XHR_READY_STATE_UNSENT = 0,
+ XHR_READY_STATE_OPENED = 1,
+ XHR_READY_STATE_HEADERS_RECEIVED = 2,
+ XHR_READY_STATE_LOADING = 3,
+ XHR_READY_STATE_DONE = 4,
+} godot_xhr_ready_state_t;
+
+extern int godot_xhr_new();
+extern void godot_xhr_reset(int p_xhr_id);
+extern bool godot_xhr_free(int p_xhr_id);
+
+extern int godot_xhr_open(int p_xhr_id, const char *p_method, const char *p_url, const char *p_user = NULL, const char *p_password = NULL);
+
+extern void godot_xhr_set_request_header(int p_xhr_id, const char *p_header, const char *p_value);
+
+extern void godot_xhr_send_null(int p_xhr_id);
+extern void godot_xhr_send_string(int p_xhr_id, const char *p_data);
+extern void godot_xhr_send_data(int p_xhr_id, const void *p_data, int p_len);
+extern void godot_xhr_abort(int p_xhr_id);
+
+/* this is an HTTPClient::ResponseCode, not ::Status */
+extern int godot_xhr_get_status(int p_xhr_id);
+extern godot_xhr_ready_state_t godot_xhr_get_ready_state(int p_xhr_id);
+
+extern int godot_xhr_get_response_headers_length(int p_xhr_id);
+extern void godot_xhr_get_response_headers(int p_xhr_id, char *r_dst, int p_len);
+
+extern int godot_xhr_get_response_length(int p_xhr_id);
+extern void godot_xhr_get_response(int p_xhr_id, void *r_dst, int p_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HTTP_REQUEST_H */
diff --git a/platform/javascript/http_request.js b/platform/javascript/http_request.js
new file mode 100644
index 0000000000..f30240b41b
--- /dev/null
+++ b/platform/javascript/http_request.js
@@ -0,0 +1,145 @@
+/*************************************************************************/
+/* http_request.js */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+var GodotHTTPRequest = {
+
+ $GodotHTTPRequest: {
+
+ requests: [],
+
+ getUnusedRequestId: function() {
+ var idMax = GodotHTTPRequest.requests.length;
+ for (var potentialId = 0; potentialId < idMax; ++potentialId) {
+ if (GodotHTTPRequest.requests[potentialId] instanceof XMLHttpRequest) {
+ continue;
+ }
+ return potentialId;
+ }
+ GodotHTTPRequest.requests.push(null)
+ return idMax;
+ },
+
+ setupRequest: function(xhr) {
+ xhr.responseType = 'arraybuffer';
+ },
+ },
+
+ godot_xhr_new: function() {
+ var newId = GodotHTTPRequest.getUnusedRequestId();
+ GodotHTTPRequest.requests[newId] = new XMLHttpRequest;
+ GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[newId]);
+ return newId;
+ },
+
+ godot_xhr_reset: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId] = new XMLHttpRequest;
+ GodotHTTPRequest.setupRequest(GodotHTTPRequest.requests[xhrId]);
+ },
+
+ godot_xhr_free: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].abort();
+ GodotHTTPRequest.requests[xhrId] = null;
+ },
+
+ godot_xhr_open: function(xhrId, method, url, user, password) {
+ user = user > 0 ? UTF8ToString(user) : null;
+ password = password > 0 ? UTF8ToString(password) : null;
+ GodotHTTPRequest.requests[xhrId].open(UTF8ToString(method), UTF8ToString(url), true, user, password);
+ },
+
+ godot_xhr_set_request_header: function(xhrId, header, value) {
+ GodotHTTPRequest.requests[xhrId].setRequestHeader(UTF8ToString(header), UTF8ToString(value));
+ },
+
+ godot_xhr_send_null: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].send();
+ },
+
+ godot_xhr_send_string: function(xhrId, strPtr) {
+ if (!strPtr) {
+ Module.printErr("Failed to send string per XHR: null pointer");
+ return;
+ }
+ GodotHTTPRequest.requests[xhrId].send(UTF8ToString(strPtr));
+ },
+
+ godot_xhr_send_data: function(xhrId, ptr, len) {
+ if (!ptr) {
+ Module.printErr("Failed to send data per XHR: null pointer");
+ return;
+ }
+ if (len < 0) {
+ Module.printErr("Failed to send data per XHR: buffer length less than 0");
+ return;
+ }
+ GodotHTTPRequest.requests[xhrId].send(HEAPU8.subarray(ptr, ptr + len));
+ },
+
+ godot_xhr_abort: function(xhrId) {
+ GodotHTTPRequest.requests[xhrId].abort();
+ },
+
+ godot_xhr_get_status: function(xhrId) {
+ return GodotHTTPRequest.requests[xhrId].status;
+ },
+
+ godot_xhr_get_ready_state: function(xhrId) {
+ return GodotHTTPRequest.requests[xhrId].readyState;
+ },
+
+ godot_xhr_get_response_headers_length: function(xhrId) {
+ var headers = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
+ return headers === null ? 0 : lengthBytesUTF8(headers);
+ },
+
+ godot_xhr_get_response_headers: function(xhrId, dst, len) {
+ var str = GodotHTTPRequest.requests[xhrId].getAllResponseHeaders();
+ if (str === null)
+ return;
+ var buf = new Uint8Array(len + 1);
+ stringToUTF8Array(str, buf, 0, buf.length);
+ buf = buf.subarray(0, -1);
+ HEAPU8.set(buf, dst);
+ },
+
+ godot_xhr_get_response_length: function(xhrId) {
+ var body = GodotHTTPRequest.requests[xhrId].response;
+ return body === null ? 0 : body.byteLength;
+ },
+
+ godot_xhr_get_response: function(xhrId, dst, len) {
+ var buf = GodotHTTPRequest.requests[xhrId].response;
+ if (buf === null)
+ return;
+ buf = new Uint8Array(buf).subarray(0, len);
+ HEAPU8.set(buf, dst);
+ },
+};
+
+autoAddDeps(GodotHTTPRequest, "$GodotHTTPRequest");
+mergeInto(LibraryManager.library, GodotHTTPRequest);
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index e5bdcec30d..389d5d206e 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -166,14 +166,15 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent
}
int mask = _input->get_mouse_button_mask();
+ int button_flag = 1 << (ev->get_button_index() - 1);
if (ev->is_pressed()) {
// since the event is consumed, focus manually
if (!is_canvas_focused()) {
focus_canvas();
}
- mask |= ev->get_button_index();
- } else if (mask & ev->get_button_index()) {
- mask &= ~ev->get_button_index();
+ mask |= button_flag;
+ } else if (mask & button_flag) {
+ mask &= ~button_flag;
} else {
// release event, but press was outside the canvas, so ignore
return false;
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 31032659b6..c24bd98bf6 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -84,8 +84,15 @@ def configure(env):
else: # 64-bit, default
basecmd = root + "/target/bin/x86_64-apple-" + env["osxcross_sdk"] + "-"
- env['CC'] = basecmd + "cc"
- env['CXX'] = basecmd + "c++"
+ ccache_path = os.environ.get("CCACHE")
+ if ccache_path == None:
+ env['CC'] = basecmd + "cc"
+ env['CXX'] = basecmd + "c++"
+ else:
+ # there aren't any ccache wrappers available for OS X cross-compile,
+ # to enable caching we need to prepend the path to the ccache binary
+ env['CC'] = ccache_path + ' ' + basecmd + "cc"
+ env['CXX'] = ccache_path + ' ' + basecmd + "c++"
env['AR'] = basecmd + "ar"
env['RANLIB'] = basecmd + "ranlib"
env['AS'] = basecmd + "as"
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 64b6d202a1..8571f0dc65 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -165,7 +165,7 @@ Error ContextGL_Win::initialize() {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
WGL_CONTEXT_MINOR_VERSION_ARB, 3,
//and it shall be forward compatible so that we can only use up to date functionality
- WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | _WGL_CONTEXT_DEBUG_BIT_ARB,
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/,
0
}; //zero indicates the end of the array
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
index 058b162e83..08b01c6a4c 100644
--- a/scene/audio/audio_player.cpp
+++ b/scene/audio/audio_player.cpp
@@ -31,20 +31,7 @@
#include "engine.h"
-void AudioStreamPlayer::_mix_audio() {
-
- if (!stream_playback.is_valid()) {
- return;
- }
-
- if (!active) {
- return;
- }
-
- if (setseek >= 0.0) {
- stream_playback->start(setseek);
- setseek = -1.0; //reset seek
- }
+void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
int bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
@@ -52,19 +39,24 @@ void AudioStreamPlayer::_mix_audio() {
AudioFrame *buffer = mix_buffer.ptr();
int buffer_size = mix_buffer.size();
+ if (p_fadeout) {
+ buffer_size = MIN(buffer_size, 16); //short fadeout ramp
+ }
+
//mix
stream_playback->mix(buffer, 1.0, buffer_size);
//multiply volume interpolating to avoid clicks if this changes
+ float target_volume = p_fadeout ? -80.0 : volume_db;
float vol = Math::db2linear(mix_volume_db);
- float vol_inc = (Math::db2linear(volume_db) - vol) / float(buffer_size);
+ float vol_inc = (Math::db2linear(target_volume) - vol) / float(buffer_size);
for (int i = 0; i < buffer_size; i++) {
buffer[i] *= vol;
vol += vol_inc;
}
//set volume for next mix
- mix_volume_db = volume_db;
+ mix_volume_db = target_volume;
AudioFrame *targets[4] = { NULL, NULL, NULL, NULL };
@@ -95,6 +87,30 @@ void AudioStreamPlayer::_mix_audio() {
}
}
+void AudioStreamPlayer::_mix_audio() {
+
+ if (!stream_playback.is_valid()) {
+ return;
+ }
+
+ if (!active) {
+ return;
+ }
+
+ if (setseek >= 0.0) {
+ if (stream_playback->is_playing()) {
+
+ //fade out to avoid pops
+ _mix_internal(true);
+ }
+ stream_playback->start(setseek);
+ setseek = -1.0; //reset seek
+ mix_volume_db = volume_db; //reset ramp
+ }
+
+ _mix_internal(false);
+}
+
void AudioStreamPlayer::_notification(int p_what) {
if (p_what == NOTIFICATION_ENTER_TREE) {
@@ -163,7 +179,7 @@ float AudioStreamPlayer::get_volume_db() const {
void AudioStreamPlayer::play(float p_from_pos) {
if (stream_playback.is_valid()) {
- mix_volume_db = volume_db; //reset volume ramp
+ //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks
setseek = p_from_pos;
active = true;
set_process_internal(true);
diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h
index 4bfc44730d..6e9d623433 100644
--- a/scene/audio/audio_player.h
+++ b/scene/audio/audio_player.h
@@ -59,6 +59,7 @@ private:
MixTarget mix_target;
+ void _mix_internal(bool p_fadeout);
void _mix_audio();
static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer *>(self)->_mix_audio(); }
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 623a110263..e9e9dcc859 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -754,7 +754,7 @@ void ItemList::_notification(int p_what) {
int width = size.width - bg->get_minimum_size().width;
if (scroll_bar->is_visible()) {
- width -= mw + bg->get_margin(MARGIN_RIGHT);
+ width -= mw;
}
draw_style_box(bg, Rect2(Point2(), size));
@@ -1107,7 +1107,7 @@ void ItemList::_notification(int p_what) {
}
for (int i = 0; i < separators.size(); i++) {
- draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(size.width - bg->get_margin(MARGIN_RIGHT), base_ofs.y + separators[i]), guide_color);
+ draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(width, base_ofs.y + separators[i]), guide_color);
}
}
}
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 1ad1e3f638..9022d67a4a 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -347,12 +347,11 @@ void ScrollContainer::update_scrollbars() {
} else {
v_scroll->show();
+ v_scroll->set_max(min.height);
+ v_scroll->set_page(size.height - hmin.height);
scroll.y = v_scroll->get_value();
}
- v_scroll->set_max(min.height);
- v_scroll->set_page(size.height - hmin.height);
-
if (!scroll_h || min.width <= size.width - vmin.width) {
h_scroll->hide();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 5d4048f928..5d429f9f91 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3668,6 +3668,11 @@ void TextEdit::set_readonly(bool p_readonly) {
readonly = p_readonly;
}
+bool TextEdit::is_readonly() const {
+
+ return readonly;
+}
+
void TextEdit::set_wrap(bool p_wrap) {
wrap = p_wrap;
@@ -4919,6 +4924,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode);
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
+ ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
+
ClassDB::bind_method(D_METHOD("set_wrap", "enable"), &TextEdit::set_wrap);
ClassDB::bind_method(D_METHOD("set_max_chars", "amount"), &TextEdit::set_max_chars);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled);
@@ -4969,6 +4976,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "readonly"), "set_readonly", "is_readonly");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index c81b41c2e3..50f005ed6a 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -448,6 +448,7 @@ public:
bool cursor_is_block_mode() const;
void set_readonly(bool p_readonly);
+ bool is_readonly() const;
void set_max_chars(int p_max_chars);
void set_wrap(bool p_wrap);
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 190ccd50d5..1b6bd30b58 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -42,44 +42,127 @@ void VideoPlayer::sp_set_mix_rate(int p_rate) {
server_mix_rate = p_rate;
}
-bool VideoPlayer::sp_mix(int32_t *p_buffer, int p_frames) {
-
- if (resampler.is_ready()) {
+bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) {
+
+ // Check the amount resampler can really handle.
+ // If it cannot, wait "wait_resampler_phase_limit" times.
+ // This mechanism contributes to smoother pause/unpause operation.
+ if (p_frames <= resampler.get_num_of_ready_frames() ||
+ wait_resampler_limit <= wait_resampler) {
+ wait_resampler = 0;
return resampler.mix(p_buffer, p_frames);
}
-
+ wait_resampler++;
return false;
}
-int VideoPlayer::_audio_mix_callback(void *p_udata, const int16_t *p_data, int p_frames) {
+// Called from main thread (eg VideoStreamPlaybackWebm::update)
+int VideoPlayer::_audio_mix_callback(void *p_udata, const float *p_data, int p_frames) {
VideoPlayer *vp = (VideoPlayer *)p_udata;
- int todo = MIN(vp->resampler.get_todo(), p_frames);
+ int todo = MIN(vp->resampler.get_writer_space(), p_frames);
- int16_t *wb = vp->resampler.get_write_buffer();
+ float *wb = vp->resampler.get_write_buffer();
int c = vp->resampler.get_channel_count();
for (int i = 0; i < todo * c; i++) {
wb[i] = p_data[i];
}
vp->resampler.write(todo);
+
return todo;
}
+// Called from audio thread
+void VideoPlayer::_mix_audio() {
+
+ if (!stream.is_valid()) {
+ return;
+ }
+ if (!playback.is_valid() || !playback->is_playing() || playback->is_paused()) {
+ return;
+ }
+
+ AudioFrame *buffer = mix_buffer.ptr();
+ int buffer_size = mix_buffer.size();
+
+ // Resample
+ if (!mix(buffer, buffer_size))
+ return;
+
+ AudioFrame vol = AudioFrame(volume, volume);
+
+ // Copy to server's audio buffer
+ switch (AudioServer::get_singleton()->get_speaker_mode()) {
+
+ case AudioServer::SPEAKER_MODE_STEREO: {
+ AudioFrame *target = AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 0);
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ target[j] += buffer[j] * vol;
+ }
+
+ } break;
+ case AudioServer::SPEAKER_SURROUND_51: {
+
+ AudioFrame *targets[2] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] = frame;
+ targets[1][j] = frame;
+ }
+ } break;
+ case AudioServer::SPEAKER_SURROUND_71: {
+
+ AudioFrame *targets[3] = {
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 1),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 2),
+ AudioServer::get_singleton()->thread_get_channel_mix_buffer(bus_index, 3)
+ };
+
+ for (int j = 0; j < buffer_size; j++) {
+
+ AudioFrame frame = buffer[j] * vol;
+ targets[0][j] += frame;
+ targets[1][j] += frame;
+ targets[2][j] += frame;
+ }
+
+ } break;
+ }
+}
+
void VideoPlayer::_notification(int p_notification) {
switch (p_notification) {
case NOTIFICATION_ENTER_TREE: {
+ AudioServer::get_singleton()->add_callback(_mix_audios, this);
+
if (stream.is_valid() && autoplay && !Engine::get_singleton()->is_editor_hint()) {
play();
}
+
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+
+ AudioServer::get_singleton()->remove_callback(_mix_audios, this);
+
} break;
case NOTIFICATION_INTERNAL_PROCESS: {
+ bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
+
if (stream.is_null())
return;
if (paused)
@@ -87,10 +170,11 @@ void VideoPlayer::_notification(int p_notification) {
if (!playback->is_playing())
return;
- double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec()); //AudioServer::get_singleton()->get_mix_time();
+ double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec());
double delta = last_audio_time == 0 ? 0 : audio_time - last_audio_time;
last_audio_time = audio_time;
+
if (delta == 0)
return;
@@ -135,6 +219,9 @@ bool VideoPlayer::has_expand() const {
void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
+ AudioServer::get_singleton()->lock();
+ mix_buffer.resize(AudioServer::get_singleton()->thread_get_mix_buffer_size());
+ AudioServer::get_singleton()->unlock();
stream = p_stream;
if (stream.is_valid()) {
@@ -309,6 +396,40 @@ bool VideoPlayer::has_autoplay() const {
return autoplay;
};
+void VideoPlayer::set_bus(const StringName &p_bus) {
+
+ //if audio is active, must lock this
+ AudioServer::get_singleton()->lock();
+ bus = p_bus;
+ AudioServer::get_singleton()->unlock();
+}
+
+StringName VideoPlayer::get_bus() const {
+
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (AudioServer::get_singleton()->get_bus_name(i) == bus) {
+ return bus;
+ }
+ }
+ return "Master";
+}
+
+void VideoPlayer::_validate_property(PropertyInfo &property) const {
+
+ if (property.name == "bus") {
+
+ String options;
+ for (int i = 0; i < AudioServer::get_singleton()->get_bus_count(); i++) {
+ if (i > 0)
+ options += ",";
+ String name = AudioServer::get_singleton()->get_bus_name(i);
+ options += name;
+ }
+
+ property.hint_string = options;
+ }
+}
+
void VideoPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &VideoPlayer::set_stream);
@@ -345,6 +466,9 @@ void VideoPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_buffering_msec", "msec"), &VideoPlayer::set_buffering_msec);
ClassDB::bind_method(D_METHOD("get_buffering_msec"), &VideoPlayer::get_buffering_msec);
+ ClassDB::bind_method(D_METHOD("set_bus", "bus"), &VideoPlayer::set_bus);
+ ClassDB::bind_method(D_METHOD("get_bus"), &VideoPlayer::get_bus);
+
ClassDB::bind_method(D_METHOD("get_video_texture"), &VideoPlayer::get_video_texture);
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_track", PROPERTY_HINT_RANGE, "0,128,1"), "set_audio_track", "get_audio_track");
@@ -354,6 +478,7 @@ void VideoPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
}
VideoPlayer::VideoPlayer() {
@@ -372,6 +497,9 @@ VideoPlayer::VideoPlayer() {
// internal_stream.player=this;
// stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
last_audio_time = 0;
+
+ wait_resampler = 0;
+ wait_resampler_limit = 2;
};
VideoPlayer::~VideoPlayer() {
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index f04e90365f..74e2f14e58 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -33,17 +33,24 @@
#include "scene/gui/control.h"
#include "scene/resources/video_stream.h"
#include "servers/audio/audio_rb_resampler.h"
+#include "servers/audio_server.h"
class VideoPlayer : public Control {
GDCLASS(VideoPlayer, Control);
+ struct Output {
+
+ AudioFrame vol;
+ int bus_index;
+ Viewport *viewport; //pointer only used for reference to previous mix
+ };
Ref<VideoStreamPlayback> playback;
Ref<VideoStream> stream;
int sp_get_channel_count() const;
void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
- bool sp_mix(int32_t *p_buffer, int p_frames);
+ bool mix(AudioFrame *p_buffer, int p_frames);
RID stream_rid;
@@ -51,6 +58,8 @@ class VideoPlayer : public Control {
Ref<Image> last_frame;
AudioRBResampler resampler;
+ Vector<AudioFrame> mix_buffer;
+ int wait_resampler, wait_resampler_limit;
bool paused;
bool autoplay;
@@ -61,12 +70,18 @@ class VideoPlayer : public Control {
int buffering_ms;
int server_mix_rate;
int audio_track;
+ int bus_index;
+
+ StringName bus;
- static int _audio_mix_callback(void *p_udata, const int16_t *p_data, int p_frames);
+ void _mix_audio();
+ static int _audio_mix_callback(void *p_udata, const float *p_data, int p_frames);
+ static void _mix_audios(void *self) { reinterpret_cast<VideoPlayer *>(self)->_mix_audio(); }
protected:
static void _bind_methods();
void _notification(int p_notification);
+ void _validate_property(PropertyInfo &property) const;
public:
Size2 get_minimum_size() const;
@@ -104,6 +119,9 @@ public:
void set_buffering_msec(int p_msec);
int get_buffering_msec() const;
+ void set_bus(const StringName &p_bus);
+ StringName get_bus() const;
+
VideoPlayer();
~VideoPlayer();
};
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index e6e11de177..d38c688241 100755
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2067,7 +2067,7 @@ int Node::get_position_in_parent() const {
return data.pos;
}
-Node *Node::_duplicate(int p_flags) const {
+Node *Node::duplicate(int p_flags) const {
Node *node = NULL;
@@ -2170,17 +2170,6 @@ Node *Node::_duplicate(int p_flags) const {
return node;
}
-Node *Node::duplicate(int p_flags) const {
-
- Node *dupe = _duplicate(p_flags);
-
- if (dupe && (p_flags & DUPLICATE_SIGNALS)) {
- _duplicate_signals(this, dupe);
- }
-
- return dupe;
-}
-
void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const {
if (get_owner() != get_parent()->get_owner())
@@ -2422,7 +2411,9 @@ void Node::_replace_connections_target(Node *p_new_target) {
if (c.flags & CONNECT_PERSIST) {
c.source->disconnect(c.signal, this, c.method);
- ERR_CONTINUE(!p_new_target->has_method(c.method));
+ bool valid = p_new_target->has_method(c.method) || p_new_target->get_script().is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.method);
+ ERR_EXPLAIN("Attempt to connect signal \'" + c.source->get_class() + "." + c.signal + "\' to nonexistent method \'" + c.target->get_class() + "." + c.method + "\'");
+ ERR_CONTINUE(!valid);
c.source->connect(c.signal, p_new_target, c.method, c.binds, c.flags);
}
}
diff --git a/scene/main/node.h b/scene/main/node.h
index c43e96063f..e8901f7b6e 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -169,7 +169,6 @@ private:
void _duplicate_signals(const Node *p_original, Node *p_copy) const;
void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const;
- Node *_duplicate(int p_flags) const;
Array _get_children() const;
Array _get_groups() const;
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index fdc3b79db6..f81f460521 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -31,17 +31,23 @@
void AudioStreamPlaybackSample::start(float p_from_pos) {
- for (int i = 0; i < 2; i++) {
- ima_adpcm[i].step_index = 0;
- ima_adpcm[i].predictor = 0;
- ima_adpcm[i].loop_step_index = 0;
- ima_adpcm[i].loop_predictor = 0;
- ima_adpcm[i].last_nibble = -1;
- ima_adpcm[i].loop_pos = 0x7FFFFFFF;
- ima_adpcm[i].window_ofs = 0;
+ if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) {
+ //no seeking in IMA_ADPCM
+ for (int i = 0; i < 2; i++) {
+ ima_adpcm[i].step_index = 0;
+ ima_adpcm[i].predictor = 0;
+ ima_adpcm[i].loop_step_index = 0;
+ ima_adpcm[i].loop_predictor = 0;
+ ima_adpcm[i].last_nibble = -1;
+ ima_adpcm[i].loop_pos = 0x7FFFFFFF;
+ ima_adpcm[i].window_ofs = 0;
+ }
+
+ offset = 0;
+ } else {
+ seek(p_from_pos);
}
- seek(p_from_pos);
sign = 1;
active = true;
}
@@ -373,6 +379,14 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
dst_buff += target;
}
+
+ if (todo) {
+ //bit was missing from mix
+ int todo_ofs = p_frames - todo;
+ for (int i = todo_ofs; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+ }
}
float AudioStreamPlaybackSample::get_length() const {
diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp
index 91263fb125..4aa47cb664 100644
--- a/scene/resources/dynamic_font_stb.cpp
+++ b/scene/resources/dynamic_font_stb.cpp
@@ -333,8 +333,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
//blit to image and texture
{
-
- Image img(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, tex.imgdata);
+ Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, tex.imgdata));
if (tex.texture.is_null()) {
tex.texture.instance();
@@ -518,7 +517,7 @@ bool ResourceFormatLoaderDynamicFont::handles_type(const String &p_type) const {
String ResourceFormatLoaderDynamicFont::get_resource_type(const String &p_path) const {
- String el = p_path.extension().to_lower();
+ String el = p_path.get_extension().to_lower();
if (el == "ttf")
return "DynamicFontData";
return "";
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 232f690074..fe59450f2e 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1184,7 +1184,8 @@ Environment::Environment() {
bg_energy = 1.0;
bg_canvas_max_layer = 0;
ambient_energy = 1.0;
- ambient_sky_contribution = 1.0;
+ //ambient_sky_contribution = 1.0;
+ set_ambient_light_sky_contribution(1.0);
tone_mapper = TONE_MAPPER_LINEAR;
tonemap_exposure = 1.0;
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index db5d87d703..26f5deae1d 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -574,7 +574,6 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND_V(!d.has("format"), false);
uint32_t format = d["format"];
- ERR_FAIL_COND_V(!d.has("primitive"), false);
uint32_t primitive = d["primitive"];
ERR_FAIL_COND_V(!d.has("vertex_count"), false);
@@ -598,8 +597,8 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
Rect3 aabb = d["aabb"];
Vector<Rect3> bone_aabb;
- if (d.has("bone_aabb")) {
- Array baabb = d["bone_aabb"];
+ if (d.has("skeleton_aabb")) {
+ Array baabb = d["skeleton_aabb"];
bone_aabb.resize(baabb.size());
for (int i = 0; i < baabb.size(); i++) {
@@ -1090,6 +1089,14 @@ void ArrayMesh::_bind_methods() {
BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX);
}
+void ArrayMesh::reload_from_file() {
+ for (int i = 0; i < get_surface_count(); i++) {
+ surface_remove(i);
+ }
+ Resource::reload_from_file();
+ String path = get_path();
+}
+
ArrayMesh::ArrayMesh() {
mesh = VisualServer::get_singleton()->mesh_create();
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index f4edb258b6..b11adf50b9 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -213,6 +213,8 @@ public:
void center_geometry();
void regen_normalmaps();
+ virtual void reload_from_file();
+
ArrayMesh();
~ArrayMesh();
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index ba356d89b1..8e3899315c 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -1299,14 +1299,16 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
tangents.resize(4 * 4);
uvs.resize(4);
- for (int i = 0; i < 4; i++) {
+ Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f);
- static const Vector3 quad_faces[4] = {
- Vector3(-1, -1, 0),
- Vector3(-1, 1, 0),
- Vector3(1, 1, 0),
- Vector3(1, -1, 0),
- };
+ Vector3 quad_faces[4] = {
+ Vector3(-_size.x, -_size.y, 0),
+ Vector3(-_size.x, _size.y, 0),
+ Vector3(_size.x, _size.y, 0),
+ Vector3(_size.x, -_size.y, 0),
+ };
+
+ for (int i = 0; i < 4; i++) {
faces.set(i, quad_faces[i]);
normals.set(i, Vector3(0, 0, 1));
@@ -1325,18 +1327,30 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const {
uvs.set(i, quad_uv[i]);
}
- p_arr[ARRAY_VERTEX] = faces;
- p_arr[ARRAY_NORMAL] = normals;
- p_arr[ARRAY_TANGENT] = tangents;
- p_arr[ARRAY_TEX_UV] = uvs;
+ p_arr[VS::ARRAY_VERTEX] = faces;
+ p_arr[VS::ARRAY_NORMAL] = normals;
+ p_arr[VS::ARRAY_TANGENT] = tangents;
+ p_arr[VS::ARRAY_TEX_UV] = uvs;
};
void QuadMesh::_bind_methods() {
- // nothing here yet...
+ ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size);
+ ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size);
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
}
QuadMesh::QuadMesh() {
primitive_type = PRIMITIVE_TRIANGLE_FAN;
+ size = Size2(1.0, 1.0);
+}
+
+void QuadMesh::set_size(const Size2 &p_size) {
+ size = p_size;
+ _request_update();
+}
+
+Size2 QuadMesh::get_size() const {
+ return size;
}
/**
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 38a5695883..f0c8935261 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -263,7 +263,7 @@ class QuadMesh : public PrimitiveMesh {
GDCLASS(QuadMesh, PrimitiveMesh)
private:
- // nothing? really? Maybe add size some day atleast... :)
+ Size2 size;
protected:
static void _bind_methods();
@@ -271,6 +271,9 @@ protected:
public:
QuadMesh();
+
+ void set_size(const Size2 &p_size);
+ Size2 get_size() const;
};
/**
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 3f79858056..fbe52909e7 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -40,7 +40,7 @@ protected:
static void _bind_methods();
public:
- typedef int (*AudioMixCallback)(void *p_udata, const int16_t *p_data, int p_frames);
+ typedef int (*AudioMixCallback)(void *p_udata, const float *p_data, int p_frames);
virtual void stop() = 0;
virtual void play() = 0;
@@ -48,7 +48,7 @@ public:
virtual bool is_playing() const = 0;
virtual void set_paused(bool p_paused) = 0;
- virtual bool is_paused(bool p_paused) const = 0;
+ virtual bool is_paused() const = 0;
virtual void set_loop(bool p_enable) = 0;
virtual bool has_loop() const = 0;
diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp
index 55707def7c..458459a843 100644
--- a/servers/arvr/arvr_interface.cpp
+++ b/servers/arvr/arvr_interface.cpp
@@ -43,7 +43,7 @@ void ARVRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tracking_status"), &ARVRInterface::get_tracking_status);
- ClassDB::bind_method(D_METHOD("get_recommended_render_targetsize"), &ARVRInterface::get_recommended_render_targetsize);
+ ClassDB::bind_method(D_METHOD("get_render_targetsize"), &ARVRInterface::get_render_targetsize);
ClassDB::bind_method(D_METHOD("is_stereo"), &ARVRInterface::is_stereo);
ADD_GROUP("Interface", "interface_");
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h
index 880f6e4595..1599c1a64f 100644
--- a/servers/arvr/arvr_interface.h
+++ b/servers/arvr/arvr_interface.h
@@ -103,7 +103,7 @@ public:
/** rendering and internal **/
- virtual Size2 get_recommended_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
+ virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp
index ede080b424..1e73d6753c 100644
--- a/servers/arvr_server.cpp
+++ b/servers/arvr_server.cpp
@@ -49,15 +49,13 @@ void ARVRServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_interface_count"), &ARVRServer::get_interface_count);
ClassDB::bind_method(D_METHOD("get_interface", "idx"), &ARVRServer::get_interface);
+ ClassDB::bind_method(D_METHOD("get_interfaces"), &ARVRServer::get_interfaces);
ClassDB::bind_method(D_METHOD("find_interface", "name"), &ARVRServer::find_interface);
ClassDB::bind_method(D_METHOD("get_tracker_count"), &ARVRServer::get_tracker_count);
ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &ARVRServer::get_tracker);
ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &ARVRServer::set_primary_interface);
- ClassDB::bind_method(D_METHOD("add_interface", "interface"), &ARVRServer::add_interface);
- ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &ARVRServer::remove_interface);
-
BIND_ENUM_CONSTANT(TRACKER_CONTROLLER);
BIND_ENUM_CONSTANT(TRACKER_BASESTATION);
BIND_ENUM_CONSTANT(TRACKER_ANCHOR);
@@ -191,6 +189,21 @@ Ref<ARVRInterface> ARVRServer::find_interface(const String &p_name) const {
return interfaces[idx];
};
+Array ARVRServer::get_interfaces() const {
+ Array ret;
+
+ for (int i = 0; i < interfaces.size(); i++) {
+ Dictionary iface_info;
+
+ iface_info["id"] = i;
+ iface_info["name"] = interfaces[i]->get_name();
+
+ ret.push_back(iface_info);
+ };
+
+ return ret;
+};
+
/*
A little extra info on the tracker ids, these are unique per tracker type so we get soem consistency in recognising our trackers, specifically controllers.
diff --git a/servers/arvr_server.h b/servers/arvr_server.h
index 948895cb27..9b84ee2e99 100644
--- a/servers/arvr_server.h
+++ b/servers/arvr_server.h
@@ -137,6 +137,7 @@ public:
int get_interface_count() const;
Ref<ARVRInterface> get_interface(int p_index) const;
Ref<ARVRInterface> find_interface(const String &p_name) const;
+ Array get_interfaces() const;
/*
note, more then one interface can technically be active, especially on mobile, but only one interface is used for
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
index 113e356612..b0b94a1f49 100644
--- a/servers/audio/audio_rb_resampler.cpp
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -28,6 +28,9 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "audio_rb_resampler.h"
+#include "core/math/math_funcs.h"
+#include "os/os.h"
+#include "servers/audio_server.h"
int AudioRBResampler::get_channel_count() const {
@@ -37,8 +40,11 @@ int AudioRBResampler::get_channel_count() const {
return channels;
}
+// Linear interpolation based sample rate convertion (low quality)
+// Note that AudioStreamPlaybackResampled::mix has better algorithm,
+// but it wasn't obvious to integrate that with VideoPlayer
template <int C>
-uint32_t AudioRBResampler::_resample(int32_t *p_dest, int p_todo, int32_t p_increment) {
+uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_increment) {
uint32_t read = offset & MIX_FRAC_MASK;
@@ -47,186 +53,128 @@ uint32_t AudioRBResampler::_resample(int32_t *p_dest, int p_todo, int32_t p_incr
offset = (offset + p_increment) & (((1 << (rb_bits + MIX_FRAC_BITS)) - 1));
read += p_increment;
uint32_t pos = offset >> MIX_FRAC_BITS;
- uint32_t frac = offset & MIX_FRAC_MASK;
-#ifndef FAST_AUDIO
+ float frac = float(offset & MIX_FRAC_MASK) / float(MIX_FRAC_LEN);
ERR_FAIL_COND_V(pos >= rb_len, 0);
-#endif
uint32_t pos_next = (pos + 1) & rb_mask;
- //printf("rb pos %i\n",pos);
// since this is a template with a known compile time value (C), conditionals go away when compiling.
if (C == 1) {
- int32_t v0 = rb[pos];
- int32_t v0n = rb[pos_next];
-#ifndef FAST_AUDIO
- v0 += (v0n - v0) * (int32_t)frac >> MIX_FRAC_BITS;
-#endif
- v0 <<= 16;
- p_dest[i] = v0;
+ float v0 = rb[pos];
+ float v0n = rb[pos_next];
+ v0 += (v0n - v0) * frac;
+ p_dest[i] = AudioFrame(v0, v0);
}
+
if (C == 2) {
- int32_t v0 = rb[(pos << 1) + 0];
- int32_t v1 = rb[(pos << 1) + 1];
- int32_t v0n = rb[(pos_next << 1) + 0];
- int32_t v1n = rb[(pos_next << 1) + 1];
-
-#ifndef FAST_AUDIO
- v0 += (v0n - v0) * (int32_t)frac >> MIX_FRAC_BITS;
- v1 += (v1n - v1) * (int32_t)frac >> MIX_FRAC_BITS;
-#endif
- v0 <<= 16;
- v1 <<= 16;
- p_dest[(i << 1) + 0] = v0;
- p_dest[(i << 1) + 1] = v1;
+ float v0 = rb[(pos << 1) + 0];
+ float v1 = rb[(pos << 1) + 1];
+ float v0n = rb[(pos_next << 1) + 0];
+ float v1n = rb[(pos_next << 1) + 1];
+
+ v0 += (v0n - v0) * frac;
+ v1 += (v1n - v1) * frac;
+ p_dest[i] = AudioFrame(v0, v1);
}
+ // For now, channels higher than stereo are almost ignored
if (C == 4) {
- int32_t v0 = rb[(pos << 2) + 0];
- int32_t v1 = rb[(pos << 2) + 1];
- int32_t v2 = rb[(pos << 2) + 2];
- int32_t v3 = rb[(pos << 2) + 3];
- int32_t v0n = rb[(pos_next << 2) + 0];
- int32_t v1n = rb[(pos_next << 2) + 1];
- int32_t v2n = rb[(pos_next << 2) + 2];
- int32_t v3n = rb[(pos_next << 2) + 3];
-
-#ifndef FAST_AUDIO
- v0 += (v0n - v0) * (int32_t)frac >> MIX_FRAC_BITS;
- v1 += (v1n - v1) * (int32_t)frac >> MIX_FRAC_BITS;
- v2 += (v2n - v2) * (int32_t)frac >> MIX_FRAC_BITS;
- v3 += (v3n - v3) * (int32_t)frac >> MIX_FRAC_BITS;
-#endif
- v0 <<= 16;
- v1 <<= 16;
- v2 <<= 16;
- v3 <<= 16;
- p_dest[(i << 2) + 0] = v0;
- p_dest[(i << 2) + 1] = v1;
- p_dest[(i << 2) + 2] = v2;
- p_dest[(i << 2) + 3] = v3;
+ float v0 = rb[(pos << 2) + 0];
+ float v1 = rb[(pos << 2) + 1];
+ float v2 = rb[(pos << 2) + 2];
+ float v3 = rb[(pos << 2) + 3];
+ float v0n = rb[(pos_next << 2) + 0];
+ float v1n = rb[(pos_next << 2) + 1];
+ float v2n = rb[(pos_next << 2) + 2];
+ float v3n = rb[(pos_next << 2) + 3];
+
+ v0 += (v0n - v0) * frac;
+ v1 += (v1n - v1) * frac;
+ v2 += (v2n - v2) * frac;
+ v3 += (v3n - v3) * frac;
+ p_dest[i] = AudioFrame(v0, v1);
}
if (C == 6) {
- int32_t v0 = rb[(pos * 6) + 0];
- int32_t v1 = rb[(pos * 6) + 1];
- int32_t v2 = rb[(pos * 6) + 2];
- int32_t v3 = rb[(pos * 6) + 3];
- int32_t v4 = rb[(pos * 6) + 4];
- int32_t v5 = rb[(pos * 6) + 5];
- int32_t v0n = rb[(pos_next * 6) + 0];
- int32_t v1n = rb[(pos_next * 6) + 1];
- int32_t v2n = rb[(pos_next * 6) + 2];
- int32_t v3n = rb[(pos_next * 6) + 3];
- int32_t v4n = rb[(pos_next * 6) + 4];
- int32_t v5n = rb[(pos_next * 6) + 5];
-
-#ifndef FAST_AUDIO
- v0 += (v0n - v0) * (int32_t)frac >> MIX_FRAC_BITS;
- v1 += (v1n - v1) * (int32_t)frac >> MIX_FRAC_BITS;
- v2 += (v2n - v2) * (int32_t)frac >> MIX_FRAC_BITS;
- v3 += (v3n - v3) * (int32_t)frac >> MIX_FRAC_BITS;
- v4 += (v4n - v4) * (int32_t)frac >> MIX_FRAC_BITS;
- v5 += (v5n - v5) * (int32_t)frac >> MIX_FRAC_BITS;
-#endif
- v0 <<= 16;
- v1 <<= 16;
- v2 <<= 16;
- v3 <<= 16;
- v4 <<= 16;
- v5 <<= 16;
- p_dest[(i * 6) + 0] = v0;
- p_dest[(i * 6) + 1] = v1;
- p_dest[(i * 6) + 2] = v2;
- p_dest[(i * 6) + 3] = v3;
- p_dest[(i * 6) + 4] = v4;
- p_dest[(i * 6) + 5] = v5;
+ float v0 = rb[(pos * 6) + 0];
+ float v1 = rb[(pos * 6) + 1];
+ float v2 = rb[(pos * 6) + 2];
+ float v3 = rb[(pos * 6) + 3];
+ float v4 = rb[(pos * 6) + 4];
+ float v5 = rb[(pos * 6) + 5];
+ float v0n = rb[(pos_next * 6) + 0];
+ float v1n = rb[(pos_next * 6) + 1];
+ float v2n = rb[(pos_next * 6) + 2];
+ float v3n = rb[(pos_next * 6) + 3];
+ float v4n = rb[(pos_next * 6) + 4];
+ float v5n = rb[(pos_next * 6) + 5];
+
+ p_dest[i] = AudioFrame(v0, v1);
}
}
- return read >> MIX_FRAC_BITS; //rb_read_pos=offset>>MIX_FRAC_BITS;
+ return read >> MIX_FRAC_BITS; //rb_read_pos = offset >> MIX_FRAC_BITS;
}
-bool AudioRBResampler::mix(int32_t *p_dest, int p_frames) {
+bool AudioRBResampler::mix(AudioFrame *p_dest, int p_frames) {
if (!rb)
return false;
- int write_pos_cache = rb_write_pos;
-
int32_t increment = (src_mix_rate * MIX_FRAC_LEN) / target_mix_rate;
-
- int rb_todo;
-
- if (write_pos_cache == rb_read_pos) {
- return false; //out of buffer
-
- } else if (rb_read_pos < write_pos_cache) {
-
- rb_todo = write_pos_cache - rb_read_pos; //-1?
- } else {
-
- rb_todo = (rb_len - rb_read_pos) + write_pos_cache; //-1?
- }
-
- int todo = MIN(((int64_t(rb_todo) << MIX_FRAC_BITS) / increment) + 1, p_frames);
+ int read_space = get_reader_space();
+ int target_todo = MIN(get_num_of_ready_frames(), p_frames);
{
-
- int read = 0;
+ int src_read = 0;
switch (channels) {
- case 1: read = _resample<1>(p_dest, todo, increment); break;
- case 2: read = _resample<2>(p_dest, todo, increment); break;
- case 4: read = _resample<4>(p_dest, todo, increment); break;
- case 6: read = _resample<6>(p_dest, todo, increment); break;
+ case 1: src_read = _resample<1>(p_dest, target_todo, increment); break;
+ case 2: src_read = _resample<2>(p_dest, target_todo, increment); break;
+ case 4: src_read = _resample<4>(p_dest, target_todo, increment); break;
+ case 6: src_read = _resample<6>(p_dest, target_todo, increment); break;
}
- //end of stream, fadeout
- int remaining = p_frames - todo;
- if (remaining && todo > 0) {
-
- //print_line("fadeout");
- for (uint32_t c = 0; c < channels; c++) {
+ if (src_read > read_space)
+ src_read = read_space;
- for (int i = 0; i < todo; i++) {
+ rb_read_pos = (rb_read_pos + src_read) & rb_mask;
- int32_t samp = p_dest[i * channels + c] >> 8;
- uint32_t mul = (todo - i) * 256 / todo;
- //print_line("mul: "+itos(i)+" "+itos(mul));
- p_dest[i * channels + c] = samp * mul;
- }
+ // Create fadeout effect for the end of stream (note that it can be because of slow writer)
+ if (p_frames - target_todo > 0) {
+ for (int i = 0; i < target_todo; i++) {
+ p_dest[i] = p_dest[i] * float(target_todo - i) / float(target_todo);
}
}
- //zero out what remains there to avoid glitches
- for (uint32_t i = todo * channels; i < int(p_frames) * channels; i++) {
-
- p_dest[i] = 0;
+ // Fill zeros (silence) for the rest of frames
+ for (uint32_t i = target_todo; i < p_frames; i++) {
+ p_dest[i] = AudioFrame(0, 0);
}
-
- if (read > rb_todo)
- read = rb_todo;
-
- rb_read_pos = (rb_read_pos + read) & rb_mask;
}
return true;
}
+int AudioRBResampler::get_num_of_ready_frames() {
+ if (!is_ready())
+ return 0;
+ int32_t increment = (src_mix_rate * MIX_FRAC_LEN) / target_mix_rate;
+ int read_space = get_reader_space();
+ return (int64_t(read_space) << MIX_FRAC_BITS) / increment;
+}
+
Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_mix_rate, int p_buffer_msec, int p_minbuff_needed) {
ERR_FAIL_COND_V(p_channels != 1 && p_channels != 2 && p_channels != 4 && p_channels != 6, ERR_INVALID_PARAMETER);
- //float buffering_sec = int(GLOBAL_DEF("audio/stream_buffering_ms",500))/1000.0;
int desired_rb_bits = nearest_shift(MAX((p_buffer_msec / 1000.0) * p_src_mix_rate, p_minbuff_needed));
bool recreate = !rb;
if (rb && (uint32_t(desired_rb_bits) != rb_bits || channels != uint32_t(p_channels))) {
- //recreate
memdelete_arr(rb);
memdelete_arr(read_buf);
@@ -239,8 +187,8 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m
rb_bits = desired_rb_bits;
rb_len = (1 << rb_bits);
rb_mask = rb_len - 1;
- rb = memnew_arr(int16_t, rb_len * p_channels);
- read_buf = memnew_arr(int16_t, rb_len * p_channels);
+ rb = memnew_arr(float, rb_len *p_channels);
+ read_buf = memnew_arr(float, rb_len *p_channels);
}
src_mix_rate = p_src_mix_rate;
diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h
index bc1f924ab5..08c7a5a668 100644
--- a/servers/audio/audio_rb_resampler.h
+++ b/servers/audio/audio_rb_resampler.h
@@ -31,6 +31,7 @@
#define AUDIO_RB_RESAMPLER_H
#include "os/memory.h"
+#include "servers/audio_server.h"
#include "typedefs.h"
struct AudioRBResampler {
@@ -53,11 +54,11 @@ struct AudioRBResampler {
MIX_FRAC_MASK = MIX_FRAC_LEN - 1,
};
- int16_t *read_buf;
- int16_t *rb;
+ float *read_buf;
+ float *rb;
template <int C>
- uint32_t _resample(int32_t *p_dest, int p_todo, int32_t p_increment);
+ uint32_t _resample(AudioFrame *p_dest, int p_todo, int32_t p_increment);
public:
_FORCE_INLINE_ void flush() {
@@ -71,33 +72,48 @@ public:
}
_FORCE_INLINE_ int get_total() const {
-
return rb_len - 1;
}
- _FORCE_INLINE_ int get_todo() const { //return amount of frames to mix
-
- int todo;
- int read_pos_cache = rb_read_pos;
+ _FORCE_INLINE_ int get_writer_space() const {
+ int space, r, w;
- if (read_pos_cache == rb_write_pos) {
- todo = rb_len - 1;
- } else if (read_pos_cache > rb_write_pos) {
+ r = rb_read_pos;
+ w = rb_write_pos;
- todo = read_pos_cache - rb_write_pos - 1;
+ if (r == w) {
+ space = rb_len - 1;
+ } else if (w < r) {
+ space = r - w - 1;
} else {
+ space = (rb_len - r) + w - 1;
+ }
+
+ return space;
+ }
+
+ _FORCE_INLINE_ int get_reader_space() const {
+ int space, r, w;
- todo = (rb_len - rb_write_pos) + read_pos_cache - 1;
+ r = rb_read_pos;
+ w = rb_write_pos;
+
+ if (r == w) {
+ space = 0;
+ } else if (w < r) {
+ space = rb_len - r + w;
+ } else {
+ space = w - r;
}
- return todo;
+ return space;
}
_FORCE_INLINE_ bool has_data() const {
return rb && rb_read_pos != rb_write_pos;
}
- _FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; }
+ _FORCE_INLINE_ float *get_write_buffer() { return read_buf; }
_FORCE_INLINE_ void write(uint32_t p_frames) {
ERR_FAIL_COND(p_frames >= rb_len);
@@ -151,7 +167,8 @@ public:
Error setup(int p_channels, int p_src_mix_rate, int p_target_mix_rate, int p_buffer_msec, int p_minbuff_needed = -1);
void clear();
- bool mix(int32_t *p_dest, int p_frames);
+ bool mix(AudioFrame *p_dest, int p_frames);
+ int get_num_of_ready_frames();
AudioRBResampler();
~AudioRBResampler();
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 697abead68..6a10d7539d 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -876,6 +876,8 @@ void AudioServer::init() {
#ifdef TOOLS_ENABLED
set_edited(false); //avoid editors from thinking this was edited
#endif
+
+ GLOBAL_DEF("audio/video_delay_compensation_ms", 0);
}
void AudioServer::load_default_bus_layout() {
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
index 76fb5bc46b..88cd728a94 100644
--- a/servers/physics_server.cpp
+++ b/servers/physics_server.cpp
@@ -678,6 +678,7 @@ void PhysicsServer::_bind_methods() {
BIND_ENUM_CONSTANT(BODY_MODE_STATIC);
BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC);
BIND_ENUM_CONSTANT(BODY_MODE_RIGID);
+ BIND_ENUM_CONSTANT(BODY_MODE_SOFT);
BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER);
BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE);
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
index 92c431e393..fbf593f5b9 100644
--- a/servers/visual/visual_server_viewport.cpp
+++ b/servers/visual/visual_server_viewport.cpp
@@ -268,7 +268,7 @@ void VisualServerViewport::draw_viewports() {
if (vp->use_arvr && arvr_interface.is_valid()) {
// override our size, make sure it matches our required size
- Size2 size = arvr_interface->get_recommended_render_targetsize();
+ Size2 size = arvr_interface->get_render_targetsize();
VSG::storage->render_target_set_size(vp->render_target, size.x, size.y);
// render mono or left eye first
diff --git a/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp b/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
index 06447aca57..c9e71eb733 100644
--- a/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
+++ b/thirdparty/libsimplewebm/OpusVorbisDecoder.cpp
@@ -122,6 +122,43 @@ bool OpusVorbisDecoder::getPCMS16(WebMFrame &frame, short *buffer, int &numOutSa
return false;
}
+bool OpusVorbisDecoder::getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples) {
+ if (m_vorbis) {
+ m_vorbis->op.packet = frame.buffer;
+ m_vorbis->op.bytes = frame.bufferSize;
+
+ if (vorbis_synthesis(&m_vorbis->block, &m_vorbis->op))
+ return false;
+ if (vorbis_synthesis_blockin(&m_vorbis->dspState, &m_vorbis->block))
+ return false;
+
+ const int maxSamples = getBufferSamples();
+ int samplesCount, count = 0;
+ float **pcm;
+ while ((samplesCount = vorbis_synthesis_pcmout(&m_vorbis->dspState, &pcm))) {
+ const int toConvert = samplesCount <= maxSamples ? samplesCount : maxSamples;
+ for (int c = 0; c < m_channels; ++c) {
+ float *samples = pcm[c];
+ for (int i = 0, j = c; i < toConvert; ++i, j += m_channels) {
+ buffer[count + j] = samples[i];
+ }
+ }
+ vorbis_synthesis_read(&m_vorbis->dspState, toConvert);
+ count += toConvert;
+ }
+
+ numOutSamples = count;
+ return true;
+ } else if (m_opus) {
+ const int samples = opus_decode_float(m_opus, frame.buffer, frame.bufferSize, buffer, m_numSamples, 0);
+ if (samples >= 0) {
+ numOutSamples = samples;
+ return true;
+ }
+ }
+ return false;
+}
+
bool OpusVorbisDecoder::openVorbis(const WebMDemuxer &demuxer)
{
size_t extradataSize = 0;
diff --git a/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp b/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
index bcdca731ee..b7619d6a25 100644
--- a/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
+++ b/thirdparty/libsimplewebm/OpusVorbisDecoder.hpp
@@ -44,7 +44,7 @@ public:
{
return m_numSamples;
}
-
+ bool getPCMF(WebMFrame &frame, float *buffer, int &numOutSamples);
bool getPCMS16(WebMFrame &frame, short *buffer, int &numOutSamples);
private: