summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/http_client.cpp135
-rw-r--r--core/io/http_client.h12
-rw-r--r--doc/classes/@GDScript.xml2
-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.xml39
-rw-r--r--doc/classes/TileMap.xml16
-rw-r--r--doc/classes/ViewportContainer.xml16
-rw-r--r--doc/classes/VisualScriptBuiltinFunc.xml44
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp4
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp6
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp10
-rw-r--r--editor/project_export.cpp2
-rw-r--r--editor/project_settings_editor.cpp4
-rw-r--r--editor/scene_tree_dock.cpp8
-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/mobile_vr/mobile_interface.cpp2
-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/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/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/windows/context_gl_win.cpp2
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/video_player.cpp144
-rw-r--r--scene/gui/video_player.h22
-rwxr-xr-xscene/main/node.cpp13
-rw-r--r--scene/main/node.h1
-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
86 files changed, 1952 insertions, 591 deletions
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/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 3c794a4c4c..47003d08e0 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -1119,7 +1119,7 @@
<constant name="PI" value="3.141593" enum="">
Constant that represents how many times the diameter of a circle fits around its perimeter.
</constant>
- <constant name="TAU" value="6.2831853" enum="">
+ <constant name="TAU" value="6.283185" enum="">
The circle constant, the circumference of the unit circle.
</constant>
<constant name="INF" value="inf" enum="">
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 3cb33c78c0..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">
@@ -260,12 +259,12 @@
</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>
+ <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>
@@ -355,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.
@@ -465,32 +464,32 @@
</method>
</methods>
<members>
- <member name="text" type="String" setter="set_text" getter="get_text">
- String value of the [TextEdit].
- </member>
- <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="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled">
</member>
<member name="caret_blink_speed" type="float" setter="cursor_set_blink_speed" getter="cursor_get_blink_speed">
</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/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/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/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index cc144344a6..75c6961521 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -1300,7 +1300,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 +1309,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()) {
@@ -1426,7 +1426,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 +1536,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()) {
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 926f26af14..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;
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 6b008838e5..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()) {
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/mobile_vr/mobile_interface.cpp b/modules/mobile_vr/mobile_interface.cpp
index dccdcd3070..3a0b83d534 100644
--- a/modules/mobile_vr/mobile_interface.cpp
+++ b/modules/mobile_vr/mobile_interface.cpp
@@ -323,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/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/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/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/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/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..1889c09d9e 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())
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/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: