Merge pull request #37289 from akien-mga/3.2-cherrypicks
Cherry-picks for the 3.2 branch (future 3.2.2) - 1st batch
This commit is contained in:
commit
909e303def
|
@ -163,7 +163,7 @@ Error PCKPacker::flush(bool p_verbose) {
|
|||
src->close();
|
||||
memdelete(src);
|
||||
count += 1;
|
||||
if (p_verbose) {
|
||||
if (p_verbose && files.size() > 0) {
|
||||
if (count % 100 == 0) {
|
||||
printf("%i/%i (%.2f)\r", count, files.size(), float(count) / files.size() * 100);
|
||||
fflush(stdout);
|
||||
|
|
|
@ -337,14 +337,14 @@ bool MessageQueue::is_flushing() const {
|
|||
|
||||
MessageQueue::MessageQueue() {
|
||||
|
||||
ERR_FAIL_COND_MSG(singleton != NULL, "MessageQueue singleton already exist.");
|
||||
ERR_FAIL_COND_MSG(singleton != NULL, "A MessageQueue singleton already exists.");
|
||||
singleton = this;
|
||||
flushing = false;
|
||||
|
||||
buffer_end = 0;
|
||||
buffer_max_used = 0;
|
||||
buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "0,2048,1,or_greater"));
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater"));
|
||||
buffer_size *= 1024;
|
||||
buffer = memnew_arr(uint8_t, buffer_size);
|
||||
}
|
||||
|
|
|
@ -1353,6 +1353,25 @@ Array Object::_get_incoming_connections() const {
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool Object::has_signal(const StringName &p_name) const {
|
||||
if (!script.is_null()) {
|
||||
Ref<Script> scr = script;
|
||||
if (scr.is_valid() && scr->has_script_signal(p_name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (ClassDB::has_signal(get_class_name(), p_name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_has_user_signal(p_name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Object::get_signal_list(List<MethodInfo> *p_signals) const {
|
||||
|
||||
if (!script.is_null()) {
|
||||
|
@ -1707,6 +1726,7 @@ void Object::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
|
||||
ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
|
||||
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);
|
||||
ClassDB::bind_method(D_METHOD("get_incoming_connections"), &Object::_get_incoming_connections);
|
||||
|
|
|
@ -704,6 +704,7 @@ public:
|
|||
void add_user_signal(const MethodInfo &p_signal);
|
||||
Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST);
|
||||
Error emit_signal(const StringName &p_name, const Variant **p_args, int p_argcount);
|
||||
bool has_signal(const StringName &p_name) const;
|
||||
void get_signal_list(List<MethodInfo> *p_signals) const;
|
||||
void get_signal_connection_list(const StringName &p_signal, List<Connection> *p_connections) const;
|
||||
void get_all_signal_connections(List<Connection> *p_connections) const;
|
||||
|
|
|
@ -518,6 +518,10 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream,
|
|||
value = false;
|
||||
else if (id == "null" || id == "nil")
|
||||
value = Variant();
|
||||
else if (id == "inf")
|
||||
value = Math_INF;
|
||||
else if (id == "nan")
|
||||
value = Math_NAN;
|
||||
else if (id == "Vector2") {
|
||||
|
||||
Vector<float> args;
|
||||
|
@ -1592,8 +1596,10 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str
|
|||
case Variant::REAL: {
|
||||
|
||||
String s = rtosfix(p_variant.operator real_t());
|
||||
if (s.find(".") == -1 && s.find("e") == -1)
|
||||
s += ".0";
|
||||
if (s != "inf" && s != "nan") {
|
||||
if (s.find(".") == -1 && s.find("e") == -1)
|
||||
s += ".0";
|
||||
}
|
||||
p_store_string_func(p_store_string_ud, s);
|
||||
} break;
|
||||
case Variant::STRING: {
|
||||
|
|
|
@ -183,6 +183,17 @@
|
|||
Renames the given node.
|
||||
</description>
|
||||
</method>
|
||||
<method name="replace_node">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="name" type="String">
|
||||
</argument>
|
||||
<argument index="1" name="node" type="AnimationNode">
|
||||
</argument>
|
||||
<description>
|
||||
Replaces the node and keeps its transitions unchanged.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_end_node">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
Returns the editor [Viewport].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_file_system_dock">
|
||||
<return type="FileSystemDock">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_inspector" qualifiers="const">
|
||||
<return type="EditorInspector">
|
||||
</return>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="ExternalTexture" inherits="Texture" category="Core" version="3.2">
|
||||
<class name="ExternalTexture" inherits="Texture" version="3.2">
|
||||
<brief_description>
|
||||
Adds support for external textures as defined by https://www.khronos.org/registry/OpenGL/extensions/OES/OES_EGL_image_external.txt
|
||||
</brief_description>
|
||||
|
@ -8,14 +8,16 @@
|
|||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_external_texture_id" qualifiers="const">
|
||||
<return type="int"/>
|
||||
<method name="get_external_texture_id">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the external texture name.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="flags" type="int" setter="set_flags" getter="get_flags" override="true" default="0" />
|
||||
<member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 1, 1 )">
|
||||
External texture size.
|
||||
</member>
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="FileSystemDock" inherits="VBoxContainer" version="3.2">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="can_drop_data_fw" qualifiers="const">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<argument index="0" name="arg0" type="Vector2">
|
||||
</argument>
|
||||
<argument index="1" name="arg1" type="Variant">
|
||||
</argument>
|
||||
<argument index="2" name="arg2" type="Control">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="drop_data_fw">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="arg0" type="Vector2">
|
||||
</argument>
|
||||
<argument index="1" name="arg1" type="Variant">
|
||||
</argument>
|
||||
<argument index="2" name="arg2" type="Control">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_drag_data_fw">
|
||||
<return type="Variant">
|
||||
</return>
|
||||
<argument index="0" name="arg0" type="Vector2">
|
||||
</argument>
|
||||
<argument index="1" name="arg1" type="Control">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="navigate_to_path">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="arg0" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<signals>
|
||||
<signal name="display_mode_changed">
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="file_removed">
|
||||
<argument index="0" name="file" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="files_moved">
|
||||
<argument index="0" name="old_file" type="String">
|
||||
</argument>
|
||||
<argument index="1" name="new_file" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="folder_moved">
|
||||
<argument index="0" name="old_folder" type="String">
|
||||
</argument>
|
||||
<argument index="1" name="new_file" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="folder_removed">
|
||||
<argument index="0" name="folder" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="inherit">
|
||||
<argument index="0" name="file" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="instance">
|
||||
<argument index="0" name="files" type="PoolStringArray">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
|
@ -349,7 +349,8 @@
|
|||
<argument index="0" name="enable" type="bool">
|
||||
</argument>
|
||||
<description>
|
||||
Whether to accumulate similar input events sent by the operating system. Enabled by default.
|
||||
Enables or disables the accumulation of similar input events sent by the operating system. When input accumulation is enabled, all input events generated during a frame will be merged and emitted when the frame is done rendering. Therefore, this limits the number of input method calls per second to the rendering FPS.
|
||||
Input accumulation is enabled by default. It can be disabled to get slightly more precise/reactive input at the cost of increased CPU usage. In applications where drawing freehand lines is required, input accumulation should generally be disabled while the user is drawing the line to get results that closely follow the actual input.
|
||||
</description>
|
||||
</method>
|
||||
<method name="start_joy_vibration">
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code].
|
||||
</member>
|
||||
<member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2( 0, 0 )">
|
||||
The mouse position relative to the previous position (position at the last frame).
|
||||
The mouse position relative to the previous position (position at the last frame).
|
||||
[b]Note:[/b] Since [InputEventMouseMotion] is only emitted when the mouse moves, the last event won't have a relative position of [code]Vector2(0, 0)[/code] when the user stops moving the mouse.
|
||||
</member>
|
||||
<member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2( 0, 0 )">
|
||||
The mouse speed in pixels per second.
|
||||
|
|
|
@ -313,13 +313,22 @@
|
|||
Returns [code]true[/code] if the object contains the given [code]method[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_signal" qualifiers="const">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<argument index="0" name="signal" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
Returns [code]true[/code] if the given [code]signal[/code] exists.
|
||||
</description>
|
||||
</method>
|
||||
<method name="has_user_signal" qualifiers="const">
|
||||
<return type="bool">
|
||||
</return>
|
||||
<argument index="0" name="signal" type="String">
|
||||
</argument>
|
||||
<description>
|
||||
Returns [code]true[/code] if the given user-defined [code]signal[/code] exists.
|
||||
Returns [code]true[/code] if the given user-defined [code]signal[/code] exists. Only signals added using [method add_user_signal] are taken into account.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_blocking_signals" qualifiers="const">
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
<member name="code" type="String" setter="set_code" getter="get_code" default="""">
|
||||
Returns the shader's code as the user has written it, not the full generated code used internally.
|
||||
</member>
|
||||
<member name="custom_defines" type="String" setter="set_custom_defines" getter="get_custom_defines" default="""">
|
||||
<member name="custom_defines" type="String" setter="set_custom_defines" getter="get_custom_defines" default=""#define MAX_LIGHT_DATA_STRUCTS 409#define MAX_FORWARD_LIGHTS 8#define MAX_REFLECTION_DATA_STRUCTS 455#define MAX_SKELETON_BONES 1365"">
|
||||
Returns the shader's custom defines. Custom defines can be used in Godot to add GLSL preprocessor directives (e.g: extensions) required for the shader logic.
|
||||
[b]Note:[/b] Custom defines are not validated by the Godot shader parser, so care should be taken when using them.
|
||||
</member>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
A node that displays a 2D texture in a 3D environment. The texture displayed can be a region from a larger atlas texture, or a frame from a sprite sheet animation.
|
||||
[b]Note:[/b] There are [url=https://github.com/godotengine/godot/issues/20855]known performance issues[/url] when using [Sprite3D]. Consider using a [MeshInstance] with a [QuadMesh] as the mesh instead. You can still have billboarding by enabling billboard properties in the QuadMesh's [SpatialMaterial].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
The VisibilityEnabler will disable [RigidBody] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibilityEnabler itself.
|
||||
Note that VisibilityEnabler will not affect nodes added after scene initialization.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
</brief_description>
|
||||
<description>
|
||||
The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and other nodes when they are not visible. It will only affect nodes with the same root node as the VisibilityEnabler2D, and the root node itself.
|
||||
Note that VisibilityEnabler2D will not affect nodes added after scene initialization.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
|
|
|
@ -4279,13 +4279,13 @@
|
|||
<constant name="TEXTURE_TYPE_2D" value="0" enum="TextureType">
|
||||
Normal texture with 2 dimensions, width and height.
|
||||
</constant>
|
||||
<constant name="TEXTURE_TYPE_CUBEMAP" value="1" enum="TextureType">
|
||||
<constant name="TEXTURE_TYPE_CUBEMAP" value="2" enum="TextureType">
|
||||
Texture made up of six faces, can be looked up with a [code]vec3[/code] in shader.
|
||||
</constant>
|
||||
<constant name="TEXTURE_TYPE_2D_ARRAY" value="2" enum="TextureType">
|
||||
<constant name="TEXTURE_TYPE_2D_ARRAY" value="3" enum="TextureType">
|
||||
An array of 2-dimensional textures.
|
||||
</constant>
|
||||
<constant name="TEXTURE_TYPE_3D" value="3" enum="TextureType">
|
||||
<constant name="TEXTURE_TYPE_3D" value="4" enum="TextureType">
|
||||
A 3-dimensional texture with width, height, and depth.
|
||||
</constant>
|
||||
<constant name="TEXTURE_FLAG_MIPMAPS" value="1" enum="TextureFlags">
|
||||
|
|
|
@ -28,12 +28,14 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "servers/audio_server.h"
|
||||
|
||||
#ifdef ALSA_ENABLED
|
||||
|
||||
#ifndef AUDIO_DRIVER_ALSA_H
|
||||
#define AUDIO_DRIVER_ALSA_H
|
||||
|
||||
#include "core/os/mutex.h"
|
||||
#include "core/os/thread.h"
|
||||
#include "servers/audio_server.h"
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
|
@ -87,4 +89,6 @@ public:
|
|||
~AudioDriverALSA();
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // AUDIO_DRIVER_ALSA_H
|
||||
|
||||
#endif // ALSA_ENABLED
|
||||
|
|
|
@ -1,303 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* doc_dump.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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 "doc_dump.h"
|
||||
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/version.h"
|
||||
#include "scene/main/node.h"
|
||||
|
||||
static void _write_string(FileAccess *f, int p_tablevel, const String &p_string) {
|
||||
|
||||
String tab;
|
||||
for (int i = 0; i < p_tablevel; i++)
|
||||
tab += "\t";
|
||||
f->store_string(tab + p_string + "\n");
|
||||
}
|
||||
|
||||
struct _ConstantSort {
|
||||
|
||||
String name;
|
||||
int value;
|
||||
bool operator<(const _ConstantSort &p_c) const {
|
||||
|
||||
String left_a = name.find("_") == -1 ? name : name.substr(0, name.find("_"));
|
||||
String left_b = p_c.name.find("_") == -1 ? p_c.name : p_c.name.substr(0, p_c.name.find("_"));
|
||||
if (left_a == left_b)
|
||||
return value < p_c.value;
|
||||
else
|
||||
return left_a < left_b;
|
||||
}
|
||||
};
|
||||
|
||||
static String _escape_string(const String &p_str) {
|
||||
|
||||
String ret = p_str;
|
||||
ret = ret.replace("&", "&");
|
||||
ret = ret.replace("<", ">");
|
||||
ret = ret.replace(">", "<");
|
||||
ret = ret.replace("'", "'");
|
||||
ret = ret.replace("\"", """);
|
||||
for (char i = 1; i < 32; i++) {
|
||||
|
||||
char chr[2] = { i, 0 };
|
||||
ret = ret.replace(chr, "&#" + String::num(i) + ";");
|
||||
}
|
||||
ret = ret.utf8();
|
||||
return ret;
|
||||
}
|
||||
void DocDump::dump(const String &p_file) {
|
||||
|
||||
List<StringName> class_list;
|
||||
ClassDB::get_class_list(&class_list);
|
||||
|
||||
class_list.sort_custom<StringName::AlphCompare>();
|
||||
|
||||
FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);
|
||||
|
||||
_write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
|
||||
_write_string(f, 0, String("<doc version=\"") + VERSION_BRANCH + "\" name=\"Engine Types\">");
|
||||
|
||||
while (class_list.size()) {
|
||||
|
||||
String name = class_list.front()->get();
|
||||
|
||||
String header = "<class name=\"" + name + "\"";
|
||||
String inherits = ClassDB::get_parent_class(name);
|
||||
if (inherits != "")
|
||||
header += " inherits=\"" + inherits + "\"";
|
||||
_write_string(f, 0, header);
|
||||
|
||||
_write_string(f, 1, "<brief_description>");
|
||||
_write_string(f, 1, "</brief_description>");
|
||||
|
||||
_write_string(f, 1, "<description>");
|
||||
_write_string(f, 1, "</description>");
|
||||
|
||||
_write_string(f, 1, "<methods>");
|
||||
|
||||
List<MethodInfo> method_list;
|
||||
ClassDB::get_method_list(name, &method_list, true);
|
||||
method_list.sort();
|
||||
|
||||
for (List<MethodInfo>::Element *E = method_list.front(); E; E = E->next()) {
|
||||
if (E->get().name == "" || E->get().name[0] == '_')
|
||||
continue; //hidden
|
||||
|
||||
MethodBind *m = ClassDB::get_method(name, E->get().name);
|
||||
|
||||
String qualifiers;
|
||||
if (E->get().flags & METHOD_FLAG_CONST)
|
||||
qualifiers += "qualifiers=\"const\"";
|
||||
|
||||
_write_string(f, 2, "<method name=\"" + _escape_string(E->get().name) + "\" " + qualifiers + " >");
|
||||
|
||||
for (int i = -1; i < E->get().arguments.size(); i++) {
|
||||
|
||||
PropertyInfo arginfo;
|
||||
|
||||
if (i == -1) {
|
||||
|
||||
arginfo = E->get().return_val;
|
||||
String type_name = (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE) ? arginfo.hint_string : Variant::get_type_name(arginfo.type);
|
||||
|
||||
if (arginfo.type == Variant::NIL)
|
||||
continue;
|
||||
_write_string(f, 3, "<return type=\"" + type_name + "\">");
|
||||
} else {
|
||||
|
||||
arginfo = E->get().arguments[i];
|
||||
|
||||
String type_name;
|
||||
|
||||
if (arginfo.hint == PROPERTY_HINT_RESOURCE_TYPE)
|
||||
type_name = arginfo.hint_string;
|
||||
else if (arginfo.type == Variant::NIL)
|
||||
type_name = "Variant";
|
||||
else
|
||||
type_name = Variant::get_type_name(arginfo.type);
|
||||
|
||||
if (m && m->has_default_argument(i)) {
|
||||
Variant default_arg = m->get_default_argument(i);
|
||||
String default_arg_text = String(_escape_string(m->get_default_argument(i)));
|
||||
|
||||
switch (default_arg.get_type()) {
|
||||
|
||||
case Variant::NIL:
|
||||
default_arg_text = "NULL";
|
||||
break;
|
||||
// atomic types
|
||||
case Variant::BOOL:
|
||||
if (bool(default_arg))
|
||||
default_arg_text = "true";
|
||||
else
|
||||
default_arg_text = "false";
|
||||
break;
|
||||
case Variant::INT:
|
||||
case Variant::REAL:
|
||||
//keep it
|
||||
break;
|
||||
case Variant::STRING:
|
||||
case Variant::NODE_PATH:
|
||||
default_arg_text = "\"" + default_arg_text + "\"";
|
||||
break;
|
||||
case Variant::TRANSFORM:
|
||||
if (default_arg.operator Transform() == Transform()) {
|
||||
default_arg_text = "";
|
||||
}
|
||||
|
||||
default_arg_text = Variant::get_type_name(default_arg.get_type()) + "(" + default_arg_text + ")";
|
||||
break;
|
||||
|
||||
case Variant::VECTOR2:
|
||||
case Variant::RECT2:
|
||||
case Variant::VECTOR3:
|
||||
case Variant::PLANE:
|
||||
case Variant::QUAT:
|
||||
case Variant::AABB:
|
||||
case Variant::BASIS:
|
||||
case Variant::COLOR:
|
||||
case Variant::POOL_BYTE_ARRAY:
|
||||
case Variant::POOL_INT_ARRAY:
|
||||
case Variant::POOL_REAL_ARRAY:
|
||||
case Variant::POOL_STRING_ARRAY:
|
||||
case Variant::POOL_VECTOR3_ARRAY:
|
||||
case Variant::POOL_COLOR_ARRAY:
|
||||
default_arg_text = Variant::get_type_name(default_arg.get_type()) + "(" + default_arg_text + ")";
|
||||
break;
|
||||
case Variant::OBJECT:
|
||||
case Variant::DICTIONARY: // 20
|
||||
case Variant::ARRAY:
|
||||
case Variant::_RID:
|
||||
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
||||
_write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + _escape_string(arginfo.name) + "\" type=\"" + type_name + "\" default=\"" + _escape_string(default_arg_text) + "\">");
|
||||
} else
|
||||
_write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + arginfo.name + "\" type=\"" + type_name + "\">");
|
||||
}
|
||||
|
||||
String hint;
|
||||
switch (arginfo.hint) {
|
||||
case PROPERTY_HINT_DIR: hint = "A directory."; break;
|
||||
case PROPERTY_HINT_RANGE: hint = "Range - min: " + arginfo.hint_string.get_slice(",", 0) + " max: " + arginfo.hint_string.get_slice(",", 1) + " step: " + arginfo.hint_string.get_slice(",", 2); break;
|
||||
case PROPERTY_HINT_ENUM:
|
||||
hint = "Values: ";
|
||||
for (int j = 0; j < arginfo.hint_string.get_slice_count(","); j++) {
|
||||
if (j > 0) hint += ", ";
|
||||
hint += arginfo.hint_string.get_slice(",", j) + "=" + itos(j);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_HINT_LENGTH: hint = "Length: " + arginfo.hint_string; break;
|
||||
case PROPERTY_HINT_FLAGS:
|
||||
hint = "Values: ";
|
||||
for (int j = 0; j < arginfo.hint_string.get_slice_count(","); j++) {
|
||||
if (j > 0) hint += ", ";
|
||||
hint += arginfo.hint_string.get_slice(",", j) + "=" + itos((uint64_t)1 << j);
|
||||
}
|
||||
break;
|
||||
case PROPERTY_HINT_FILE: hint = "A file:"; break;
|
||||
default: {
|
||||
}
|
||||
//case PROPERTY_HINT_RESOURCE_TYPE: hint="Type: "+arginfo.hint_string; break;
|
||||
};
|
||||
if (hint != "")
|
||||
_write_string(f, 4, hint);
|
||||
|
||||
_write_string(f, 3, (i == -1) ? "</return>" : "</argument>");
|
||||
}
|
||||
|
||||
_write_string(f, 3, "<description>");
|
||||
_write_string(f, 3, "</description>");
|
||||
|
||||
_write_string(f, 2, "</method>");
|
||||
}
|
||||
|
||||
_write_string(f, 1, "</methods>");
|
||||
|
||||
List<MethodInfo> signal_list;
|
||||
ClassDB::get_signal_list(name, &signal_list, true);
|
||||
|
||||
if (signal_list.size()) {
|
||||
|
||||
_write_string(f, 1, "<signals>");
|
||||
for (List<MethodInfo>::Element *EV = signal_list.front(); EV; EV = EV->next()) {
|
||||
|
||||
_write_string(f, 2, "<signal name=\"" + EV->get().name + "\">");
|
||||
for (int i = 0; i < EV->get().arguments.size(); i++) {
|
||||
PropertyInfo arginfo = EV->get().arguments[i];
|
||||
_write_string(f, 3, "<argument index=\"" + itos(i) + "\" name=\"" + arginfo.name + "\" type=\"" + Variant::get_type_name(arginfo.type) + "\">");
|
||||
_write_string(f, 3, "</argument>");
|
||||
}
|
||||
_write_string(f, 3, "<description>");
|
||||
_write_string(f, 3, "</description>");
|
||||
|
||||
_write_string(f, 2, "</signal>");
|
||||
}
|
||||
|
||||
_write_string(f, 1, "</signals>");
|
||||
}
|
||||
|
||||
_write_string(f, 1, "<constants>");
|
||||
|
||||
List<String> constant_list;
|
||||
ClassDB::get_integer_constant_list(name, &constant_list, true);
|
||||
|
||||
/* constants are sorted in a special way */
|
||||
|
||||
List<_ConstantSort> constant_sort;
|
||||
|
||||
for (List<String>::Element *E = constant_list.front(); E; E = E->next()) {
|
||||
_ConstantSort cs;
|
||||
cs.name = E->get();
|
||||
cs.value = ClassDB::get_integer_constant(name, E->get());
|
||||
constant_sort.push_back(cs);
|
||||
}
|
||||
|
||||
constant_sort.sort();
|
||||
|
||||
for (List<_ConstantSort>::Element *E = constant_sort.front(); E; E = E->next()) {
|
||||
|
||||
_write_string(f, 2, "<constant name=\"" + E->get().name + "\" value=\"" + itos(E->get().value) + "\">");
|
||||
_write_string(f, 2, "</constant>");
|
||||
}
|
||||
|
||||
_write_string(f, 1, "</constants>");
|
||||
_write_string(f, 0, "</class>");
|
||||
|
||||
class_list.erase(name);
|
||||
}
|
||||
|
||||
_write_string(f, 0, "</doc>");
|
||||
f->close();
|
||||
memdelete(f);
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* doc_dump.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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 DOC_DUMP_H
|
||||
#define DOC_DUMP_H
|
||||
|
||||
#include "core/class_db.h"
|
||||
|
||||
class DocDump {
|
||||
public:
|
||||
static void dump(const String &p_file);
|
||||
};
|
||||
|
||||
#endif // DOC_DUMP_H
|
|
@ -1707,6 +1707,18 @@ void EditorInspector::update_tree() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<String> slices = propname.operator String().split("/");
|
||||
if (slices.size() == 2 && slices[0].begins_with("custom_")) {
|
||||
// Likely a theme property.
|
||||
for (int i = 0; i < F->get().theme_properties.size(); i++) {
|
||||
if (F->get().theme_properties[i].name == slices[1]) {
|
||||
descr = F->get().theme_properties[i].description.strip_edges();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!F->get().inherits.empty()) {
|
||||
F = dd->class_list.find(F->get().inherits);
|
||||
} else {
|
||||
|
|
|
@ -1400,7 +1400,6 @@ void EditorNode::_mark_unsaved_scenes() {
|
|||
String path = node->get_filename();
|
||||
if (!(path == String() || FileAccess::exists(path))) {
|
||||
|
||||
node->set_filename("");
|
||||
if (i == editor_data.get_edited_scene())
|
||||
set_current_version(-1);
|
||||
else
|
||||
|
@ -6834,6 +6833,9 @@ EditorNode::EditorNode() {
|
|||
screenshot_timer->connect("timeout", this, "_request_screenshot");
|
||||
add_child(screenshot_timer);
|
||||
screenshot_timer->set_owner(get_owner());
|
||||
|
||||
String exec = OS::get_singleton()->get_executable_path();
|
||||
EditorSettings::get_singleton()->set_project_metadata("editor_metadata", "executable_path", exec); // Save editor executable path for third-party tools
|
||||
}
|
||||
|
||||
EditorNode::~EditorNode() {
|
||||
|
|
|
@ -137,19 +137,12 @@ void EditorPluginSettings::update_plugins() {
|
|||
item->set_metadata(1, script);
|
||||
item->set_text(2, author);
|
||||
item->set_metadata(2, description);
|
||||
item->set_cell_mode(3, TreeItem::CELL_MODE_RANGE);
|
||||
item->set_range_config(3, 0, 1, 1);
|
||||
item->set_text(3, "Inactive,Active");
|
||||
item->set_cell_mode(3, TreeItem::CELL_MODE_CHECK);
|
||||
item->set_text(3, TTR("Enable"));
|
||||
bool is_active = EditorNode::get_singleton()->is_addon_plugin_enabled(d2);
|
||||
item->set_checked(3, is_active);
|
||||
item->set_editable(3, true);
|
||||
item->add_button(4, get_icon("Edit", "EditorIcons"), BUTTON_PLUGIN_EDIT, false, TTR("Edit Plugin"));
|
||||
|
||||
if (EditorNode::get_singleton()->is_addon_plugin_enabled(d2)) {
|
||||
item->set_custom_color(3, get_color("success_color", "Editor"));
|
||||
item->set_range(3, 1);
|
||||
} else {
|
||||
item->set_custom_color(3, get_color("disabled_font_color", "Editor"));
|
||||
item->set_range(3, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +157,7 @@ void EditorPluginSettings::_plugin_activity_changed() {
|
|||
|
||||
TreeItem *ti = plugin_list->get_edited();
|
||||
ERR_FAIL_COND(!ti);
|
||||
bool active = ti->get_range(3);
|
||||
bool active = ti->is_checked(3);
|
||||
String name = ti->get_metadata(0);
|
||||
|
||||
EditorNode::get_singleton()->set_addon_plugin_enabled(name, active, true);
|
||||
|
@ -173,14 +166,9 @@ void EditorPluginSettings::_plugin_activity_changed() {
|
|||
|
||||
if (is_active != active) {
|
||||
updating = true;
|
||||
ti->set_range(3, is_active ? 1 : 0);
|
||||
ti->set_checked(3, is_active);
|
||||
updating = false;
|
||||
}
|
||||
|
||||
if (is_active)
|
||||
ti->set_custom_color(3, get_color("success_color", "Editor"));
|
||||
else
|
||||
ti->set_custom_color(3, get_color("disabled_font_color", "Editor"));
|
||||
}
|
||||
|
||||
void EditorPluginSettings::_create_clicked() {
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* file_type_cache.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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 "file_type_cache.h"
|
||||
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/project_settings.h"
|
||||
|
||||
FileTypeCache *FileTypeCache::singleton = NULL;
|
||||
|
||||
bool FileTypeCache::has_file(const String &p_path) const {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION
|
||||
return file_type_map.has(p_path);
|
||||
}
|
||||
|
||||
String FileTypeCache::get_file_type(const String &p_path) const {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION
|
||||
ERR_FAIL_COND_V(!file_type_map.has(p_path), "");
|
||||
return file_type_map[p_path];
|
||||
}
|
||||
void FileTypeCache::set_file_type(const String &p_path, const String &p_type) {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION
|
||||
file_type_map[p_path] = p_type;
|
||||
}
|
||||
|
||||
void FileTypeCache::load() {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION
|
||||
String project = ProjectSettings::get_singleton()->get_resource_path();
|
||||
FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::READ);
|
||||
|
||||
if (!f) {
|
||||
|
||||
WARN_PRINT("Can't open file_type_cache.cch.");
|
||||
return;
|
||||
}
|
||||
|
||||
file_type_map.clear();
|
||||
while (!f->eof_reached()) {
|
||||
|
||||
String path = f->get_line();
|
||||
if (f->eof_reached())
|
||||
break;
|
||||
String type = f->get_line();
|
||||
set_file_type(path, type);
|
||||
}
|
||||
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
void FileTypeCache::save() {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION
|
||||
String project = ProjectSettings::get_singleton()->get_resource_path();
|
||||
FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE);
|
||||
|
||||
ERR_FAIL_COND_MSG(!f, "Can't open file_type_cache.cch for writing, not saving file type cache!");
|
||||
|
||||
const String *K = NULL;
|
||||
|
||||
while ((K = file_type_map.next(K))) {
|
||||
|
||||
f->store_line(*K);
|
||||
f->store_line(file_type_map[*K]);
|
||||
}
|
||||
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
FileTypeCache::FileTypeCache() {
|
||||
|
||||
ERR_FAIL_COND_MSG(singleton, "FileTypeCache singleton already exist.");
|
||||
singleton = this;
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* file_type_cache.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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 FILE_TYPE_CACHE_H
|
||||
#define FILE_TYPE_CACHE_H
|
||||
|
||||
#include "core/object.h"
|
||||
|
||||
class FileTypeCache : Object {
|
||||
|
||||
GDCLASS(FileTypeCache, Object);
|
||||
|
||||
HashMap<String, String> file_type_map;
|
||||
|
||||
static FileTypeCache *singleton;
|
||||
|
||||
public:
|
||||
static FileTypeCache *get_singleton() { return singleton; }
|
||||
|
||||
bool has_file(const String &p_path) const;
|
||||
String get_file_type(const String &p_path) const;
|
||||
void set_file_type(const String &p_path, const String &p_type);
|
||||
|
||||
void load();
|
||||
void save();
|
||||
|
||||
FileTypeCache();
|
||||
};
|
||||
|
||||
#endif // FILE_TYPE_CACHE_H
|
|
@ -4217,10 +4217,20 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
|
|||
|
||||
float prev_zoom = zoom;
|
||||
zoom = p_zoom;
|
||||
Point2 ofs = p_position;
|
||||
ofs = ofs / prev_zoom - ofs / zoom;
|
||||
view_offset.x = Math::round(view_offset.x + ofs.x);
|
||||
view_offset.y = Math::round(view_offset.y + ofs.y);
|
||||
|
||||
view_offset += p_position / prev_zoom - p_position / zoom;
|
||||
|
||||
// We want to align in-scene pixels to screen pixels, this prevents blurry rendering
|
||||
// in small details (texts, lines).
|
||||
// This correction adds a jitter movement when zooming, so we correct only when the
|
||||
// zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
|
||||
float closest_zoom_factor = Math::round(zoom);
|
||||
if (Math::is_zero_approx(zoom - closest_zoom_factor)) {
|
||||
// make sure scene pixel at view_offset is aligned on a screen pixel
|
||||
Vector2 view_offset_int = view_offset.floor();
|
||||
Vector2 view_offset_frac = view_offset - view_offset_int;
|
||||
view_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
|
||||
}
|
||||
|
||||
_update_zoom_label();
|
||||
update_viewport();
|
||||
|
|
|
@ -2389,11 +2389,19 @@ void SpatialEditorViewport::_notification(int p_what) {
|
|||
if (!se)
|
||||
continue;
|
||||
|
||||
Transform t = sp->get_global_gizmo_transform();
|
||||
|
||||
exist = true;
|
||||
if (se->last_xform == t && !se->last_xform_dirty)
|
||||
continue;
|
||||
changed = true;
|
||||
se->last_xform_dirty = false;
|
||||
se->last_xform = t;
|
||||
|
||||
VisualInstance *vi = Object::cast_to<VisualInstance>(sp);
|
||||
|
||||
se->aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp);
|
||||
|
||||
Transform t = sp->get_global_gizmo_transform();
|
||||
t.translate(se->aabb.position);
|
||||
|
||||
// apply AABB scaling before item's global transform
|
||||
|
@ -2401,11 +2409,6 @@ void SpatialEditorViewport::_notification(int p_what) {
|
|||
aabb_s.scale(se->aabb.size);
|
||||
t.basis = t.basis * aabb_s;
|
||||
|
||||
exist = true;
|
||||
if (se->last_xform == t)
|
||||
continue;
|
||||
changed = true;
|
||||
se->last_xform = t;
|
||||
VisualServer::get_singleton()->instance_set_transform(se->sbox_instance, t);
|
||||
}
|
||||
|
||||
|
@ -3360,6 +3363,7 @@ void SpatialEditorViewport::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("_menu_option"), &SpatialEditorViewport::_menu_option);
|
||||
ClassDB::bind_method(D_METHOD("_toggle_camera_preview"), &SpatialEditorViewport::_toggle_camera_preview);
|
||||
ClassDB::bind_method(D_METHOD("_preview_exited_scene"), &SpatialEditorViewport::_preview_exited_scene);
|
||||
ClassDB::bind_method(D_METHOD("_update_camera"), &SpatialEditorViewport::_update_camera);
|
||||
ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &SpatialEditorViewport::update_transform_gizmo_view);
|
||||
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &SpatialEditorViewport::_selection_result_pressed);
|
||||
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &SpatialEditorViewport::_selection_menu_hide);
|
||||
|
@ -4504,13 +4508,15 @@ void SpatialEditor::set_state(const Dictionary &p_state) {
|
|||
}
|
||||
|
||||
if (d.has("translate_snap"))
|
||||
snap_translate->set_text(d["translate_snap"]);
|
||||
snap_translate_value = d["translate_snap"];
|
||||
|
||||
if (d.has("rotate_snap"))
|
||||
snap_rotate->set_text(d["rotate_snap"]);
|
||||
snap_rotate_value = d["rotate_snap"];
|
||||
|
||||
if (d.has("scale_snap"))
|
||||
snap_scale->set_text(d["scale_snap"]);
|
||||
snap_scale_value = d["scale_snap"];
|
||||
|
||||
_snap_update();
|
||||
|
||||
if (d.has("local_coords")) {
|
||||
tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_pressed(d["local_coords"]);
|
||||
|
@ -4617,6 +4623,20 @@ void SpatialEditor::edit(Spatial *p_spatial) {
|
|||
}
|
||||
}
|
||||
|
||||
void SpatialEditor::_snap_changed() {
|
||||
|
||||
snap_translate_value = snap_translate->get_text().to_double();
|
||||
snap_rotate_value = snap_rotate->get_text().to_double();
|
||||
snap_scale_value = snap_scale->get_text().to_double();
|
||||
}
|
||||
|
||||
void SpatialEditor::_snap_update() {
|
||||
|
||||
snap_translate->set_text(String::num(snap_translate_value));
|
||||
snap_rotate->set_text(String::num(snap_rotate_value));
|
||||
snap_scale->set_text(String::num(snap_scale_value));
|
||||
}
|
||||
|
||||
void SpatialEditor::_xform_dialog_action() {
|
||||
|
||||
Transform t;
|
||||
|
@ -5848,6 +5868,8 @@ void SpatialEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons);
|
||||
ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button);
|
||||
ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport);
|
||||
ClassDB::bind_method("_snap_changed", &SpatialEditor::_snap_changed);
|
||||
ClassDB::bind_method("_snap_update", &SpatialEditor::_snap_update);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("transform_key_request"));
|
||||
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
|
||||
|
@ -6106,25 +6128,30 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
|
|||
|
||||
/* SNAP DIALOG */
|
||||
|
||||
snap_translate_value = 1;
|
||||
snap_rotate_value = 15;
|
||||
snap_scale_value = 10;
|
||||
|
||||
snap_dialog = memnew(ConfirmationDialog);
|
||||
snap_dialog->set_title(TTR("Snap Settings"));
|
||||
add_child(snap_dialog);
|
||||
snap_dialog->connect("confirmed", this, "_snap_changed");
|
||||
snap_dialog->get_cancel()->connect("pressed", this, "_snap_update");
|
||||
|
||||
VBoxContainer *snap_dialog_vbc = memnew(VBoxContainer);
|
||||
snap_dialog->add_child(snap_dialog_vbc);
|
||||
|
||||
snap_translate = memnew(LineEdit);
|
||||
snap_translate->set_text("1");
|
||||
snap_dialog_vbc->add_margin_child(TTR("Translate Snap:"), snap_translate);
|
||||
|
||||
snap_rotate = memnew(LineEdit);
|
||||
snap_rotate->set_text("15");
|
||||
snap_dialog_vbc->add_margin_child(TTR("Rotate Snap (deg.):"), snap_rotate);
|
||||
|
||||
snap_scale = memnew(LineEdit);
|
||||
snap_scale->set_text("10");
|
||||
snap_dialog_vbc->add_margin_child(TTR("Scale Snap (%):"), snap_scale);
|
||||
|
||||
_snap_update();
|
||||
|
||||
/* SETTINGS DIALOG */
|
||||
|
||||
settings_dialog = memnew(ConfirmationDialog);
|
||||
|
@ -6155,6 +6182,10 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
|
|||
settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500));
|
||||
settings_vbc->add_margin_child(TTR("View Z-Far:"), settings_zfar);
|
||||
|
||||
for (uint32_t i = 0; i < VIEWPORTS_COUNT; ++i) {
|
||||
settings_dialog->connect("confirmed", viewports[i], "_update_camera", varray(0.0));
|
||||
}
|
||||
|
||||
/* XFORM DIALOG */
|
||||
|
||||
xform_dialog = memnew(ConfirmationDialog);
|
||||
|
|
|
@ -469,10 +469,14 @@ public:
|
|||
Transform original; // original location when moving
|
||||
Transform original_local;
|
||||
Transform last_xform; // last transform
|
||||
bool last_xform_dirty;
|
||||
Spatial *sp;
|
||||
RID sbox_instance;
|
||||
|
||||
SpatialEditorSelectedItem() { sp = NULL; }
|
||||
SpatialEditorSelectedItem() {
|
||||
sp = NULL;
|
||||
last_xform_dirty = true;
|
||||
}
|
||||
~SpatialEditorSelectedItem();
|
||||
};
|
||||
|
||||
|
@ -579,6 +583,9 @@ private:
|
|||
Ref<SpatialMaterial> plane_gizmo_color_hl[3];
|
||||
|
||||
int over_gizmo_handle;
|
||||
float snap_translate_value;
|
||||
float snap_rotate_value;
|
||||
float snap_scale_value;
|
||||
|
||||
Ref<ArrayMesh> selection_box;
|
||||
RID indicators;
|
||||
|
@ -658,6 +665,8 @@ private:
|
|||
SpinBox *settings_znear;
|
||||
SpinBox *settings_zfar;
|
||||
|
||||
void _snap_changed();
|
||||
void _snap_update();
|
||||
void _xform_dialog_action();
|
||||
void _menu_item_pressed(int p_option);
|
||||
void _menu_item_toggled(bool pressed, int p_option);
|
||||
|
|
|
@ -1999,6 +1999,8 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
|
|||
device_index_label = l;
|
||||
|
||||
device_index = memnew(OptionButton);
|
||||
device_index->set_clip_text(true);
|
||||
|
||||
vbc_right->add_child(device_index);
|
||||
|
||||
setting = false;
|
||||
|
|
|
@ -28,8 +28,9 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "test_main.h"
|
||||
|
||||
#include "core/list.h"
|
||||
#include "core/os/main_loop.h"
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
|
||||
|
|
|
@ -32,9 +32,10 @@
|
|||
#define TEST_MAIN_H
|
||||
|
||||
#include "core/list.h"
|
||||
#include "core/os/main_loop.h"
|
||||
#include "core/ustring.h"
|
||||
|
||||
const char **tests_get_names();
|
||||
MainLoop *test_main(String p_test, const List<String> &p_args);
|
||||
|
||||
#endif
|
||||
#endif // TEST_MAIN_H
|
||||
|
|
|
@ -30,9 +30,8 @@
|
|||
|
||||
#include "test_oa_hash_map.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
|
||||
#include "core/oa_hash_map.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
namespace TestOAHashMap {
|
||||
|
||||
|
|
|
@ -37,4 +37,5 @@ namespace TestOAHashMap {
|
|||
|
||||
MainLoop *test();
|
||||
}
|
||||
|
||||
#endif // TEST_OA_HASH_MAP_H
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "test_ordered_hash_map.h"
|
||||
|
||||
#include "core/ordered_hash_map.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/pair.h"
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
#ifndef TEST_ORDERED_HASH_MAP_H
|
||||
#define TEST_ORDERED_HASH_MAP_H
|
||||
|
||||
#include "core/os/main_loop.h"
|
||||
|
||||
namespace TestOrderedHashMap {
|
||||
|
||||
MainLoop *test();
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // TEST_ORDERED_HASH_MAP_H
|
||||
|
|
47
methods.py
47
methods.py
|
@ -181,53 +181,6 @@ void unregister_module_types() {
|
|||
return module_list
|
||||
|
||||
|
||||
def win32_spawn(sh, escape, cmd, args, env):
|
||||
import subprocess
|
||||
newargs = ' '.join(args[1:])
|
||||
cmdline = cmd + " " + newargs
|
||||
startupinfo = subprocess.STARTUPINFO()
|
||||
for e in env:
|
||||
if type(env[e]) != type(""):
|
||||
env[e] = str(env[e])
|
||||
proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, startupinfo=startupinfo, shell=False, env=env)
|
||||
_, err = proc.communicate()
|
||||
rv = proc.wait()
|
||||
if rv:
|
||||
print("=====")
|
||||
print(err)
|
||||
print("=====")
|
||||
return rv
|
||||
|
||||
"""
|
||||
def win32_spawn(sh, escape, cmd, args, spawnenv):
|
||||
import win32file
|
||||
import win32event
|
||||
import win32process
|
||||
import win32security
|
||||
for var in spawnenv:
|
||||
spawnenv[var] = spawnenv[var].encode('ascii', 'replace')
|
||||
|
||||
sAttrs = win32security.SECURITY_ATTRIBUTES()
|
||||
StartupInfo = win32process.STARTUPINFO()
|
||||
newargs = ' '.join(map(escape, args[1:]))
|
||||
cmdline = cmd + " " + newargs
|
||||
|
||||
# check for any special operating system commands
|
||||
if cmd == 'del':
|
||||
for arg in args[1:]:
|
||||
win32file.DeleteFile(arg)
|
||||
exit_code = 0
|
||||
else:
|
||||
# otherwise execute the command.
|
||||
hProcess, hThread, dwPid, dwTid = win32process.CreateProcess(None, cmdline, None, None, 1, 0, spawnenv, None, StartupInfo)
|
||||
win32event.WaitForSingleObject(hProcess, win32event.INFINITE)
|
||||
exit_code = win32process.GetExitCodeProcess(hProcess)
|
||||
win32file.CloseHandle(hProcess);
|
||||
win32file.CloseHandle(hThread);
|
||||
return exit_code
|
||||
"""
|
||||
|
||||
def disable_module(self):
|
||||
self.disabled_modules.append(self.current_module)
|
||||
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ASSIMP_REGISTER_TYPES_H
|
||||
#define ASSIMP_REGISTER_TYPES_H
|
||||
|
||||
void register_assimp_types();
|
||||
void unregister_assimp_types();
|
||||
|
||||
#endif // ASSIMP_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef BMP_REGISTER_TYPES_H
|
||||
#define BMP_REGISTER_TYPES_H
|
||||
|
||||
void register_bmp_types();
|
||||
void unregister_bmp_types();
|
||||
|
||||
#endif // BMP_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef CSG_REGISTER_TYPES_H
|
||||
#define CSG_REGISTER_TYPES_H
|
||||
|
||||
void register_csg_types();
|
||||
void unregister_csg_types();
|
||||
|
||||
#endif // CSG_REGISTER_TYPES_H
|
||||
|
|
|
@ -29,6 +29,13 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
|
||||
#ifndef CVTT_REGISTER_TYPES_H
|
||||
#define CVTT_REGISTER_TYPES_H
|
||||
|
||||
void register_cvtt_types();
|
||||
void unregister_cvtt_types();
|
||||
#endif
|
||||
|
||||
#endif // CVTT_REGISTER_TYPES_H
|
||||
|
||||
#endif // TOOLS_ENABLED
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef DDS_REGISTER_TYPES_H
|
||||
#define DDS_REGISTER_TYPES_H
|
||||
|
||||
void register_dds_types();
|
||||
void unregister_dds_types();
|
||||
|
||||
#endif // DDS_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ENET_REGISTER_TYPES_H
|
||||
#define ENET_REGISTER_TYPES_H
|
||||
|
||||
void register_enet_types();
|
||||
void unregister_enet_types();
|
||||
|
||||
#endif // ENET_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ETC_REGISTER_TYPES_H
|
||||
#define ETC_REGISTER_TYPES_H
|
||||
|
||||
void register_etc_types();
|
||||
void unregister_etc_types();
|
||||
|
||||
#endif // ETC_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef FREETYPE_REGISTER_TYPES_H
|
||||
#define FREETYPE_REGISTER_TYPES_H
|
||||
|
||||
void register_freetype_types();
|
||||
void unregister_freetype_types();
|
||||
|
||||
#endif // FREETYPE_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef ARVR_REGISTER_TYPES_H
|
||||
#define ARVR_REGISTER_TYPES_H
|
||||
|
||||
void register_arvr_types();
|
||||
void unregister_arvr_types();
|
||||
|
||||
#endif // ARVR_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef NATIVESCRIPT_REGISTER_TYPES_H
|
||||
#define NATIVESCRIPT_REGISTER_TYPES_H
|
||||
|
||||
void register_nativescript_types();
|
||||
void unregister_nativescript_types();
|
||||
|
||||
#endif // NATIVESCRIPT_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef NET_REGISTER_TYPES_H
|
||||
#define NET_REGISTER_TYPES_H
|
||||
|
||||
void register_net_types();
|
||||
void unregister_net_types();
|
||||
|
||||
#endif // NET_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PLUGINSCRIPT_REGISTER_TYPES_H
|
||||
#define PLUGINSCRIPT_REGISTER_TYPES_H
|
||||
|
||||
void register_pluginscript_types();
|
||||
void unregister_pluginscript_types();
|
||||
|
||||
#endif // PLUGINSCRIPT_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GDNATIVE_REGISTER_TYPES_H
|
||||
#define GDNATIVE_REGISTER_TYPES_H
|
||||
|
||||
void register_gdnative_types();
|
||||
void unregister_gdnative_types();
|
||||
|
||||
#endif // GDNATIVE_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef VIDEODECODER_REGISTER_TYPES_H
|
||||
#define VIDEODECODER_REGISTER_TYPES_H
|
||||
|
||||
void register_videodecoder_types();
|
||||
void unregister_videodecoder_types();
|
||||
|
||||
#endif // VIDEODECODER_REGISTER_TYPES_H
|
||||
|
|
|
@ -3103,18 +3103,18 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
|
|||
Vector<Node *> args;
|
||||
Vector<double> constants;
|
||||
|
||||
bool constant = false;
|
||||
bool constant = true;
|
||||
|
||||
for (int i = 1; i < op->arguments.size(); i++) {
|
||||
args.push_back(op->arguments[i]);
|
||||
if (constant && op->arguments[i]->type == Node::TYPE_CONSTANT) {
|
||||
if (op->arguments[i]->type == Node::TYPE_CONSTANT) {
|
||||
ConstantNode *c = static_cast<ConstantNode *>(op->arguments[i]);
|
||||
if (c->value.get_type() == Variant::REAL || c->value.get_type() == Variant::INT) {
|
||||
constants.push_back(c->value);
|
||||
constant = true;
|
||||
}
|
||||
} else {
|
||||
constant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3809,6 +3809,12 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
}
|
||||
|
||||
StringName argname = tokenizer->get_token_identifier();
|
||||
for (int i = 0; i < arguments.size(); i++) {
|
||||
if (arguments[i] == argname) {
|
||||
_set_error("The argument name \"" + String(argname) + "\" is defined multiple times.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
arguments.push_back(argname);
|
||||
#ifdef DEBUG_ENABLED
|
||||
arguments_usage.push_back(0);
|
||||
|
|
|
@ -32,32 +32,107 @@
|
|||
#include "core/io/json.h"
|
||||
#include "core/os/copymem.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "editor/editor_log.h"
|
||||
#include "editor/editor_node.h"
|
||||
|
||||
GDScriptLanguageProtocol *GDScriptLanguageProtocol::singleton = NULL;
|
||||
|
||||
void GDScriptLanguageProtocol::on_data_received(int p_id) {
|
||||
lastest_client_id = p_id;
|
||||
Ref<WebSocketPeer> peer = server->get_peer(p_id);
|
||||
PoolByteArray data;
|
||||
if (OK == peer->get_packet_buffer(data)) {
|
||||
String message;
|
||||
message.parse_utf8((const char *)data.read().ptr(), data.size());
|
||||
if (message.begins_with("Content-Length:")) return;
|
||||
String output = process_message(message);
|
||||
if (!output.empty()) {
|
||||
CharString charstr = output.utf8();
|
||||
peer->put_packet((const uint8_t *)charstr.ptr(), charstr.length());
|
||||
Error GDScriptLanguageProtocol::LSPeer::handle_data() {
|
||||
int read = 0;
|
||||
// Read headers
|
||||
if (!has_header) {
|
||||
while (true) {
|
||||
if (req_pos >= LSP_MAX_BUFFER_SIZE) {
|
||||
req_pos = 0;
|
||||
ERR_FAIL_COND_V_MSG(true, ERR_OUT_OF_MEMORY, "Response header too big");
|
||||
}
|
||||
Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
|
||||
if (err != OK)
|
||||
return FAILED;
|
||||
else if (read != 1) // Busy, wait until next poll
|
||||
return ERR_BUSY;
|
||||
char *r = (char *)req_buf;
|
||||
int l = req_pos;
|
||||
|
||||
// End of headers
|
||||
if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') {
|
||||
r[l - 3] = '\0'; // Null terminate to read string
|
||||
String header;
|
||||
header.parse_utf8(r);
|
||||
content_length = header.substr(16).to_int();
|
||||
has_header = true;
|
||||
req_pos = 0;
|
||||
break;
|
||||
}
|
||||
req_pos++;
|
||||
}
|
||||
}
|
||||
if (has_header) {
|
||||
while (req_pos < content_length) {
|
||||
if (req_pos >= LSP_MAX_BUFFER_SIZE) {
|
||||
req_pos = 0;
|
||||
has_header = false;
|
||||
ERR_FAIL_COND_V_MSG(req_pos >= LSP_MAX_BUFFER_SIZE, ERR_OUT_OF_MEMORY, "Response content too big");
|
||||
}
|
||||
Error err = connection->get_partial_data(&req_buf[req_pos], 1, read);
|
||||
if (err != OK)
|
||||
return FAILED;
|
||||
else if (read != 1)
|
||||
return ERR_BUSY;
|
||||
req_pos++;
|
||||
}
|
||||
|
||||
// Parse data
|
||||
String msg;
|
||||
msg.parse_utf8((const char *)req_buf, req_pos);
|
||||
|
||||
// Reset to read again
|
||||
req_pos = 0;
|
||||
has_header = false;
|
||||
|
||||
// Response
|
||||
String output = GDScriptLanguageProtocol::get_singleton()->process_message(msg);
|
||||
if (!output.empty()) {
|
||||
res_queue.push_back(output.utf8());
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::on_client_connected(int p_id, const String &p_protocal) {
|
||||
clients.set(p_id, server->get_peer(p_id));
|
||||
Error GDScriptLanguageProtocol::LSPeer::send_data() {
|
||||
int sent = 0;
|
||||
if (!res_queue.empty()) {
|
||||
CharString c_res = res_queue[0];
|
||||
if (res_sent < c_res.size()) {
|
||||
Error err = connection->put_partial_data((const uint8_t *)c_res.get_data() + res_sent, c_res.size() - res_sent - 1, sent);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
res_sent += sent;
|
||||
}
|
||||
// Response sent
|
||||
if (res_sent >= c_res.size() - 1) {
|
||||
res_sent = 0;
|
||||
res_queue.remove(0);
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::on_client_disconnected(int p_id, bool p_was_clean_close) {
|
||||
clients.erase(p_id);
|
||||
Error GDScriptLanguageProtocol::on_client_connected() {
|
||||
Ref<StreamPeerTCP> tcp_peer = server->take_connection();
|
||||
ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached");
|
||||
Ref<LSPeer> peer = memnew(LSPeer);
|
||||
peer->connection = tcp_peer;
|
||||
clients.set(next_client_id, peer);
|
||||
next_client_id++;
|
||||
EditorNode::get_log()->add_message("Connection Taken", EditorLog::MSG_TYPE_EDITOR);
|
||||
return OK;
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::on_client_disconnected(const int &p_client_id) {
|
||||
clients.erase(p_client_id);
|
||||
EditorNode::get_log()->add_message("Disconnected", EditorLog::MSG_TYPE_EDITOR);
|
||||
}
|
||||
|
||||
String GDScriptLanguageProtocol::process_message(const String &p_text) {
|
||||
|
@ -83,11 +158,9 @@ String GDScriptLanguageProtocol::format_output(const String &p_text) {
|
|||
void GDScriptLanguageProtocol::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("initialize", "params"), &GDScriptLanguageProtocol::initialize);
|
||||
ClassDB::bind_method(D_METHOD("initialized", "params"), &GDScriptLanguageProtocol::initialized);
|
||||
ClassDB::bind_method(D_METHOD("on_data_received"), &GDScriptLanguageProtocol::on_data_received);
|
||||
ClassDB::bind_method(D_METHOD("on_client_connected"), &GDScriptLanguageProtocol::on_client_connected);
|
||||
ClassDB::bind_method(D_METHOD("on_client_disconnected"), &GDScriptLanguageProtocol::on_client_disconnected);
|
||||
ClassDB::bind_method(D_METHOD("notify_all_clients", "p_method", "p_params"), &GDScriptLanguageProtocol::notify_all_clients, DEFVAL(Variant()));
|
||||
ClassDB::bind_method(D_METHOD("notify_client", "p_method", "p_params", "p_client"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("notify_client", "p_method", "p_params"), &GDScriptLanguageProtocol::notify_client, DEFVAL(Variant()), DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("is_smart_resolve_enabled"), &GDScriptLanguageProtocol::is_smart_resolve_enabled);
|
||||
ClassDB::bind_method(D_METHOD("get_text_document"), &GDScriptLanguageProtocol::get_text_document);
|
||||
ClassDB::bind_method(D_METHOD("get_workspace"), &GDScriptLanguageProtocol::get_workspace);
|
||||
|
@ -116,11 +189,12 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) {
|
|||
Dictionary params;
|
||||
params["path"] = workspace->root;
|
||||
Dictionary request = make_notification("gdscrip_client/changeWorkspace", params);
|
||||
if (Ref<WebSocketPeer> *peer = clients.getptr(lastest_client_id)) {
|
||||
|
||||
Ref<LSPeer> peer = clients.get(latest_client_id);
|
||||
if (peer != NULL) {
|
||||
String msg = JSON::print(request);
|
||||
msg = format_output(msg);
|
||||
CharString charstr = msg.utf8();
|
||||
(*peer)->put_packet((const uint8_t *)charstr.ptr(), charstr.length());
|
||||
(*peer)->res_queue.push_back(msg.utf8());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,61 +227,59 @@ void GDScriptLanguageProtocol::initialized(const Variant &p_params) {
|
|||
}
|
||||
|
||||
void GDScriptLanguageProtocol::poll() {
|
||||
server->poll();
|
||||
if (server->is_connection_available()) {
|
||||
on_client_connected();
|
||||
}
|
||||
const int *id = NULL;
|
||||
while ((id = clients.next(id))) {
|
||||
Ref<LSPeer> peer = clients.get(*id);
|
||||
StreamPeerTCP::Status status = peer->connection->get_status();
|
||||
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
|
||||
on_client_disconnected(*id);
|
||||
id = NULL;
|
||||
} else {
|
||||
if (peer->connection->get_available_bytes() > 0) {
|
||||
latest_client_id = *id;
|
||||
Error err = peer->handle_data();
|
||||
if (err != OK && err != ERR_BUSY) {
|
||||
on_client_disconnected(*id);
|
||||
id = NULL;
|
||||
}
|
||||
}
|
||||
Error err = peer->send_data();
|
||||
if (err != OK && err != ERR_BUSY) {
|
||||
on_client_disconnected(*id);
|
||||
id = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) {
|
||||
if (server == NULL) {
|
||||
server = dynamic_cast<WebSocketServer *>(ClassDB::instance("WebSocketServer"));
|
||||
ERR_FAIL_COND_V(!server, FAILED);
|
||||
server->set_buffers(8192, 1024, 8192, 1024); // 8mb should be way more than enough
|
||||
server->connect("data_received", this, "on_data_received");
|
||||
server->connect("client_connected", this, "on_client_connected");
|
||||
server->connect("client_disconnected", this, "on_client_disconnected");
|
||||
}
|
||||
server->set_bind_ip(p_bind_ip);
|
||||
return server->listen(p_port);
|
||||
return server->listen(p_port, p_bind_ip);
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::stop() {
|
||||
const int *ptr = clients.next(NULL);
|
||||
while (ptr) {
|
||||
clients.get(*ptr)->close();
|
||||
ptr = clients.next(ptr);
|
||||
const int *id = NULL;
|
||||
while ((id = clients.next(id))) {
|
||||
Ref<LSPeer> peer = clients.get(*id);
|
||||
peer->connection->disconnect_from_host();
|
||||
}
|
||||
|
||||
server->stop();
|
||||
clients.clear();
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::notify_all_clients(const String &p_method, const Variant &p_params) {
|
||||
|
||||
Dictionary message = make_notification(p_method, p_params);
|
||||
String msg = JSON::print(message);
|
||||
msg = format_output(msg);
|
||||
CharString charstr = msg.utf8();
|
||||
const int *p_id = clients.next(NULL);
|
||||
while (p_id != NULL) {
|
||||
Ref<WebSocketPeer> peer = clients.get(*p_id);
|
||||
(*peer)->put_packet((const uint8_t *)charstr.ptr(), charstr.length());
|
||||
p_id = clients.next(p_id);
|
||||
void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client_id) {
|
||||
if (p_client_id == -1) {
|
||||
p_client_id = latest_client_id;
|
||||
}
|
||||
}
|
||||
|
||||
void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client) {
|
||||
|
||||
if (p_client == -1) {
|
||||
p_client = lastest_client_id;
|
||||
}
|
||||
|
||||
Ref<WebSocketPeer> *peer = clients.getptr(p_client);
|
||||
Ref<LSPeer> peer = clients.get(p_client_id);
|
||||
ERR_FAIL_COND(peer == NULL);
|
||||
|
||||
Dictionary message = make_notification(p_method, p_params);
|
||||
String msg = JSON::print(message);
|
||||
msg = format_output(msg);
|
||||
CharString charstr = msg.utf8();
|
||||
|
||||
(*peer)->put_packet((const uint8_t *)charstr.ptr(), charstr.length());
|
||||
peer->res_queue.push_back(msg.utf8());
|
||||
}
|
||||
|
||||
bool GDScriptLanguageProtocol::is_smart_resolve_enabled() const {
|
||||
|
@ -219,7 +291,7 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const {
|
|||
}
|
||||
|
||||
GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
|
||||
server = NULL;
|
||||
server.instance();
|
||||
singleton = this;
|
||||
_initialized = false;
|
||||
workspace.instance();
|
||||
|
@ -228,9 +300,6 @@ GDScriptLanguageProtocol::GDScriptLanguageProtocol() {
|
|||
set_scope("completionItem", text_document.ptr());
|
||||
set_scope("workspace", workspace.ptr());
|
||||
workspace->root = ProjectSettings::get_singleton()->get_resource_path();
|
||||
}
|
||||
|
||||
GDScriptLanguageProtocol::~GDScriptLanguageProtocol() {
|
||||
memdelete(server);
|
||||
server = NULL;
|
||||
latest_client_id = 0;
|
||||
next_client_id = 0;
|
||||
}
|
||||
|
|
|
@ -31,16 +31,36 @@
|
|||
#ifndef GDSCRIPT_PROTOCAL_SERVER_H
|
||||
#define GDSCRIPT_PROTOCAL_SERVER_H
|
||||
|
||||
#include "core/io/stream_peer.h"
|
||||
#include "core/io/stream_peer_tcp.h"
|
||||
#include "core/io/tcp_server.h"
|
||||
#include "gdscript_text_document.h"
|
||||
#include "gdscript_workspace.h"
|
||||
#include "lsp.hpp"
|
||||
#include "modules/jsonrpc/jsonrpc.h"
|
||||
#include "modules/websocket/websocket_peer.h"
|
||||
#include "modules/websocket/websocket_server.h"
|
||||
|
||||
#define LSP_MAX_BUFFER_SIZE 4194304
|
||||
#define LSP_MAX_CLIENTS 8
|
||||
|
||||
class GDScriptLanguageProtocol : public JSONRPC {
|
||||
GDCLASS(GDScriptLanguageProtocol, JSONRPC)
|
||||
|
||||
private:
|
||||
struct LSPeer : Reference {
|
||||
Ref<StreamPeerTCP> connection;
|
||||
|
||||
uint8_t req_buf[LSP_MAX_BUFFER_SIZE];
|
||||
int req_pos = 0;
|
||||
bool has_header = false;
|
||||
bool has_content = false;
|
||||
int content_length = 0;
|
||||
Vector<CharString> res_queue;
|
||||
int res_sent = 0;
|
||||
|
||||
Error handle_data();
|
||||
Error send_data();
|
||||
};
|
||||
|
||||
enum LSPErrorCode {
|
||||
RequestCancelled = -32800,
|
||||
ContentModified = -32801,
|
||||
|
@ -48,16 +68,16 @@ class GDScriptLanguageProtocol : public JSONRPC {
|
|||
|
||||
static GDScriptLanguageProtocol *singleton;
|
||||
|
||||
HashMap<int, Ref<WebSocketPeer> > clients;
|
||||
WebSocketServer *server;
|
||||
int lastest_client_id;
|
||||
HashMap<int, Ref<LSPeer> > clients;
|
||||
Ref<TCP_Server> server;
|
||||
int latest_client_id;
|
||||
int next_client_id;
|
||||
|
||||
Ref<GDScriptTextDocument> text_document;
|
||||
Ref<GDScriptWorkspace> workspace;
|
||||
|
||||
void on_data_received(int p_id);
|
||||
void on_client_connected(int p_id, const String &p_protocal);
|
||||
void on_client_disconnected(int p_id, bool p_was_clean_close);
|
||||
Error on_client_connected();
|
||||
void on_client_disconnected(const int &p_client_id);
|
||||
|
||||
String process_message(const String &p_text);
|
||||
String format_output(const String &p_text);
|
||||
|
@ -80,14 +100,12 @@ public:
|
|||
Error start(int p_port, const IP_Address &p_bind_ip);
|
||||
void stop();
|
||||
|
||||
void notify_all_clients(const String &p_method, const Variant &p_params = Variant());
|
||||
void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client = -1);
|
||||
void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1);
|
||||
|
||||
bool is_smart_resolve_enabled() const;
|
||||
bool is_goto_native_symbols_enabled() const;
|
||||
|
||||
GDScriptLanguageProtocol();
|
||||
~GDScriptLanguageProtocol();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,8 +33,11 @@
|
|||
#include "../gdscript_parser.h"
|
||||
#include "core/project_settings.h"
|
||||
#include "core/script_language.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "editor/editor_help.h"
|
||||
#include "editor/editor_node.h"
|
||||
#include "gdscript_language_protocol.h"
|
||||
#include "scene/resources/packed_scene.h"
|
||||
|
||||
void GDScriptWorkspace::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol);
|
||||
|
@ -373,6 +376,50 @@ void GDScriptWorkspace::publish_diagnostics(const String &p_path) {
|
|||
GDScriptLanguageProtocol::get_singleton()->notify_client("textDocument/publishDiagnostics", params);
|
||||
}
|
||||
|
||||
void GDScriptWorkspace::_get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners) {
|
||||
if (!efsd)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < efsd->get_subdir_count(); i++) {
|
||||
_get_owners(efsd->get_subdir(i), p_path, owners);
|
||||
}
|
||||
|
||||
for (int i = 0; i < efsd->get_file_count(); i++) {
|
||||
|
||||
Vector<String> deps = efsd->get_file_deps(i);
|
||||
bool found = false;
|
||||
for (int j = 0; j < deps.size(); j++) {
|
||||
if (deps[j] == p_path) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
|
||||
owners.push_back(efsd->get_file_path(i));
|
||||
}
|
||||
}
|
||||
|
||||
Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
|
||||
Node *owner_scene_node = NULL;
|
||||
List<String> owners;
|
||||
|
||||
_get_owners(EditorFileSystem::get_singleton()->get_filesystem(), p_path, owners);
|
||||
|
||||
for (int i = 0; i < owners.size(); i++) {
|
||||
NodePath owner_path = owners[i];
|
||||
RES owner_res = ResourceLoader::load(owner_path);
|
||||
if (Object::cast_to<PackedScene>(owner_res.ptr())) {
|
||||
Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res));
|
||||
owner_scene_node = owner_packed_scene->instance();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return owner_scene_node;
|
||||
}
|
||||
|
||||
void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options) {
|
||||
|
||||
String path = get_file_path(p_params.textDocument.uri);
|
||||
|
@ -380,8 +427,12 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
|
|||
bool forced = false;
|
||||
|
||||
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
|
||||
Node *owner_scene_node = _get_owner_scene_node(path);
|
||||
String code = parser->get_text_for_completion(p_params.position);
|
||||
GDScriptLanguage::get_singleton()->complete_code(code, path, NULL, r_options, forced, call_hint);
|
||||
GDScriptLanguage::get_singleton()->complete_code(code, path, owner_scene_node, r_options, forced, call_hint);
|
||||
if (owner_scene_node) {
|
||||
memdelete(owner_scene_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,12 +33,17 @@
|
|||
|
||||
#include "../gdscript_parser.h"
|
||||
#include "core/variant.h"
|
||||
#include "editor/editor_file_system.h"
|
||||
#include "gdscript_extend_parser.h"
|
||||
#include "lsp.hpp"
|
||||
|
||||
class GDScriptWorkspace : public Reference {
|
||||
GDCLASS(GDScriptWorkspace, Reference);
|
||||
|
||||
private:
|
||||
void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners);
|
||||
Node *_get_owner_scene_node(String p_path);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
void remove_cache_parser(const String &p_path);
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GDSCRIPT_REGISTER_TYPES_H
|
||||
#define GDSCRIPT_REGISTER_TYPES_H
|
||||
|
||||
void register_gdscript_types();
|
||||
void unregister_gdscript_types();
|
||||
|
||||
#endif // GDSCRIPT_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef GRIDMAP_REGISTER_TYPES_H
|
||||
#define GRIDMAP_REGISTER_TYPES_H
|
||||
|
||||
void register_gridmap_types();
|
||||
void unregister_gridmap_types();
|
||||
|
||||
#endif // GRIDMAP_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef HDR_REGISTER_TYPES_H
|
||||
#define HDR_REGISTER_TYPES_H
|
||||
|
||||
void register_hdr_types();
|
||||
void unregister_hdr_types();
|
||||
|
||||
#endif // HDR_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef JPG_REGISTER_TYPES_H
|
||||
#define JPG_REGISTER_TYPES_H
|
||||
|
||||
void register_jpg_types();
|
||||
void unregister_jpg_types();
|
||||
|
||||
#endif // JPG_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef JSONRPC_REGISTER_TYPES_H
|
||||
#define JSONRPC_REGISTER_TYPES_H
|
||||
|
||||
void register_jsonrpc_types();
|
||||
void unregister_jsonrpc_types();
|
||||
|
||||
#endif // JSONRPC_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MBEDTLS_REGISTER_TYPES_H
|
||||
#define MBEDTLS_REGISTER_TYPES_H
|
||||
|
||||
void register_mbedtls_types();
|
||||
void unregister_mbedtls_types();
|
||||
|
||||
#endif // MBEDTLS_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef MOBILE_VR_REGISTER_TYPES_H
|
||||
#define MOBILE_VR_REGISTER_TYPES_H
|
||||
|
||||
void register_mobile_vr_types();
|
||||
void unregister_mobile_vr_types();
|
||||
|
||||
#endif // MOBILE_VR_REGISTER_TYPES_H
|
||||
|
|
|
@ -9,7 +9,7 @@ def configure(env):
|
|||
env.use_ptrcall = True
|
||||
env.add_module_version_string('mono')
|
||||
|
||||
from SCons.Script import BoolVariable, PathVariable, Variables
|
||||
from SCons.Script import BoolVariable, PathVariable, Variables, Help
|
||||
|
||||
envvars = Variables()
|
||||
envvars.Add(PathVariable('mono_prefix', 'Path to the mono installation directory for the target platform and architecture', '', PathVariable.PathAccept))
|
||||
|
@ -18,6 +18,7 @@ def configure(env):
|
|||
envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False))
|
||||
envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
|
||||
envvars.Update(env)
|
||||
Help(envvars.GenerateHelpText(env))
|
||||
|
||||
if env['platform'] == 'javascript':
|
||||
# Mono wasm already has zlib builtin, so we need this workaround to avoid symbol collisions
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using GodotTools.Core;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace GodotTools.ProjectEditor
|
||||
{
|
||||
|
@ -118,5 +120,40 @@ EndProject";
|
|||
const string ProjectPlatformsConfig =
|
||||
@" {{{0}}}.{1}|Any CPU.ActiveCfg = {1}|Any CPU
|
||||
{{{0}}}.{1}|Any CPU.Build.0 = {1}|Any CPU";
|
||||
|
||||
public static void MigrateFromOldConfigNames(string slnPath)
|
||||
{
|
||||
if (!File.Exists(slnPath))
|
||||
return;
|
||||
|
||||
var input = File.ReadAllText(slnPath);
|
||||
|
||||
if (!Regex.IsMatch(input, Regex.Escape("Tools|Any CPU")))
|
||||
return;
|
||||
|
||||
// This method renames old configurations in solutions to the new ones.
|
||||
//
|
||||
// This is the order configs appear in the solution and what we want to rename them to:
|
||||
// Debug|Any CPU = Debug|Any CPU -> ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
// Tools|Any CPU = Tools|Any CPU -> Debug|Any CPU = Debug|Any CPU
|
||||
//
|
||||
// But we want to move Tools (now Debug) to the top, so it's easier to rename like this:
|
||||
// Debug|Any CPU = Debug|Any CPU -> Debug|Any CPU = Debug|Any CPU
|
||||
// Release|Any CPU = Release|Any CPU -> ExportDebug|Any CPU = ExportDebug|Any CPU
|
||||
// Tools|Any CPU = Tools|Any CPU -> ExportRelease|Any CPU = ExportRelease|Any CPU
|
||||
|
||||
var dict = new Dictionary<string, string>
|
||||
{
|
||||
{"Debug|Any CPU", "Debug|Any CPU"},
|
||||
{"Release|Any CPU", "ExportDebug|Any CPU"},
|
||||
{"Tools|Any CPU", "ExportRelease|Any CPU"}
|
||||
};
|
||||
|
||||
var regex = new Regex(string.Join("|",dict.Keys.Select(Regex.Escape)));
|
||||
var result = regex.Replace(input,m => dict[m.Value]);
|
||||
|
||||
if (result != input)
|
||||
File.WriteAllText(slnPath, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,30 +17,30 @@ namespace GodotTools.ProjectEditor
|
|||
string path = Path.Combine(dir, name + ".csproj");
|
||||
|
||||
ProjectPropertyGroupElement mainGroup;
|
||||
var root = CreateLibraryProject(name, "Tools", out mainGroup);
|
||||
var root = CreateLibraryProject(name, "Debug", out mainGroup);
|
||||
|
||||
mainGroup.SetProperty("OutputPath", Path.Combine(".mono", "temp", "bin", "$(Configuration)"));
|
||||
mainGroup.SetProperty("BaseIntermediateOutputPath", Path.Combine(".mono", "temp", "obj"));
|
||||
mainGroup.SetProperty("IntermediateOutputPath", Path.Combine("$(BaseIntermediateOutputPath)", "$(Configuration)"));
|
||||
mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'Release' ";
|
||||
mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'Release' ";
|
||||
mainGroup.SetProperty("ApiConfiguration", "Debug").Condition = " '$(Configuration)' != 'ExportRelease' ";
|
||||
mainGroup.SetProperty("ApiConfiguration", "Release").Condition = " '$(Configuration)' == 'ExportRelease' ";
|
||||
|
||||
var toolsGroup = root.AddPropertyGroup();
|
||||
toolsGroup.Condition = " '$(Configuration)|$(Platform)' == 'Tools|AnyCPU' ";
|
||||
toolsGroup.AddProperty("DebugSymbols", "true");
|
||||
toolsGroup.AddProperty("DebugType", "portable");
|
||||
toolsGroup.AddProperty("Optimize", "false");
|
||||
toolsGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;");
|
||||
toolsGroup.AddProperty("ErrorReport", "prompt");
|
||||
toolsGroup.AddProperty("WarningLevel", "4");
|
||||
toolsGroup.AddProperty("ConsolePause", "false");
|
||||
var debugGroup = root.AddPropertyGroup();
|
||||
debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
|
||||
debugGroup.AddProperty("DebugSymbols", "true");
|
||||
debugGroup.AddProperty("DebugType", "portable");
|
||||
debugGroup.AddProperty("Optimize", "false");
|
||||
debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;TOOLS;");
|
||||
debugGroup.AddProperty("ErrorReport", "prompt");
|
||||
debugGroup.AddProperty("WarningLevel", "4");
|
||||
debugGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
var coreApiRef = root.AddItem("Reference", CoreApiProjectName);
|
||||
coreApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", CoreApiProjectName + ".dll"));
|
||||
coreApiRef.AddMetadata("Private", "False");
|
||||
|
||||
var editorApiRef = root.AddItem("Reference", EditorApiProjectName);
|
||||
editorApiRef.Condition = " '$(Configuration)' == 'Tools' ";
|
||||
editorApiRef.Condition = " '$(Configuration)' == 'Debug' ";
|
||||
editorApiRef.AddMetadata("HintPath", Path.Combine("$(ProjectDir)", ".mono", "assemblies", "$(ApiConfiguration)", EditorApiProjectName + ".dll"));
|
||||
editorApiRef.AddMetadata("Private", "False");
|
||||
|
||||
|
@ -103,24 +103,24 @@ namespace GodotTools.ProjectEditor
|
|||
mainGroup.AddProperty("TargetFrameworkVersion", "v4.7");
|
||||
mainGroup.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||
|
||||
var debugGroup = root.AddPropertyGroup();
|
||||
debugGroup.Condition = " '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ";
|
||||
debugGroup.AddProperty("DebugSymbols", "true");
|
||||
debugGroup.AddProperty("DebugType", "portable");
|
||||
debugGroup.AddProperty("Optimize", "false");
|
||||
debugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;");
|
||||
debugGroup.AddProperty("ErrorReport", "prompt");
|
||||
debugGroup.AddProperty("WarningLevel", "4");
|
||||
debugGroup.AddProperty("ConsolePause", "false");
|
||||
var exportDebugGroup = root.AddPropertyGroup();
|
||||
exportDebugGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportDebug|AnyCPU' ";
|
||||
exportDebugGroup.AddProperty("DebugSymbols", "true");
|
||||
exportDebugGroup.AddProperty("DebugType", "portable");
|
||||
exportDebugGroup.AddProperty("Optimize", "false");
|
||||
exportDebugGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;DEBUG;");
|
||||
exportDebugGroup.AddProperty("ErrorReport", "prompt");
|
||||
exportDebugGroup.AddProperty("WarningLevel", "4");
|
||||
exportDebugGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
var releaseGroup = root.AddPropertyGroup();
|
||||
releaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ";
|
||||
releaseGroup.AddProperty("DebugType", "portable");
|
||||
releaseGroup.AddProperty("Optimize", "true");
|
||||
releaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;");
|
||||
releaseGroup.AddProperty("ErrorReport", "prompt");
|
||||
releaseGroup.AddProperty("WarningLevel", "4");
|
||||
releaseGroup.AddProperty("ConsolePause", "false");
|
||||
var exportReleaseGroup = root.AddPropertyGroup();
|
||||
exportReleaseGroup.Condition = " '$(Configuration)|$(Platform)' == 'ExportRelease|AnyCPU' ";
|
||||
exportReleaseGroup.AddProperty("DebugType", "portable");
|
||||
exportReleaseGroup.AddProperty("Optimize", "true");
|
||||
exportReleaseGroup.AddProperty("DefineConstants", "$(GodotDefineConstants);GODOT;");
|
||||
exportReleaseGroup.AddProperty("ErrorReport", "prompt");
|
||||
exportReleaseGroup.AddProperty("WarningLevel", "4");
|
||||
exportReleaseGroup.AddProperty("ConsolePause", "false");
|
||||
|
||||
// References
|
||||
var referenceGroup = root.AddItemGroup();
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using DotNet.Globbing;
|
||||
using Microsoft.Build.Construction;
|
||||
|
||||
|
@ -117,6 +118,7 @@ namespace GodotTools.ProjectEditor
|
|||
globOptions.Evaluation.CaseInsensitive = false;
|
||||
|
||||
var root = ProjectRootElement.Open(projectPath);
|
||||
Debug.Assert(root != null);
|
||||
|
||||
foreach (var itemGroup in root.ItemGroups)
|
||||
{
|
||||
|
@ -158,35 +160,35 @@ namespace GodotTools.ProjectEditor
|
|||
void AddPropertyIfNotPresent(string name, string condition, string value)
|
||||
{
|
||||
if (root.PropertyGroups
|
||||
.Any(g => (g.Condition == string.Empty || g.Condition == condition) &&
|
||||
.Any(g => (g.Condition == string.Empty || g.Condition.Trim() == condition) &&
|
||||
g.Properties
|
||||
.Any(p => p.Name == name &&
|
||||
p.Value == value &&
|
||||
(p.Condition == condition || g.Condition == condition))))
|
||||
(p.Condition.Trim() == condition || g.Condition.Trim() == condition))))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
root.AddProperty(name, value).Condition = condition;
|
||||
root.AddProperty(name, value).Condition = " " + condition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
AddPropertyIfNotPresent(name: "ApiConfiguration",
|
||||
condition: " '$(Configuration)' != 'Release' ",
|
||||
condition: "'$(Configuration)' != 'ExportRelease'",
|
||||
value: "Debug");
|
||||
AddPropertyIfNotPresent(name: "ApiConfiguration",
|
||||
condition: " '$(Configuration)' == 'Release' ",
|
||||
condition: "'$(Configuration)' == 'ExportRelease'",
|
||||
value: "Release");
|
||||
|
||||
void SetReferenceHintPath(string referenceName, string condition, string hintPath)
|
||||
{
|
||||
foreach (var itemGroup in root.ItemGroups.Where(g =>
|
||||
g.Condition == string.Empty || g.Condition == condition))
|
||||
g.Condition.Trim() == string.Empty || g.Condition.Trim() == condition))
|
||||
{
|
||||
var references = itemGroup.Items.Where(item =>
|
||||
item.ItemType == "Reference" &&
|
||||
item.Include == referenceName &&
|
||||
(item.Condition == condition || itemGroup.Condition == condition));
|
||||
(item.Condition.Trim() == condition || itemGroup.Condition.Trim() == condition));
|
||||
|
||||
var referencesWithHintPath = references.Where(reference =>
|
||||
reference.Metadata.Any(m => m.Name == "HintPath"));
|
||||
|
@ -225,7 +227,7 @@ namespace GodotTools.ProjectEditor
|
|||
}
|
||||
|
||||
// Found no Reference item at all. Add it.
|
||||
root.AddItem("Reference", referenceName).Condition = condition;
|
||||
root.AddItem("Reference", referenceName).Condition = " " + condition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
|
@ -233,7 +235,7 @@ namespace GodotTools.ProjectEditor
|
|||
const string editorProjectName = "GodotSharpEditor";
|
||||
|
||||
const string coreCondition = "";
|
||||
const string editorCondition = " '$(Configuration)' == 'Tools' ";
|
||||
const string editorCondition = "'$(Configuration)' == 'Debug'";
|
||||
|
||||
var coreHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{coreProjectName}.dll";
|
||||
var editorHintPath = $"$(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/{editorProjectName}.dll";
|
||||
|
@ -241,6 +243,105 @@ namespace GodotTools.ProjectEditor
|
|||
SetReferenceHintPath(coreProjectName, coreCondition, coreHintPath);
|
||||
SetReferenceHintPath(editorProjectName, editorCondition, editorHintPath);
|
||||
|
||||
if (dirty)
|
||||
root.Save();
|
||||
}
|
||||
|
||||
public static void MigrateFromOldConfigNames(string projectPath)
|
||||
{
|
||||
var root = ProjectRootElement.Open(projectPath);
|
||||
Debug.Assert(root != null);
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
bool hasGodotProjectGeneratorVersion = false;
|
||||
bool foundOldConfiguration = false;
|
||||
|
||||
foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition == string.Empty))
|
||||
{
|
||||
if (!hasGodotProjectGeneratorVersion && propertyGroup.Properties.Any(p => p.Name == "GodotProjectGeneratorVersion"))
|
||||
hasGodotProjectGeneratorVersion = true;
|
||||
|
||||
foreach (var configItem in propertyGroup.Properties
|
||||
.Where(p => p.Condition.Trim() == "'$(Configuration)' == ''" && p.Value == "Tools"))
|
||||
{
|
||||
configItem.Value = "Debug";
|
||||
foundOldConfiguration = true;
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasGodotProjectGeneratorVersion)
|
||||
{
|
||||
root.PropertyGroups.First(g => g.Condition == string.Empty)?
|
||||
.AddProperty("GodotProjectGeneratorVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if (!foundOldConfiguration)
|
||||
{
|
||||
var toolsConditions = new[]
|
||||
{
|
||||
"'$(Configuration)|$(Platform)' == 'Tools|AnyCPU'",
|
||||
"'$(Configuration)|$(Platform)' != 'Tools|AnyCPU'",
|
||||
"'$(Configuration)' == 'Tools'",
|
||||
"'$(Configuration)' != 'Tools'"
|
||||
};
|
||||
|
||||
foundOldConfiguration = root.PropertyGroups
|
||||
.Any(g => toolsConditions.Any(c => c == g.Condition.Trim()));
|
||||
}
|
||||
|
||||
if (foundOldConfiguration)
|
||||
{
|
||||
void MigrateConfigurationConditions(string oldConfiguration, string newConfiguration)
|
||||
{
|
||||
void MigrateConditions(string oldCondition, string newCondition)
|
||||
{
|
||||
foreach (var propertyGroup in root.PropertyGroups.Where(g => g.Condition.Trim() == oldCondition))
|
||||
{
|
||||
propertyGroup.Condition = " " + newCondition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
foreach (var propertyGroup in root.PropertyGroups)
|
||||
{
|
||||
foreach (var prop in propertyGroup.Properties.Where(p => p.Condition.Trim() == oldCondition))
|
||||
{
|
||||
prop.Condition = " " + newCondition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var itemGroup in root.ItemGroups.Where(g => g.Condition.Trim() == oldCondition))
|
||||
{
|
||||
itemGroup.Condition = " " + newCondition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
foreach (var itemGroup in root.ItemGroups)
|
||||
{
|
||||
foreach (var item in itemGroup.Items.Where(item => item.Condition.Trim() == oldCondition))
|
||||
{
|
||||
item.Condition = " " + newCondition + " ";
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var op in new[] {"==", "!="})
|
||||
{
|
||||
MigrateConditions($"'$(Configuration)|$(Platform)' {op} '{oldConfiguration}|AnyCPU'", $"'$(Configuration)|$(Platform)' {op} '{newConfiguration}|AnyCPU'");
|
||||
MigrateConditions($"'$(Configuration)' {op} '{oldConfiguration}'", $"'$(Configuration)' {op} '{newConfiguration}'");
|
||||
}
|
||||
}
|
||||
|
||||
MigrateConfigurationConditions("Debug", "ExportDebug");
|
||||
MigrateConfigurationConditions("Release", "ExportRelease");
|
||||
MigrateConfigurationConditions("Tools", "Debug"); // Must be last
|
||||
}
|
||||
|
||||
|
||||
if (dirty)
|
||||
root.Save();
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace GodotTools
|
|||
Internal.GodotIs32Bits() ? "32" : "64"
|
||||
};
|
||||
|
||||
bool buildSuccess = BuildManager.BuildProjectBlocking("Tools", godotDefines);
|
||||
bool buildSuccess = BuildManager.BuildProjectBlocking("Debug", godotDefines);
|
||||
|
||||
if (!buildSuccess)
|
||||
return;
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace GodotTools
|
|||
// Make sure the API assemblies are up to date before building the project.
|
||||
// We may not have had the chance to update the release API assemblies, and the debug ones
|
||||
// may have been deleted by the user at some point after they were loaded by the Godot editor.
|
||||
string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "Release" ? "Release" : "Debug");
|
||||
string apiAssembliesUpdateError = Internal.UpdateApiAssembliesFromPrebuilt(config == "ExportRelease" ? "Release" : "Debug");
|
||||
|
||||
if (!string.IsNullOrEmpty(apiAssembliesUpdateError))
|
||||
{
|
||||
|
@ -242,7 +242,7 @@ namespace GodotTools
|
|||
Internal.GodotIs32Bits() ? "32" : "64"
|
||||
};
|
||||
|
||||
return BuildProjectBlocking("Tools", godotDefines);
|
||||
return BuildProjectBlocking("Debug", godotDefines);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
|
@ -251,12 +251,12 @@ namespace GodotTools
|
|||
var editorSettings = GodotSharpEditor.Instance.GetEditorInterface().GetEditorSettings();
|
||||
var msbuild = BuildTool.MsBuildMono;
|
||||
if (OS.IsWindows)
|
||||
msbuild = RiderPathManager.IsRider((string) editorSettings.GetSetting(RiderPathManager.EditorPathSettingName))
|
||||
msbuild = RiderPathManager.IsExternalEditorSetToRider(editorSettings)
|
||||
? BuildTool.JetBrainsMsBuild
|
||||
: BuildTool.MsBuildVs;
|
||||
|
||||
EditorDef("mono/builds/build_tool", msbuild);
|
||||
|
||||
|
||||
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
|
||||
{
|
||||
["type"] = Godot.Variant.Type.Int,
|
||||
|
|
|
@ -32,18 +32,6 @@ namespace GodotTools
|
|||
ProjectUtils.AddItemToProjectChecked(projectPath, itemType, include);
|
||||
}
|
||||
|
||||
public static void FixApiHintPath(string projectPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProjectUtils.FixApiHintPath(projectPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
private static ulong ConvertToTimestamp(this DateTime value)
|
||||
|
|
|
@ -150,7 +150,7 @@ namespace GodotTools.Export
|
|||
string outputDir = new FileInfo(path).Directory?.FullName ??
|
||||
throw new FileNotFoundException("Base directory not found");
|
||||
|
||||
string buildConfig = isDebug ? "Debug" : "Release";
|
||||
string buildConfig = isDebug ? "ExportDebug" : "ExportRelease";
|
||||
|
||||
string scriptsMetadataPath = Path.Combine(GodotSharpDirs.ResMetadataDir, $"scripts_metadata.{(isDebug ? "debug" : "release")}");
|
||||
CsProjOperations.GenerateScriptsMetadata(GodotSharpDirs.ProjectCsProjPath, scriptsMetadataPath);
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace GodotTools
|
|||
{
|
||||
Guid = guid,
|
||||
PathRelativeToSolution = name + ".csproj",
|
||||
Configs = new List<string> {"Debug", "Release", "Tools"}
|
||||
Configs = new List<string> { "Debug", "ExportDebug", "ExportRelease" }
|
||||
};
|
||||
|
||||
solution.AddNewProject(name, projectInfo);
|
||||
|
@ -437,8 +437,22 @@ namespace GodotTools
|
|||
|
||||
if (File.Exists(GodotSharpDirs.ProjectSlnPath) && File.Exists(GodotSharpDirs.ProjectCsProjPath))
|
||||
{
|
||||
// Make sure the existing project has Api assembly references configured correctly
|
||||
CsProjOperations.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
|
||||
try
|
||||
{
|
||||
// Migrate solution from old configuration names to: Debug, ExportDebug and ExportRelease
|
||||
DotNetSolution.MigrateFromOldConfigNames(GodotSharpDirs.ProjectSlnPath);
|
||||
// Migrate csproj from old configuration names to: Debug, ExportDebug and ExportRelease
|
||||
ProjectUtils.MigrateFromOldConfigNames(GodotSharpDirs.ProjectCsProjPath);
|
||||
|
||||
// Apply the other fixes after configurations are migrated
|
||||
|
||||
// Make sure the existing project has Api assembly references configured correctly
|
||||
ProjectUtils.FixApiHintPath(GodotSharpDirs.ProjectCsProjPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GD.PushError(e.ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -55,6 +55,11 @@ namespace GodotTools.Ides.Rider
|
|||
}
|
||||
}
|
||||
|
||||
public static bool IsExternalEditorSetToRider(EditorSettings editorSettings)
|
||||
{
|
||||
return editorSettings.HasSetting(EditorPathSettingName) && IsRider((string) editorSettings.GetSetting(EditorPathSettingName));
|
||||
}
|
||||
|
||||
public static bool IsRider(string path)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
|
|
|
@ -8,8 +8,6 @@ Global
|
|||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AEBF0036-DA76-4341-B651-A3F2856AB2FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
Import('env')
|
||||
Import('env_modules')
|
||||
|
||||
# Only kept to build the thirdparty library used by the theora and webm
|
||||
# modules.
|
||||
|
||||
env_ogg = env_modules.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OGG_REGISTER_TYPES_H
|
||||
#define OGG_REGISTER_TYPES_H
|
||||
|
||||
void register_ogg_types();
|
||||
void unregister_ogg_types();
|
||||
|
||||
#endif // OGG_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENSIMPLEX_REGISTER_TYPES_H
|
||||
#define OPENSIMPLEX_REGISTER_TYPES_H
|
||||
|
||||
void register_opensimplex_types();
|
||||
void unregister_opensimplex_types();
|
||||
|
||||
#endif // OPENSIMPLEX_REGISTER_TYPES_H
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
Import('env')
|
||||
Import('env_modules')
|
||||
|
||||
stub = True
|
||||
# Only kept to build the thirdparty library used by the webm module.
|
||||
# AudioStreamOpus was dropped in 3.0 due to incompatibility with the new audio
|
||||
# engine. If you want to port it, fetch it from the Git history.
|
||||
|
||||
env_opus = env_modules.Clone()
|
||||
|
||||
|
@ -235,9 +237,5 @@ if env['builtin_opus']:
|
|||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
|
||||
|
||||
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")
|
||||
# Module files
|
||||
env_opus.add_source_files(env.modules_sources, "register_types.cpp")
|
||||
|
|
|
@ -1,379 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_opus.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "audio_stream_opus.h"
|
||||
|
||||
/**
|
||||
@author George Marques <george@gmarqu.es>
|
||||
*/
|
||||
|
||||
const float AudioStreamPlaybackOpus::osrate = 48000.0f;
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) {
|
||||
FileAccess *fa = (FileAccess *)_stream;
|
||||
|
||||
if (fa->eof_reached())
|
||||
return 0;
|
||||
|
||||
uint8_t *dst = (uint8_t *)_ptr;
|
||||
|
||||
int read = fa->get_buffer(dst, _nbytes);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence) {
|
||||
|
||||
#ifdef SEEK_SET
|
||||
FileAccess *fa = (FileAccess *)_stream;
|
||||
|
||||
switch (_whence) {
|
||||
case SEEK_SET: {
|
||||
fa->seek(_offset);
|
||||
} break;
|
||||
case SEEK_CUR: {
|
||||
fa->seek(fa->get_position() + _offset);
|
||||
} break;
|
||||
case SEEK_END: {
|
||||
fa->seek_end(_offset);
|
||||
} break;
|
||||
default: {
|
||||
ERR_PRINT("Opus seek function failure: Unexpected value in _whence\n");
|
||||
}
|
||||
}
|
||||
int ret = fa->eof_reached() ? -1 : 0;
|
||||
return ret;
|
||||
#else
|
||||
return -1; // no seeking
|
||||
#endif
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::_op_close_func(void *_stream) {
|
||||
if (!_stream)
|
||||
return 0;
|
||||
FileAccess *fa = (FileAccess *)_stream;
|
||||
if (fa->is_open())
|
||||
fa->close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) {
|
||||
FileAccess *_fa = (FileAccess *)_stream;
|
||||
return (opus_int64)_fa->get_position();
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::_clear_stream() {
|
||||
if (!stream_loaded)
|
||||
return;
|
||||
|
||||
op_free(opus_file);
|
||||
_close_file();
|
||||
|
||||
stream_loaded = false;
|
||||
stream_channels = 1;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::_close_file() {
|
||||
if (f) {
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOpus::_load_stream() {
|
||||
|
||||
ERR_FAIL_COND_V(!stream_valid, ERR_UNCONFIGURED);
|
||||
|
||||
_clear_stream();
|
||||
if (file == "")
|
||||
return ERR_INVALID_DATA;
|
||||
|
||||
Error err;
|
||||
f = FileAccess::open(file, FileAccess::READ, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'.");
|
||||
|
||||
int _err = 0;
|
||||
|
||||
opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err);
|
||||
|
||||
switch (_err) {
|
||||
case OP_EREAD: { // - Can't read the file.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CANT_READ);
|
||||
} break;
|
||||
case OP_EVERSION: // - Unrecognized version number.
|
||||
case OP_ENOTFORMAT: // - Stream is not Opus data.
|
||||
case OP_EIMPL: { // - Stream used non-implemented feature.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
|
||||
} break;
|
||||
case OP_EBADLINK: // - Failed to find old data after seeking.
|
||||
case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
|
||||
case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CORRUPT);
|
||||
} break;
|
||||
case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_BUG);
|
||||
} break;
|
||||
}
|
||||
repeats = 0;
|
||||
stream_loaded = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() {
|
||||
loops = false;
|
||||
playing = false;
|
||||
f = NULL;
|
||||
stream_loaded = false;
|
||||
stream_valid = false;
|
||||
repeats = 0;
|
||||
paused = true;
|
||||
stream_channels = 0;
|
||||
current_section = 0;
|
||||
length = 0;
|
||||
loop_restart_time = 0;
|
||||
pre_skip = 0;
|
||||
|
||||
_op_callbacks.read = _op_read_func;
|
||||
_op_callbacks.seek = _op_seek_func;
|
||||
_op_callbacks.tell = _op_tell_func;
|
||||
_op_callbacks.close = _op_close_func;
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
|
||||
file = p_file;
|
||||
stream_valid = false;
|
||||
Error err;
|
||||
f = FileAccess::open(file, FileAccess::READ, &err);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + file + "'.");
|
||||
|
||||
int _err;
|
||||
|
||||
opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &_err);
|
||||
|
||||
switch (_err) {
|
||||
case OP_EREAD: { // - Can't read the file.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CANT_READ);
|
||||
} break;
|
||||
case OP_EVERSION: // - Unrecognized version number.
|
||||
case OP_ENOTFORMAT: // - Stream is not Opus data.
|
||||
case OP_EIMPL: { // - Stream used non-implemented feature.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
|
||||
} break;
|
||||
case OP_EBADLINK: // - Failed to find old data after seeking.
|
||||
case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
|
||||
case OP_EBADHEADER: { // - Invalid or missing Opus bitstream header.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CORRUPT);
|
||||
} break;
|
||||
case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_BUG);
|
||||
} break;
|
||||
}
|
||||
|
||||
const OpusHead *oinfo = op_head(opus_file, -1);
|
||||
|
||||
stream_channels = oinfo->channel_count;
|
||||
pre_skip = oinfo->pre_skip;
|
||||
frames_mixed = pre_skip;
|
||||
ogg_int64_t len = op_pcm_total(opus_file, -1);
|
||||
if (len < 0) {
|
||||
length = 0;
|
||||
} else {
|
||||
length = (len / osrate);
|
||||
}
|
||||
|
||||
op_free(opus_file);
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
stream_valid = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::play(float p_from) {
|
||||
if (playing)
|
||||
stop();
|
||||
|
||||
if (_load_stream() != OK)
|
||||
return;
|
||||
|
||||
frames_mixed = pre_skip;
|
||||
playing = true;
|
||||
if (p_from > 0) {
|
||||
seek(p_from);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::stop() {
|
||||
_clear_stream();
|
||||
playing = false;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOpus::seek(float p_time) {
|
||||
if (!playing) return;
|
||||
ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate);
|
||||
bool ok = op_pcm_seek(opus_file, pcm_offset) == 0;
|
||||
if (!ok) {
|
||||
ERR_PRINT("Seek time over stream size.");
|
||||
return;
|
||||
}
|
||||
frames_mixed = osrate * p_time;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::mix(int16_t *p_buffer, int p_frames) {
|
||||
if (!playing)
|
||||
return 0;
|
||||
|
||||
int total = p_frames;
|
||||
|
||||
while (true) {
|
||||
|
||||
int todo = p_frames;
|
||||
|
||||
if (todo < MIN_MIX) {
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = op_read(opus_file, (opus_int16 *)p_buffer, todo * stream_channels, ¤t_section);
|
||||
if (ret < 0) {
|
||||
playing = false;
|
||||
ERR_BREAK_MSG(ret < 0, "Error reading Opus file: " + file + ".");
|
||||
} else if (ret == 0) { // end of song, reload?
|
||||
op_free(opus_file);
|
||||
|
||||
_close_file();
|
||||
|
||||
f = FileAccess::open(file, FileAccess::READ);
|
||||
|
||||
int errv = 0;
|
||||
opus_file = op_open_callbacks(f, &_op_callbacks, NULL, 0, &errv);
|
||||
if (errv != 0) {
|
||||
playing = false;
|
||||
break; // :(
|
||||
}
|
||||
|
||||
if (!has_loop()) {
|
||||
playing = false;
|
||||
repeats = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (loop_restart_time) {
|
||||
bool ok = op_pcm_seek(opus_file, (loop_restart_time * osrate) + pre_skip) == 0;
|
||||
if (!ok) {
|
||||
playing = false;
|
||||
ERR_PRINT("Loop restart time rejected");
|
||||
}
|
||||
|
||||
frames_mixed = (loop_restart_time * osrate) + pre_skip;
|
||||
} else {
|
||||
frames_mixed = pre_skip;
|
||||
}
|
||||
repeats++;
|
||||
continue;
|
||||
}
|
||||
|
||||
stream_channels = op_head(opus_file, current_section)->channel_count;
|
||||
|
||||
frames_mixed += ret;
|
||||
|
||||
p_buffer += ret * stream_channels;
|
||||
p_frames -= ret;
|
||||
}
|
||||
|
||||
return total - p_frames;
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOpus::get_length() const {
|
||||
if (!stream_loaded) {
|
||||
if (const_cast<AudioStreamPlaybackOpus *>(this)->_load_stream() != OK)
|
||||
return 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOpus::get_playback_position() const {
|
||||
|
||||
int32_t frames = int32_t(frames_mixed);
|
||||
if (frames < 0)
|
||||
frames = 0;
|
||||
return double(frames) / osrate;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOpus::get_minimum_buffer_size() const {
|
||||
return MIN_MIX;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() {
|
||||
_clear_stream();
|
||||
}
|
||||
|
||||
RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String &p_original_path, Error *r_error) {
|
||||
if (r_error)
|
||||
*r_error = OK;
|
||||
|
||||
AudioStreamOpus *opus_stream = memnew(AudioStreamOpus);
|
||||
opus_stream->set_file(p_path);
|
||||
return Ref<AudioStreamOpus>(opus_stream);
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
||||
p_extensions->push_back("opus");
|
||||
}
|
||||
String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const {
|
||||
|
||||
if (p_path.get_extension().to_lower() == "opus")
|
||||
return "AudioStreamOpus";
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String &p_type) const {
|
||||
return (p_type == "AudioStream" || p_type == "AudioStreamOpus");
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_opus.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef AUDIO_STREAM_OPUS_H
|
||||
#define AUDIO_STREAM_OPUS_H
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "scene/resources/audio_stream.h"
|
||||
|
||||
#include <opus/opusfile.h>
|
||||
|
||||
/**
|
||||
@author George Marques <george@gmarqu.es>
|
||||
*/
|
||||
|
||||
class AudioStreamPlaybackOpus : public AudioStreamPlayback {
|
||||
|
||||
GDCLASS(AudioStreamPlaybackOpus, AudioStreamPlayback);
|
||||
|
||||
enum {
|
||||
MIN_MIX = 1024
|
||||
};
|
||||
|
||||
FileAccess *f;
|
||||
|
||||
OpusFileCallbacks _op_callbacks;
|
||||
float length;
|
||||
static int _op_read_func(void *_stream, unsigned char *_ptr, int _nbytes);
|
||||
static int _op_seek_func(void *_stream, opus_int64 _offset, int _whence);
|
||||
static int _op_close_func(void *_stream);
|
||||
static opus_int64 _op_tell_func(void *_stream);
|
||||
static const float osrate;
|
||||
|
||||
String file;
|
||||
int64_t frames_mixed;
|
||||
|
||||
bool stream_loaded;
|
||||
volatile bool playing;
|
||||
OggOpusFile *opus_file;
|
||||
int stream_channels;
|
||||
int current_section;
|
||||
int pre_skip;
|
||||
|
||||
bool paused;
|
||||
bool loops;
|
||||
int repeats;
|
||||
|
||||
Error _load_stream();
|
||||
void _clear_stream();
|
||||
void _close_file();
|
||||
|
||||
bool stream_valid;
|
||||
float loop_restart_time;
|
||||
|
||||
public:
|
||||
Error set_file(const String &p_file);
|
||||
|
||||
virtual void play(float p_from = 0);
|
||||
virtual void stop();
|
||||
virtual bool is_playing() const { return playing; }
|
||||
|
||||
virtual void set_loop_restart_time(float p_time) { loop_restart_time = p_time; }
|
||||
|
||||
virtual void set_paused(bool p_paused) { paused = p_paused; }
|
||||
virtual bool is_paused() const { return paused; }
|
||||
|
||||
virtual void set_loop(bool p_enable) { loops = p_enable; }
|
||||
virtual bool has_loop() const { return loops; }
|
||||
|
||||
virtual float get_length() const;
|
||||
|
||||
virtual String get_stream_name() const { return ""; }
|
||||
|
||||
virtual int get_loop_count() const { return repeats; }
|
||||
|
||||
virtual float get_playback_position() const;
|
||||
virtual void seek(float p_time);
|
||||
|
||||
virtual int get_channels() const { return stream_channels; }
|
||||
virtual int get_mix_rate() const { return osrate; }
|
||||
|
||||
virtual int get_minimum_buffer_size() const;
|
||||
|
||||
virtual int mix(int16_t *p_buffer, int p_frames);
|
||||
|
||||
AudioStreamPlaybackOpus();
|
||||
~AudioStreamPlaybackOpus();
|
||||
};
|
||||
|
||||
class AudioStreamOpus : public AudioStream {
|
||||
|
||||
GDCLASS(AudioStreamOpus, AudioStream);
|
||||
|
||||
String file;
|
||||
|
||||
public:
|
||||
Ref<AudioStreamPlayback> instance_playback() {
|
||||
Ref<AudioStreamPlaybackOpus> pb = memnew(AudioStreamPlaybackOpus);
|
||||
pb->set_file(file);
|
||||
return pb;
|
||||
}
|
||||
|
||||
void set_file(const String &p_file) { file = p_file; }
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderAudioStreamOpus : 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 // AUDIO_STREAM_OPUS_H
|
|
@ -3,11 +3,3 @@ def can_build(env, platform):
|
|||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"AudioStreamOpus",
|
||||
]
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
||||
|
|
|
@ -30,23 +30,8 @@
|
|||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "audio_stream_opus.h"
|
||||
// Dummy module as libvorbis is needed by other modules (theora ...)
|
||||
|
||||
static Ref<ResourceFormatLoaderAudioStreamOpus> opus_stream_loader;
|
||||
void register_opus_types() {}
|
||||
|
||||
void register_opus_types() {
|
||||
// Sorry guys, do not enable this unless you can figure out a way
|
||||
// to get Opus to not do any memory allocation or system calls
|
||||
// in the audio thread.
|
||||
// Currently the implementation even reads files from the audio thread,
|
||||
// and this is not how audio programming works.
|
||||
|
||||
//opus_stream_loader = memnew(ResourceFormatLoaderAudioStreamOpus);
|
||||
//ResourceLoader::add_resource_format_loader(opus_stream_loader);
|
||||
//ClassDB::register_class<AudioStreamOpus>();
|
||||
}
|
||||
|
||||
void unregister_opus_types() {
|
||||
|
||||
//memdelete(opus_stream_loader);
|
||||
}
|
||||
void unregister_opus_types() {}
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPUS_REGISTER_TYPES_H
|
||||
#define OPUS_REGISTER_TYPES_H
|
||||
|
||||
void register_opus_types();
|
||||
void unregister_opus_types();
|
||||
|
||||
#endif // OPUS_REGISTER_TYPES_H
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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() {}
|
|
@ -1,32 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 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();
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef PVR_REGISTER_TYPES_H
|
||||
#define PVR_REGISTER_TYPES_H
|
||||
|
||||
void register_pvr_types();
|
||||
void unregister_pvr_types();
|
||||
|
||||
#endif // PVR_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef RECAST_REGISTER_TYPES_H
|
||||
#define RECAST_REGISTER_TYPES_H
|
||||
|
||||
void register_recast_types();
|
||||
void unregister_recast_types();
|
||||
|
||||
#endif // RECAST_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef REGEX_REGISTER_TYPES_H
|
||||
#define REGEX_REGISTER_TYPES_H
|
||||
|
||||
void register_regex_types();
|
||||
void unregister_regex_types();
|
||||
|
||||
#endif // REGEX_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef SQUISH_REGISTER_TYPES_H
|
||||
#define SQUISH_REGISTER_TYPES_H
|
||||
|
||||
void register_squish_types();
|
||||
void unregister_squish_types();
|
||||
|
||||
#endif // SQUISH_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef STB_VORBIS_REGISTER_TYPES_H
|
||||
#define STB_VORBIS_REGISTER_TYPES_H
|
||||
|
||||
void register_stb_vorbis_types();
|
||||
void unregister_stb_vorbis_types();
|
||||
|
||||
#endif // STB_VORBIS_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef SVG_REGISTER_TYPES_H
|
||||
#define SVG_REGISTER_TYPES_H
|
||||
|
||||
void register_svg_types();
|
||||
void unregister_svg_types();
|
||||
|
||||
#endif // SVG_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef TGA_REGISTER_TYPES_H
|
||||
#define TGA_REGISTER_TYPES_H
|
||||
|
||||
void register_tga_types();
|
||||
void unregister_tga_types();
|
||||
|
||||
#endif // TGA_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef THEORA_REGISTER_TYPES_H
|
||||
#define THEORA_REGISTER_TYPES_H
|
||||
|
||||
void register_theora_types();
|
||||
void unregister_theora_types();
|
||||
|
||||
#endif // THEORA_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef TINYEXR_REGISTER_TYPES_H
|
||||
#define TINYEXR_REGISTER_TYPES_H
|
||||
|
||||
void register_tinyexr_types();
|
||||
void unregister_tinyexr_types();
|
||||
|
||||
#endif // TINYEXR_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef UPNP_REGISTER_TYPES_H
|
||||
#define UPNP_REGISTER_TYPES_H
|
||||
|
||||
void register_upnp_types();
|
||||
void unregister_upnp_types();
|
||||
|
||||
#endif // UPNP_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef VHACD_REGISTER_TYPES_H
|
||||
#define VHACD_REGISTER_TYPES_H
|
||||
|
||||
void register_vhacd_types();
|
||||
void unregister_vhacd_types();
|
||||
|
||||
#endif // VHACD_REGISTER_TYPES_H
|
||||
|
|
|
@ -28,5 +28,10 @@
|
|||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
|
||||
#define VISUAL_SCRIPT_REGISTER_TYPES_H
|
||||
|
||||
void register_visual_script_types();
|
||||
void unregister_visual_script_types();
|
||||
|
||||
#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
Import('env')
|
||||
Import('env_modules')
|
||||
|
||||
# Only kept to build the thirdparty library used by the theora and webm
|
||||
# modules. We now use stb_vorbis for AudioStreamOGGVorbis.
|
||||
|
||||
env_vorbis = env_modules.Clone()
|
||||
|
||||
stub = True
|
||||
|
@ -50,9 +53,5 @@ if env['builtin_libvorbis']:
|
|||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
|
||||
|
||||
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")
|
||||
# Module files
|
||||
env_vorbis.add_source_files(env.modules_sources, "register_types.cpp")
|
||||
|
|
|
@ -1,406 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_ogg_vorbis.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "audio_stream_ogg_vorbis.h"
|
||||
|
||||
size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst, size_t p_data, size_t p_count, void *_f) {
|
||||
|
||||
//printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f);
|
||||
FileAccess *fa = (FileAccess *)_f;
|
||||
size_t read_total = p_data * p_count;
|
||||
|
||||
if (fa->eof_reached())
|
||||
return 0;
|
||||
|
||||
uint8_t *dst = (uint8_t *)p_dst;
|
||||
|
||||
int read = fa->get_buffer(dst, read_total);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f, ogg_int64_t offs, int whence) {
|
||||
|
||||
//printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence);
|
||||
|
||||
#ifdef SEEK_SET
|
||||
//printf("seek set defined\n");
|
||||
FileAccess *fa = (FileAccess *)_f;
|
||||
|
||||
if (whence == SEEK_SET) {
|
||||
|
||||
fa->seek(offs);
|
||||
} else if (whence == SEEK_CUR) {
|
||||
|
||||
fa->seek(fa->get_position() + offs);
|
||||
} else if (whence == SEEK_END) {
|
||||
|
||||
fa->seek_end(offs);
|
||||
} else {
|
||||
|
||||
ERR_PRINT("Vorbis seek function failure: Unexpected value in _whence\n");
|
||||
}
|
||||
int ret = fa->eof_reached() ? -1 : 0;
|
||||
//printf("returning %i\n",ret);
|
||||
return ret;
|
||||
|
||||
#else
|
||||
return -1; // no seeking
|
||||
#endif
|
||||
}
|
||||
int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) {
|
||||
|
||||
//printf("close %p\n",_f);
|
||||
if (!_f)
|
||||
return 0;
|
||||
FileAccess *fa = (FileAccess *)_f;
|
||||
if (fa->is_open())
|
||||
fa->close();
|
||||
return 0;
|
||||
}
|
||||
long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
|
||||
|
||||
//printf("close %p\n",_f);
|
||||
|
||||
FileAccess *fa = (FileAccess *)_f;
|
||||
return fa->get_position();
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOGGVorbis::mix(int16_t *p_buffer, int p_frames) {
|
||||
|
||||
if (!playing)
|
||||
return 0;
|
||||
|
||||
int total = p_frames;
|
||||
while (true) {
|
||||
|
||||
int todo = p_frames;
|
||||
|
||||
if (todo < MIN_MIX) {
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef BIG_ENDIAN_ENABLED
|
||||
long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 1, 2, 1, ¤t_section);
|
||||
#else
|
||||
long ret = ov_read(&vf, (char *)p_buffer, todo * stream_channels * sizeof(int16_t), 0, 2, 1, ¤t_section);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
|
||||
playing = false;
|
||||
ERR_BREAK_MSG(ret < 0, "Error reading OGG Vorbis file: " + file + ".");
|
||||
} else if (ret == 0) { // end of song, reload?
|
||||
|
||||
ov_clear(&vf);
|
||||
|
||||
_close_file();
|
||||
|
||||
if (!has_loop()) {
|
||||
|
||||
playing = false;
|
||||
repeats = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
f = FileAccess::open(file, FileAccess::READ);
|
||||
|
||||
int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
|
||||
if (errv != 0) {
|
||||
playing = false;
|
||||
break; // :(
|
||||
}
|
||||
|
||||
if (loop_restart_time) {
|
||||
bool ok = ov_time_seek(&vf, loop_restart_time) == 0;
|
||||
if (!ok) {
|
||||
playing = false;
|
||||
ERR_PRINT("Loop restart time rejected");
|
||||
}
|
||||
|
||||
frames_mixed = stream_srate * loop_restart_time;
|
||||
} else {
|
||||
|
||||
frames_mixed = 0;
|
||||
}
|
||||
repeats++;
|
||||
continue;
|
||||
}
|
||||
|
||||
ret /= stream_channels;
|
||||
ret /= sizeof(int16_t);
|
||||
|
||||
frames_mixed += ret;
|
||||
|
||||
p_buffer += ret * stream_channels;
|
||||
p_frames -= ret;
|
||||
}
|
||||
|
||||
return total - p_frames;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::play(float p_from) {
|
||||
|
||||
if (playing)
|
||||
stop();
|
||||
|
||||
if (_load_stream() != OK)
|
||||
return;
|
||||
|
||||
frames_mixed = 0;
|
||||
playing = true;
|
||||
if (p_from > 0) {
|
||||
seek(p_from);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::_close_file() {
|
||||
|
||||
if (f) {
|
||||
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool AudioStreamPlaybackOGGVorbis::is_playing() const {
|
||||
return playing;
|
||||
}
|
||||
void AudioStreamPlaybackOGGVorbis::stop() {
|
||||
|
||||
_clear_stream();
|
||||
playing = false;
|
||||
//_clear();
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
|
||||
|
||||
int32_t frames = int32_t(frames_mixed);
|
||||
if (frames < 0)
|
||||
frames = 0;
|
||||
return double(frames) / stream_srate;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
|
||||
|
||||
if (!playing)
|
||||
return;
|
||||
bool ok = ov_time_seek(&vf, p_time) == 0;
|
||||
ERR_FAIL_COND(!ok);
|
||||
frames_mixed = stream_srate * p_time;
|
||||
}
|
||||
|
||||
String AudioStreamPlaybackOGGVorbis::get_stream_name() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) {
|
||||
|
||||
loops = p_enable;
|
||||
}
|
||||
|
||||
bool AudioStreamPlaybackOGGVorbis::has_loop() const {
|
||||
|
||||
return loops;
|
||||
}
|
||||
|
||||
int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
|
||||
return repeats;
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOGGVorbis::set_file(const String &p_file) {
|
||||
|
||||
file = p_file;
|
||||
stream_valid = false;
|
||||
Error err;
|
||||
f = FileAccess::open(file, FileAccess::READ, &err);
|
||||
ERR_FAIL_COND_V_MSG(err, err, "Cannot open file '" + p_file + "'.");
|
||||
|
||||
int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
|
||||
switch (errv) {
|
||||
|
||||
case OV_EREAD: { // - A read from media returned an error.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CANT_READ);
|
||||
} break;
|
||||
case OV_EVERSION: // - Vorbis version mismatch.
|
||||
case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
|
||||
} break;
|
||||
case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CORRUPT);
|
||||
} break;
|
||||
case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_BUG);
|
||||
} break;
|
||||
}
|
||||
const vorbis_info *vinfo = ov_info(&vf, -1);
|
||||
stream_channels = vinfo->channels;
|
||||
stream_srate = vinfo->rate;
|
||||
length = ov_time_total(&vf, -1);
|
||||
ov_clear(&vf);
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
stream_valid = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error AudioStreamPlaybackOGGVorbis::_load_stream() {
|
||||
|
||||
ERR_FAIL_COND_V(!stream_valid, ERR_UNCONFIGURED);
|
||||
|
||||
_clear_stream();
|
||||
if (file == "")
|
||||
return ERR_INVALID_DATA;
|
||||
|
||||
Error err;
|
||||
f = FileAccess::open(file, FileAccess::READ, &err);
|
||||
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + file + "'.");
|
||||
|
||||
int errv = ov_open_callbacks(f, &vf, NULL, 0, _ov_callbacks);
|
||||
switch (errv) {
|
||||
|
||||
case OV_EREAD: { // - A read from media returned an error.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CANT_READ);
|
||||
} break;
|
||||
case OV_EVERSION: // - Vorbis version mismatch.
|
||||
case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
|
||||
} break;
|
||||
case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_FILE_CORRUPT);
|
||||
} break;
|
||||
case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
|
||||
memdelete(f);
|
||||
f = NULL;
|
||||
ERR_FAIL_V(ERR_BUG);
|
||||
} break;
|
||||
}
|
||||
repeats = 0;
|
||||
stream_loaded = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
float AudioStreamPlaybackOGGVorbis::get_length() const {
|
||||
|
||||
if (!stream_loaded) {
|
||||
if (const_cast<AudioStreamPlaybackOGGVorbis *>(this)->_load_stream() != OK)
|
||||
return 0;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::_clear_stream() {
|
||||
|
||||
if (!stream_loaded)
|
||||
return;
|
||||
|
||||
ov_clear(&vf);
|
||||
_close_file();
|
||||
|
||||
stream_loaded = false;
|
||||
//stream_channels=1;
|
||||
playing = false;
|
||||
}
|
||||
|
||||
void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) {
|
||||
|
||||
paused = p_paused;
|
||||
}
|
||||
|
||||
bool AudioStreamPlaybackOGGVorbis::is_paused() const {
|
||||
|
||||
return paused;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() {
|
||||
|
||||
loops = false;
|
||||
playing = false;
|
||||
_ov_callbacks.read_func = _ov_read_func;
|
||||
_ov_callbacks.seek_func = _ov_seek_func;
|
||||
_ov_callbacks.close_func = _ov_close_func;
|
||||
_ov_callbacks.tell_func = _ov_tell_func;
|
||||
f = NULL;
|
||||
stream_loaded = false;
|
||||
stream_valid = false;
|
||||
repeats = 0;
|
||||
paused = true;
|
||||
stream_channels = 0;
|
||||
stream_srate = 0;
|
||||
current_section = 0;
|
||||
length = 0;
|
||||
loop_restart_time = 0;
|
||||
}
|
||||
|
||||
AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
|
||||
|
||||
_clear_stream();
|
||||
}
|
||||
|
||||
RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String &p_original_path, Error *r_error) {
|
||||
if (r_error)
|
||||
*r_error = OK;
|
||||
|
||||
AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis);
|
||||
ogg_stream->set_file(p_path);
|
||||
return Ref<AudioStreamOGGVorbis>(ogg_stream);
|
||||
}
|
||||
|
||||
void ResourceFormatLoaderAudioStreamOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
||||
p_extensions->push_back("ogg");
|
||||
}
|
||||
String ResourceFormatLoaderAudioStreamOGGVorbis::get_resource_type(const String &p_path) const {
|
||||
|
||||
if (p_path.get_extension().to_lower() == "ogg")
|
||||
return "AudioStreamOGGVorbis";
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ResourceFormatLoaderAudioStreamOGGVorbis::handles_type(const String &p_type) const {
|
||||
return (p_type == "AudioStream" || p_type == "AudioStreamOGG" || p_type == "AudioStreamOGGVorbis");
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
/*************************************************************************/
|
||||
/* audio_stream_ogg_vorbis.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef AUDIO_STREAM_OGG_VORBIS_H
|
||||
#define AUDIO_STREAM_OGG_VORBIS_H
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/os/thread_safe.h"
|
||||
#include "scene/resources/audio_stream.h"
|
||||
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback {
|
||||
|
||||
GDCLASS(AudioStreamPlaybackOGGVorbis, AudioStreamPlayback);
|
||||
|
||||
enum {
|
||||
MIN_MIX = 1024
|
||||
};
|
||||
|
||||
FileAccess *f;
|
||||
|
||||
ov_callbacks _ov_callbacks;
|
||||
float length;
|
||||
static size_t _ov_read_func(void *p_dst, size_t p_data, size_t p_count, void *_f);
|
||||
static int _ov_seek_func(void *_f, ogg_int64_t offs, int whence);
|
||||
static int _ov_close_func(void *_f);
|
||||
static long _ov_tell_func(void *_f);
|
||||
|
||||
String file;
|
||||
int64_t frames_mixed;
|
||||
|
||||
bool stream_loaded;
|
||||
volatile bool playing;
|
||||
OggVorbis_File vf;
|
||||
int stream_channels;
|
||||
int stream_srate;
|
||||
int current_section;
|
||||
|
||||
bool paused;
|
||||
bool loops;
|
||||
int repeats;
|
||||
|
||||
Error _load_stream();
|
||||
void _clear_stream();
|
||||
void _close_file();
|
||||
|
||||
bool stream_valid;
|
||||
float loop_restart_time;
|
||||
|
||||
public:
|
||||
Error set_file(const String &p_file);
|
||||
|
||||
virtual void play(float p_from = 0);
|
||||
virtual void stop();
|
||||
virtual bool is_playing() const;
|
||||
|
||||
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() const;
|
||||
|
||||
virtual void set_loop(bool p_enable);
|
||||
virtual bool has_loop() const;
|
||||
|
||||
virtual float get_length() const;
|
||||
|
||||
virtual String get_stream_name() const;
|
||||
|
||||
virtual int get_loop_count() const;
|
||||
|
||||
virtual float get_playback_position() const;
|
||||
virtual void seek(float p_time);
|
||||
|
||||
virtual int get_channels() const { return stream_channels; }
|
||||
virtual int get_mix_rate() const { return stream_srate; }
|
||||
|
||||
virtual int get_minimum_buffer_size() const { return 0; }
|
||||
virtual int mix(int16_t *p_buffer, int p_frames);
|
||||
|
||||
AudioStreamPlaybackOGGVorbis();
|
||||
~AudioStreamPlaybackOGGVorbis();
|
||||
};
|
||||
|
||||
class AudioStreamOGGVorbis : public AudioStream {
|
||||
|
||||
GDCLASS(AudioStreamOGGVorbis, AudioStream);
|
||||
|
||||
String file;
|
||||
|
||||
public:
|
||||
Ref<AudioStreamPlayback> instance_playback() {
|
||||
Ref<AudioStreamPlaybackOGGVorbis> pb = memnew(AudioStreamPlaybackOGGVorbis);
|
||||
pb->set_file(file);
|
||||
return pb;
|
||||
}
|
||||
|
||||
void set_file(const String &p_file) { file = p_file; }
|
||||
};
|
||||
|
||||
class ResourceFormatLoaderAudioStreamOGGVorbis : 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 // AUDIO_STREAM_OGG_H
|
|
@ -30,19 +30,8 @@
|
|||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "audio_stream_ogg_vorbis.h"
|
||||
// Dummy module as libvorbis is needed by other modules (theora ...)
|
||||
|
||||
static Ref<ResourceFormatLoaderAudioStreamOGGVorbis> vorbis_stream_loader;
|
||||
void register_vorbis_types() {}
|
||||
|
||||
void register_vorbis_types() {
|
||||
|
||||
vorbis_stream_loader.instance();
|
||||
ResourceLoader::add_resource_format_loader(vorbis_stream_loader);
|
||||
ClassDB::register_class<AudioStreamOGGVorbis>();
|
||||
}
|
||||
|
||||
void unregister_vorbis_types() {
|
||||
|
||||
ResourceLoader::remove_resource_format_loader(vorbis_stream_loader);
|
||||
vorbis_stream_loader.unref();
|
||||
}
|
||||
void unregister_vorbis_types() {}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue