summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/assimp/SCsub95
-rw-r--r--modules/assimp/config.py5
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp2181
-rw-r--r--modules/assimp/editor_scene_importer_assimp.h206
-rw-r--r--modules/assimp/godot_update_assimp.sh261
-rw-r--r--modules/assimp/register_types.cpp53
-rw-r--r--modules/assimp/register_types.h32
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml2
-rw-r--r--modules/bullet/doc_classes/BulletPhysicsServer.xml2
-rw-r--r--modules/bullet/shape_bullet.cpp9
-rw-r--r--modules/csg/csg_shape.cpp8
-rw-r--r--modules/csg/doc_classes/CSGBox.xml2
-rw-r--r--modules/csg/doc_classes/CSGCombiner.xml2
-rw-r--r--modules/csg/doc_classes/CSGCylinder.xml2
-rw-r--r--modules/csg/doc_classes/CSGMesh.xml2
-rw-r--r--modules/csg/doc_classes/CSGPolygon.xml2
-rw-r--r--modules/csg/doc_classes/CSGPrimitive.xml2
-rw-r--r--modules/csg/doc_classes/CSGShape.xml2
-rw-r--r--modules/csg/doc_classes/CSGSphere.xml2
-rw-r--r--modules/csg/doc_classes/CSGTorus.xml2
-rw-r--r--modules/enet/doc_classes/NetworkedMultiplayerENet.xml2
-rw-r--r--modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml2
-rw-r--r--modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml2
-rw-r--r--modules/gdnative/doc_classes/PacketPeerGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/PluginScript.xml2
-rw-r--r--modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/StreamPeerGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/VideoStreamGDNative.xml2
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp4
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScriptFunctionState.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScriptNativeClass.xml2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp190
-rw-r--r--modules/gdscript/gdscript_compiler.h9
-rw-r--r--modules/gdscript/gdscript_functions.cpp57
-rw-r--r--modules/gdscript/gdscript_parser.cpp24
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp10
-rw-r--r--modules/gridmap/doc_classes/GridMap.xml2
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml2
-rw-r--r--modules/mono/csharp_script.cpp6
-rw-r--r--modules/mono/doc_classes/@C#.xml2
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml2
-rw-r--r--modules/mono/editor/bindings_generator.cpp117
-rw-r--r--modules/mono/editor/bindings_generator.h11
-rw-r--r--modules/mono/glue/Managed/Files/DynamicObject.cs213
-rw-r--r--modules/mono/glue/Managed/Files/GD.cs16
-rw-r--r--modules/mono/glue/Managed/Files/Object.base.cs28
-rw-r--r--modules/mono/glue/arguments_vector.h68
-rw-r--r--modules/mono/glue/base_object_glue.cpp69
-rw-r--r--modules/mono/glue/base_object_glue.h12
-rw-r--r--modules/mono/glue/collections_glue.cpp16
-rw-r--r--modules/mono/glue/collections_glue.h16
-rw-r--r--modules/mono/glue/gd_glue.cpp12
-rw-r--r--modules/mono/glue/gd_glue.h6
-rw-r--r--modules/mono/glue/glue_header.h2
-rw-r--r--modules/mono/mono_reg_utils.py14
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp6
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml2
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml2
-rw-r--r--modules/opus/SCsub11
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml2
-rw-r--r--modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml2
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp37
-rw-r--r--modules/upnp/doc_classes/UPNP.xml2
-rw-r--r--modules/upnp/doc_classes/UPNPDevice.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptClassConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComment.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCondition.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstructor.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptDeconstruct.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEditor.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEmitSignal.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptExpression.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionCall.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionState.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIterator.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptMathConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptOperator.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPreload.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptResourcePath.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptReturn.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneTree.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelect.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelf.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSequence.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSubCall.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSwitch.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableSet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptWhile.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYield.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml2
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp43
-rw-r--r--modules/webm/doc_classes/VideoStreamWebm.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml2
-rw-r--r--modules/websocket/packet_buffer.h2
124 files changed, 3691 insertions, 336 deletions
diff --git a/modules/assimp/SCsub b/modules/assimp/SCsub
new file mode 100644
index 0000000000..61a357809a
--- /dev/null
+++ b/modules/assimp/SCsub
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+
+Import('env')
+Import('env_modules')
+
+env_assimp = env_modules.Clone()
+env_assimp.Append(CPPPATH=['#thirdparty/assimp'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/include'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/code/Importer/IFC'])
+env_assimp.Append(CPPPATH=['#thirdparty/misc'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/code'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/contrib/irrXML/'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/contrib/unzip/'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/code/Importer/STEPParser'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/'])
+env_assimp.Append(CPPPATH=['#thirdparty/zlib/'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/contrib/openddlparser/include'])
+env_assimp.Append(CPPPATH=['#thirdparty/assimp/contrib/rapidjson/include'])
+env_assimp.Append(CPPPATH=['.'])
+#env_assimp.Append(CPPFLAGS=['-DASSIMP_DOUBLE_PRECISION']) # TODO default to what godot is compiled with for future double support
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_BOOST_WORKAROUND'])
+env_assimp.Append(CPPFLAGS=['-DOPENDDLPARSER_BUILD'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OWN_ZLIB'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_EXPORT'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_X_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_AMF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3DS_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD3_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD5_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MDL_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD2_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_PLY_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_ASE_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OBJ_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_HMP_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_SMD_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MDC_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MD5_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_STL_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_LWO_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_DXF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_NFF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_RAW_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_SIB_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OFF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_AC_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_BVH_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IRRMESH_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IRR_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_Q3D_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_B3D_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_COLLADA_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_TERRAGEN_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_CSM_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3D_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_LWS_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OGRE_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_OPENGEX_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_MS3D_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_COB_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_BLEND_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_Q3BSP_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_NDO_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_STEP_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_IFC_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_XGL_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_ASSBIN_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_GLTF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_C4D_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_3MF_IMPORTER'])
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_NO_X3D_IMPORTER'])
+
+env_assimp.Append(CPPFLAGS=['-DASSIMP_BUILD_SINGLETHREADED'])
+
+if (not env.msvc):
+ env_assimp.Append(CXXFLAGS=['-std=c++11'])
+elif (env.msvc == False and env['platform'] == 'windows'):
+ env_assimp.Append(LDFLAGS=['-pthread'])
+
+if(env['platform'] == 'windows'):
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM_WINDOWS'])
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM=WINDOWS'])
+elif(env['platform'] == 'x11'):
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM_LINUX'])
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM=LINUX'])
+elif(env['platform'] == 'osx'):
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM_DARWIN'])
+ env_assimp.Append(CPPFLAGS=['-DPLATFORM=DARWIN'])
+
+env_thirdparty = env_assimp.Clone()
+env_thirdparty.disable_warnings()
+env_thirdparty.add_source_files(env.modules_sources, Glob('#thirdparty/assimp/code/*.cpp'))
+
+# Godot's own source files
+env_assimp.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/assimp/config.py b/modules/assimp/config.py
new file mode 100644
index 0000000000..098f1eafa9
--- /dev/null
+++ b/modules/assimp/config.py
@@ -0,0 +1,5 @@
+def can_build(env, platform):
+ return env['tools']
+
+def configure(env):
+ pass
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
new file mode 100644
index 0000000000..4662cf9d0a
--- /dev/null
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -0,0 +1,2181 @@
+/*************************************************************************/
+/* editor_scene_importer_assimp.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 "assimp/DefaultLogger.hpp"
+#include "assimp/Importer.hpp"
+#include "assimp/LogStream.hpp"
+#include "assimp/Logger.hpp"
+#include "assimp/SceneCombiner.h"
+#include "assimp/cexport.h"
+#include "assimp/cimport.h"
+#include "assimp/matrix4x4.h"
+#include "assimp/pbrmaterial.h"
+#include "assimp/postprocess.h"
+#include "assimp/scene.h"
+
+#include "core/bind/core_bind.h"
+#include "core/io/image_loader.h"
+#include "editor/editor_file_system.h"
+#include "editor/import/resource_importer_scene.h"
+#include "editor_scene_importer_assimp.h"
+#include "editor_settings.h"
+#include "scene/3d/camera.h"
+#include "scene/3d/light.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/animation/animation_player.h"
+#include "scene/main/node.h"
+#include "scene/resources/material.h"
+#include "scene/resources/surface_tool.h"
+#include "zutil.h"
+#include <string>
+
+void EditorSceneImporterAssimp::get_extensions(List<String> *r_extensions) const {
+
+ const String import_setting_string = "filesystem/import/open_asset_import/";
+
+ Map<String, ImportFormat> import_format;
+ {
+ Vector<String> exts;
+ exts.push_back("fbx");
+ ImportFormat import = { exts, true };
+ import_format.insert("fbx", import);
+ }
+ {
+ Vector<String> exts;
+ exts.push_back("pmx");
+ ImportFormat import = { exts, true };
+ import_format.insert("mmd", import);
+ }
+ for (Map<String, ImportFormat>::Element *E = import_format.front(); E; E = E->next()) {
+ _register_project_setting_import(E->key(), import_setting_string, E->get().extensions, r_extensions, E->get().is_default);
+ }
+}
+
+void EditorSceneImporterAssimp::_register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const {
+ const String use_generic = "use_" + generic;
+ _GLOBAL_DEF(import_setting_string + use_generic, p_enabled, true);
+ if (ProjectSettings::get_singleton()->get(import_setting_string + use_generic)) {
+ for (int32_t i = 0; i < exts.size(); i++) {
+ r_extensions->push_back(exts[i]);
+ }
+ }
+}
+
+uint32_t EditorSceneImporterAssimp::get_import_flags() const {
+ return IMPORT_SCENE;
+}
+
+AssimpStream::AssimpStream() {
+ // empty
+}
+
+AssimpStream::~AssimpStream() {
+ // empty
+}
+
+void AssimpStream::write(const char *message) {
+ print_verbose(String("Open Asset Import: ") + String(message).strip_edges());
+}
+
+void EditorSceneImporterAssimp::_bind_methods() {
+}
+
+Node *EditorSceneImporterAssimp::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) {
+ Assimp::Importer importer;
+ std::wstring w_path = ProjectSettings::get_singleton()->globalize_path(p_path).c_str();
+ std::string s_path(w_path.begin(), w_path.end());
+ importer.SetPropertyBool(AI_CONFIG_PP_FD_REMOVE, true);
+ // Cannot remove pivot points because the static mesh will be in the wrong place
+ importer.SetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
+ int32_t max_bone_weights = 4;
+ //if (p_flags & IMPORT_ANIMATION_EIGHT_WEIGHTS) {
+ // const int eight_bones = 8;
+ // importer.SetPropertyBool(AI_CONFIG_PP_LBW_MAX_WEIGHTS, eight_bones);
+ // max_bone_weights = eight_bones;
+ //}
+
+ importer.SetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT);
+ //importer.SetPropertyFloat(AI_CONFIG_PP_DB_THRESHOLD, 1.0f);
+ int32_t post_process_Steps = aiProcess_CalcTangentSpace |
+ //aiProcess_FlipUVs |
+ //aiProcess_FlipWindingOrder |
+ aiProcess_DropNormals |
+ aiProcess_GenSmoothNormals |
+ aiProcess_JoinIdenticalVertices |
+ aiProcess_ImproveCacheLocality |
+ aiProcess_LimitBoneWeights |
+ //aiProcess_RemoveRedundantMaterials | // Causes a crash
+ aiProcess_SplitLargeMeshes |
+ aiProcess_Triangulate |
+ aiProcess_GenUVCoords |
+ //aiProcess_FindDegenerates |
+ aiProcess_SortByPType |
+ aiProcess_FindInvalidData |
+ aiProcess_TransformUVCoords |
+ aiProcess_FindInstances |
+ //aiProcess_FixInfacingNormals |
+ //aiProcess_ValidateDataStructure |
+ aiProcess_OptimizeMeshes |
+ //aiProcess_OptimizeGraph |
+ //aiProcess_Debone |
+ aiProcess_EmbedTextures |
+ aiProcess_SplitByBoneCount |
+ 0;
+ const aiScene *scene = importer.ReadFile(s_path.c_str(),
+ post_process_Steps);
+ ERR_EXPLAIN(String("Open Asset Import failed to open: ") + String(importer.GetErrorString()));
+ ERR_FAIL_COND_V(scene == NULL, NULL);
+ return _generate_scene(p_path, scene, p_flags, p_bake_fps, max_bone_weights);
+}
+
+template <class T>
+struct EditorSceneImporterAssetImportInterpolate {
+
+ T lerp(const T &a, const T &b, float c) const {
+
+ return a + (b - a) * c;
+ }
+
+ T catmull_rom(const T &p0, const T &p1, const T &p2, const T &p3, float t) {
+
+ float t2 = t * t;
+ float t3 = t2 * t;
+
+ return 0.5f * ((2.0f * p1) + (-p0 + p2) * t + (2.0f * p0 - 5.0f * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * t3);
+ }
+
+ T bezier(T start, T control_1, T control_2, T end, float t) {
+ /* Formula from Wikipedia article on Bezier curves. */
+ real_t omt = (1.0 - t);
+ real_t omt2 = omt * omt;
+ real_t omt3 = omt2 * omt;
+ real_t t2 = t * t;
+ real_t t3 = t2 * t;
+
+ return start * omt3 + control_1 * omt2 * t * 3.0 + control_2 * omt * t2 * 3.0 + end * t3;
+ }
+};
+
+//thank you for existing, partial specialization
+template <>
+struct EditorSceneImporterAssetImportInterpolate<Quat> {
+
+ Quat lerp(const Quat &a, const Quat &b, float c) const {
+ ERR_FAIL_COND_V(!a.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!b.is_normalized(), Quat());
+
+ return a.slerp(b, c).normalized();
+ }
+
+ Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) {
+ ERR_FAIL_COND_V(!p1.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!p2.is_normalized(), Quat());
+
+ return p1.slerp(p2, c).normalized();
+ }
+
+ Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) {
+ ERR_FAIL_COND_V(!start.is_normalized(), Quat());
+ ERR_FAIL_COND_V(!end.is_normalized(), Quat());
+
+ return start.slerp(end, t).normalized();
+ }
+};
+
+template <class T>
+T EditorSceneImporterAssimp::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp) {
+ //could use binary search, worth it?
+ int idx = -1;
+ for (int i = 0; i < p_times.size(); i++) {
+ if (p_times[i] > p_time)
+ break;
+ idx++;
+ }
+
+ EditorSceneImporterAssetImportInterpolate<T> interp;
+
+ switch (p_interp) {
+ case AssetImportAnimation::INTERP_LINEAR: {
+
+ if (idx == -1) {
+ return p_values[0];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[p_times.size() - 1];
+ }
+
+ float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
+
+ return interp.lerp(p_values[idx], p_values[idx + 1], c);
+
+ } break;
+ case AssetImportAnimation::INTERP_STEP: {
+
+ if (idx == -1) {
+ return p_values[0];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[p_times.size() - 1];
+ }
+
+ return p_values[idx];
+
+ } break;
+ case AssetImportAnimation::INTERP_CATMULLROMSPLINE: {
+
+ if (idx == -1) {
+ return p_values[1];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[1 + p_times.size() - 1];
+ }
+
+ float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
+
+ return interp.catmull_rom(p_values[idx - 1], p_values[idx], p_values[idx + 1], p_values[idx + 3], c);
+
+ } break;
+ case AssetImportAnimation::INTERP_CUBIC_SPLINE: {
+
+ if (idx == -1) {
+ return p_values[1];
+ } else if (idx >= p_times.size() - 1) {
+ return p_values[(p_times.size() - 1) * 3 + 1];
+ }
+
+ float c = (p_time - p_times[idx]) / (p_times[idx + 1] - p_times[idx]);
+
+ T from = p_values[idx * 3 + 1];
+ T c1 = from + p_values[idx * 3 + 2];
+ T to = p_values[idx * 3 + 4];
+ T c2 = to + p_values[idx * 3 + 3];
+
+ return interp.bezier(from, c1, c2, to, c);
+
+ } break;
+ }
+
+ ERR_FAIL_V(p_values[0]);
+}
+
+Spatial *EditorSceneImporterAssimp::_generate_scene(const String &p_path, const aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights) {
+ ERR_FAIL_COND_V(scene == NULL, NULL);
+ Spatial *root = memnew(Spatial);
+ AnimationPlayer *ap = NULL;
+ if (p_flags & IMPORT_ANIMATION) {
+ ap = memnew(AnimationPlayer);
+ root->add_child(ap);
+ ap->set_owner(root);
+ ap->set_name(TTR("AnimationPlayer"));
+ }
+ Set<String> bone_names;
+ Set<String> light_names;
+ Set<String> camera_names;
+ real_t factor = 1.0f;
+ String ext = p_path.get_file().get_extension().to_lower();
+ if ((ext == "fbx")) {
+ if (scene->mMetaData != NULL) {
+ scene->mMetaData->Get("UnitScaleFactor", factor);
+ factor = factor * 0.01f;
+ }
+ }
+ for (size_t l = 0; l < scene->mNumLights; l++) {
+ Light *light = NULL;
+ aiLight *ai_light = scene->mLights[l];
+ ERR_CONTINUE(ai_light == NULL);
+ if (ai_light->mType == aiLightSource_DIRECTIONAL) {
+ light = memnew(DirectionalLight);
+ Vector3 dir = Vector3(ai_light->mDirection.y, ai_light->mDirection.x, ai_light->mDirection.z);
+ dir.normalize();
+ Transform xform;
+ Quat quat;
+ quat.set_euler(dir);
+ Vector3 pos = Vector3(ai_light->mPosition.x, ai_light->mPosition.y, ai_light->mPosition.z);
+ pos = factor * pos;
+ xform.origin = pos;
+ light->set_transform(xform);
+ } else if (ai_light->mType == aiLightSource_POINT) {
+ light = memnew(OmniLight);
+ Vector3 pos = Vector3(ai_light->mPosition.x, ai_light->mPosition.y, ai_light->mPosition.z);
+ Transform xform;
+ xform.origin = pos;
+ pos = factor * pos;
+ light->set_transform(xform);
+ // No idea for energy
+ light->set_param(Light::PARAM_ATTENUATION, 0.0f);
+ } else if (ai_light->mType == aiLightSource_SPOT) {
+ light = memnew(SpotLight);
+ Vector3 pos = Vector3(ai_light->mPosition.x, ai_light->mPosition.y, ai_light->mPosition.z);
+ pos = factor * pos;
+ Transform xform;
+ xform.origin = pos;
+ Vector3 dir = Vector3(ai_light->mDirection.y, ai_light->mDirection.x, ai_light->mDirection.z);
+ dir.normalize();
+ Quat quat;
+ quat.set_euler(dir);
+ xform.basis = quat;
+ light->set_transform(xform);
+ // No idea for energy
+ light->set_param(Light::PARAM_ATTENUATION, 0.0f);
+ }
+ ERR_CONTINUE(light == NULL);
+ light->set_color(Color(ai_light->mColorDiffuse.r, ai_light->mColorDiffuse.g, ai_light->mColorDiffuse.b));
+ root->add_child(light);
+ light->set_name(_ai_string_to_string(ai_light->mName));
+ light->set_owner(root);
+ light_names.insert(_ai_string_to_string(scene->mLights[l]->mName));
+ }
+ for (size_t c = 0; c < scene->mNumCameras; c++) {
+ aiCamera *ai_camera = scene->mCameras[c];
+ Camera *camera = memnew(Camera);
+ float near = ai_camera->mClipPlaneNear;
+ if (Math::is_equal_approx(near, 0.0f)) {
+ near = 0.1f;
+ }
+ camera->set_perspective(Math::rad2deg(ai_camera->mHorizontalFOV) * 2.0f, near, ai_camera->mClipPlaneFar);
+ Vector3 pos = Vector3(ai_camera->mPosition.x, ai_camera->mPosition.y, ai_camera->mPosition.z);
+
+ Vector3 look_at = Vector3(ai_camera->mLookAt.y, ai_camera->mLookAt.x, ai_camera->mLookAt.z).normalized();
+ Quat quat;
+ quat.set_euler(look_at);
+ Transform xform;
+ xform.basis = quat;
+ xform.set_origin(pos);
+ root->add_child(camera);
+ camera->set_transform(xform);
+ camera->set_name(_ai_string_to_string(ai_camera->mName));
+ camera->set_owner(root);
+ camera_names.insert(_ai_string_to_string(scene->mCameras[c]->mName));
+ }
+ Map<Skeleton *, MeshInstance *> skeletons;
+ Map<String, Transform> bone_rests;
+ Vector<MeshInstance *> meshes;
+ int32_t mesh_count = 0;
+ Skeleton *s = memnew(Skeleton);
+ Set<String> removed_bones;
+ Map<String, Map<uint32_t, String> > path_morph_mesh_names;
+ _generate_node(p_path, scene, scene->mRootNode, root, root, bone_names, light_names, camera_names, skeletons, bone_rests, meshes, mesh_count, s, p_max_bone_weights, removed_bones, path_morph_mesh_names);
+ for (Map<Skeleton *, MeshInstance *>::Element *E = skeletons.front(); E; E = E->next()) {
+ E->key()->localize_rests();
+ }
+ Set<String> removed_nodes;
+ Set<Node *> keep_nodes;
+ _keep_node(p_path, root, root, keep_nodes);
+ _fill_kept_node(keep_nodes);
+ _filter_node(p_path, root, root, keep_nodes, removed_nodes);
+ if (p_flags & IMPORT_ANIMATION) {
+ for (size_t i = 0; i < scene->mNumAnimations; i++) {
+ _import_animation(p_path, meshes, scene, ap, i, p_bake_fps, skeletons, removed_nodes, removed_bones, path_morph_mesh_names);
+ }
+ List<StringName> animation_names;
+ ap->get_animation_list(&animation_names);
+ if (animation_names.empty()) {
+ root->remove_child(ap);
+ memdelete(ap);
+ }
+ }
+ return root;
+}
+
+void EditorSceneImporterAssimp::_fill_kept_node(Set<Node *> &keep_nodes) {
+ for (Set<Node *>::Element *E = keep_nodes.front(); E; E = E->next()) {
+ Node *node = E->get();
+ while (node != NULL) {
+ if (keep_nodes.has(node) == false) {
+ keep_nodes.insert(node);
+ }
+ node = node->get_parent();
+ }
+ }
+}
+
+String EditorSceneImporterAssimp::_find_skeleton_bone_root(Map<Skeleton *, MeshInstance *> &skeletons, Map<MeshInstance *, String> &meshes, Spatial *root) {
+ for (Map<Skeleton *, MeshInstance *>::Element *E = skeletons.front(); E; E = E->next()) {
+ if (meshes.has(E->get())) {
+ String name = meshes[E->get()];
+ if (name != "") {
+ return name;
+ }
+ }
+ }
+ return "";
+}
+
+void EditorSceneImporterAssimp::_set_bone_parent(Skeleton *s, Node *p_owner, aiNode *p_node) {
+ for (int32_t j = 0; j < s->get_bone_count(); j++) {
+ String bone_name = s->get_bone_name(j);
+ const aiNode *ai_bone_node = _ai_find_node(p_node, bone_name);
+ if (ai_bone_node == NULL) {
+ continue;
+ }
+ ai_bone_node = ai_bone_node->mParent;
+ while (ai_bone_node != NULL) {
+ int32_t node_parent_index = -1;
+ String parent_bone_name = _ai_string_to_string(ai_bone_node->mName);
+ node_parent_index = s->find_bone(parent_bone_name);
+ if (node_parent_index != -1) {
+ s->set_bone_parent(j, node_parent_index);
+ break;
+ }
+ ai_bone_node = ai_bone_node->mParent;
+ }
+ }
+}
+
+void EditorSceneImporterAssimp::_insert_animation_track(const aiScene *p_scene, const String p_path, int p_bake_fps, Ref<Animation> animation, float ticks_per_second, float length, const Skeleton *sk, const aiNodeAnim *track, String node_name, NodePath node_path) {
+
+ if (track->mNumRotationKeys || track->mNumPositionKeys || track->mNumScalingKeys) {
+ //make transform track
+ int track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->track_set_path(track_idx, node_path);
+ //first determine animation length
+
+ for (size_t i = 0; i < track->mNumRotationKeys; i++) {
+ length = MAX(length, track->mRotationKeys[i].mTime / ticks_per_second);
+ }
+ for (size_t i = 0; i < track->mNumPositionKeys; i++) {
+ length = MAX(length, track->mPositionKeys[i].mTime / ticks_per_second);
+ }
+ for (size_t i = 0; i < track->mNumScalingKeys; i++) {
+ length = MAX(length, track->mScalingKeys[i].mTime / ticks_per_second);
+ }
+
+ float increment = 1.0 / float(p_bake_fps);
+ float time = 0.0;
+
+ Vector3 base_pos;
+ Quat base_rot;
+ Vector3 base_scale = Vector3(1, 1, 1);
+
+ if (track->mNumRotationKeys != 0) {
+ aiQuatKey key = track->mRotationKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ real_t w = key.mValue.w;
+ Quat q(x, y, z, w);
+ q = q.normalized();
+ base_rot = q;
+ }
+
+ if (track->mNumPositionKeys != 0) {
+ aiVectorKey key = track->mPositionKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ base_pos = Vector3(x, y, z);
+ }
+
+ if (track->mNumScalingKeys != 0) {
+ aiVectorKey key = track->mScalingKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ base_scale = Vector3(x, y, z);
+ }
+
+ bool last = false;
+
+ Vector<Vector3> pos_values;
+ Vector<float> pos_times;
+ Vector<Vector3> scale_values;
+ Vector<float> scale_times;
+ Vector<Quat> rot_values;
+ Vector<float> rot_times;
+
+ for (size_t p = 0; p < track->mNumPositionKeys; p++) {
+ aiVector3D pos = track->mPositionKeys[p].mValue;
+ pos_values.push_back(Vector3(pos.x, pos.y, pos.z));
+ pos_times.push_back(track->mPositionKeys[p].mTime / ticks_per_second);
+ }
+
+ for (size_t r = 0; r < track->mNumRotationKeys; r++) {
+ aiQuaternion quat = track->mRotationKeys[r].mValue;
+ rot_values.push_back(Quat(quat.x, quat.y, quat.z, quat.w).normalized());
+ rot_times.push_back(track->mRotationKeys[r].mTime / ticks_per_second);
+ }
+
+ for (size_t sc = 0; sc < track->mNumScalingKeys; sc++) {
+ aiVector3D scale = track->mScalingKeys[sc].mValue;
+ scale_values.push_back(Vector3(scale.x, scale.y, scale.z));
+ scale_times.push_back(track->mScalingKeys[sc].mTime / ticks_per_second);
+ }
+ while (true) {
+ Vector3 pos = base_pos;
+ Quat rot = base_rot;
+ Vector3 scale = base_scale;
+
+ if (pos_values.size()) {
+ pos = _interpolate_track<Vector3>(pos_times, pos_values, time, AssetImportAnimation::INTERP_LINEAR);
+ }
+
+ if (rot_values.size()) {
+ rot = _interpolate_track<Quat>(rot_times, rot_values, time, AssetImportAnimation::INTERP_LINEAR).normalized();
+ }
+
+ if (scale_values.size()) {
+ scale = _interpolate_track<Vector3>(scale_times, scale_values, time, AssetImportAnimation::INTERP_LINEAR);
+ }
+
+ if (sk != NULL && sk->find_bone(node_name) != -1) {
+ Transform xform;
+ xform.basis.set_quat_scale(rot, scale);
+ xform.origin = pos;
+
+ int bone = sk->find_bone(node_name);
+ Transform rest_xform = sk->get_bone_rest(bone);
+ xform = rest_xform.affine_inverse() * xform;
+ rot = xform.basis.get_rotation_quat();
+ scale = xform.basis.get_scale();
+ pos = xform.origin;
+ }
+ {
+ Transform xform;
+ xform.basis.set_quat_scale(rot, scale);
+ xform.origin = pos;
+ Transform anim_xform;
+ String ext = p_path.get_file().get_extension().to_lower();
+ if (ext == "fbx") {
+ real_t factor = 1.0f;
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("UnitScaleFactor", factor);
+ }
+ anim_xform = anim_xform.scaled(Vector3(factor, factor, factor));
+ }
+ xform = anim_xform * xform;
+ rot = xform.basis.get_rotation_quat();
+ scale = xform.basis.get_scale();
+ pos = xform.origin;
+ }
+ rot.normalize();
+
+ animation->track_set_interpolation_type(track_idx, Animation::INTERPOLATION_LINEAR);
+ animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
+
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ }
+}
+
+void EditorSceneImporterAssimp::_import_animation(const String p_path, const Vector<MeshInstance *> p_meshes, const aiScene *p_scene, AnimationPlayer *ap, int32_t p_index, int p_bake_fps, Map<Skeleton *, MeshInstance *> p_skeletons, const Set<String> p_removed_nodes, const Set<String> removed_bones, const Map<String, Map<uint32_t, String> > p_path_morph_mesh_names) {
+ String name = "Animation";
+ aiAnimation const *anim = NULL;
+ if (p_index != -1) {
+ anim = p_scene->mAnimations[p_index];
+ if (anim->mName.length > 0) {
+ name = _ai_anim_string_to_string(anim->mName);
+ }
+ }
+
+ Ref<Animation> animation;
+ animation.instance();
+ float length = 0.0f;
+ animation->set_name(name);
+ float ticks_per_second = p_scene->mAnimations[p_index]->mTicksPerSecond;
+
+ if (p_scene->mMetaData != NULL && Math::is_equal_approx(ticks_per_second, 0.0f)) {
+ int32_t time_mode = 0;
+ p_scene->mMetaData->Get("TimeMode", time_mode);
+ ticks_per_second = _get_fbx_fps(time_mode, p_scene);
+ }
+
+ if ((p_path.get_file().get_extension().to_lower() == "glb" || p_path.get_file().get_extension().to_lower() == "gltf") && Math::is_equal_approx(ticks_per_second, 0.0f)) {
+ ticks_per_second = 1000.0f;
+ }
+
+ if (Math::is_equal_approx(ticks_per_second, 0.0f)) {
+ ticks_per_second = 25.0f;
+ }
+
+ length = anim->mDuration / ticks_per_second;
+ if (anim) {
+ Map<String, Vector<const aiNodeAnim *> > node_tracks;
+ for (size_t i = 0; i < anim->mNumChannels; i++) {
+ const aiNodeAnim *track = anim->mChannels[i];
+ String node_name = _ai_string_to_string(track->mNodeName);
+ NodePath node_path = node_name;
+ bool is_bone = false;
+ if (node_name.split(ASSIMP_FBX_KEY).size() > 1) {
+ String p_track_type = node_name.split(ASSIMP_FBX_KEY)[1];
+ if (p_track_type == "_Translation" || p_track_type == "_Rotation" || p_track_type == "_Scaling") {
+ continue;
+ }
+ }
+ for (Map<Skeleton *, MeshInstance *>::Element *E = p_skeletons.front(); E; E = E->next()) {
+ Skeleton *sk = E->key();
+ const String path = ap->get_owner()->get_path_to(sk);
+ if (path.empty()) {
+ continue;
+ }
+ if (sk->find_bone(node_name) == -1) {
+ continue;
+ }
+ node_path = path + ":" + node_name;
+ ERR_CONTINUE(ap->get_owner()->has_node(node_path) == false);
+ _insert_animation_track(p_scene, p_path, p_bake_fps, animation, ticks_per_second, length, sk, track, node_name, node_path);
+ is_bone = true;
+ }
+ if (is_bone) {
+ continue;
+ }
+ Node *node = ap->get_owner()->find_node(node_name);
+ if (node == NULL) {
+ continue;
+ }
+ if (p_removed_nodes.has(node_name)) {
+ continue;
+ }
+ const String path = ap->get_owner()->get_path_to(node);
+ if (path.empty()) {
+ print_verbose("Can't animate path");
+ continue;
+ }
+ node_path = path;
+ if (ap->get_owner()->has_node(node_path) == false) {
+ continue;
+ }
+ _insert_animation_track(p_scene, p_path, p_bake_fps, animation, ticks_per_second, length, NULL, track, node_name, node_path);
+ }
+ for (size_t i = 0; i < anim->mNumChannels; i++) {
+ const aiNodeAnim *track = anim->mChannels[i];
+ String node_name = _ai_string_to_string(track->mNodeName);
+ Vector<String> split_name = node_name.split(ASSIMP_FBX_KEY);
+ String bare_name = split_name[0];
+ Node *node = ap->get_owner()->find_node(bare_name);
+ if (node != NULL && split_name.size() > 1) {
+ Map<String, Vector<const aiNodeAnim *> >::Element *E = node_tracks.find(bare_name);
+ Vector<const aiNodeAnim *> ai_tracks;
+ if (E) {
+ ai_tracks = E->get();
+ ai_tracks.push_back(anim->mChannels[i]);
+ } else {
+ ai_tracks.push_back(anim->mChannels[i]);
+ }
+ node_tracks.insert(bare_name, ai_tracks);
+ }
+ }
+ for (Map<Skeleton *, MeshInstance *>::Element *E = p_skeletons.front(); E; E = E->next()) {
+ Skeleton *sk = E->key();
+ Map<String, Vector<const aiNodeAnim *> > anim_tracks;
+ for (int32_t i = 0; i < sk->get_bone_count(); i++) {
+ String _bone_name = sk->get_bone_name(i);
+ Vector<const aiNodeAnim *> ai_tracks;
+
+ if (sk->find_bone(_bone_name) == -1) {
+ continue;
+ }
+ for (size_t j = 0; j < anim->mNumChannels; j++) {
+ if (_ai_string_to_string(anim->mChannels[j]->mNodeName).split(ASSIMP_FBX_KEY).size() == 1) {
+ continue;
+ }
+ String track_name = _ai_string_to_string(anim->mChannels[j]->mNodeName).split(ASSIMP_FBX_KEY)[0];
+ if (track_name != _bone_name) {
+ continue;
+ }
+ if (sk->find_bone(_bone_name) == -1) {
+ continue;
+ }
+ ai_tracks.push_back(anim->mChannels[j]);
+ }
+ if (ai_tracks.size() == 0) {
+ continue;
+ }
+ anim_tracks.insert(_bone_name, ai_tracks);
+ }
+ for (Map<String, Vector<const aiNodeAnim *> >::Element *F = anim_tracks.front(); F; F = F->next()) {
+ _insert_pivot_anim_track(p_meshes, F->key(), F->get(), ap, sk, length, ticks_per_second, animation, p_bake_fps, p_path, p_scene);
+ }
+ }
+ for (Map<String, Vector<const aiNodeAnim *> >::Element *E = node_tracks.front(); E; E = E->next()) {
+ if (p_removed_nodes.has(E->key())) {
+ continue;
+ }
+ if (removed_bones.find(E->key())) {
+ continue;
+ }
+ _insert_pivot_anim_track(p_meshes, E->key(), E->get(), ap, NULL, length, ticks_per_second, animation, p_bake_fps, p_path, p_scene);
+ }
+ for (size_t i = 0; i < anim->mNumMorphMeshChannels; i++) {
+ const aiMeshMorphAnim *anim_mesh = anim->mMorphMeshChannels[i];
+ const String prop_name = _ai_string_to_string(anim_mesh->mName);
+ const String mesh_name = prop_name.split("*")[0];
+ if (p_removed_nodes.has(mesh_name)) {
+ continue;
+ }
+ ERR_CONTINUE(prop_name.split("*").size() != 2);
+ const MeshInstance *mesh_instance = Object::cast_to<MeshInstance>(ap->get_owner()->find_node(mesh_name));
+ ERR_CONTINUE(mesh_instance == NULL);
+ if (ap->get_owner()->find_node(mesh_instance->get_name()) == NULL) {
+ print_verbose("Can't find mesh in scene: " + mesh_instance->get_name());
+ continue;
+ }
+ const String path = ap->get_owner()->get_path_to(mesh_instance);
+ if (path.empty()) {
+ print_verbose("Can't find mesh in scene");
+ continue;
+ }
+ Ref<Mesh> mesh = mesh_instance->get_mesh();
+ ERR_CONTINUE(mesh.is_null());
+ const Map<String, Map<uint32_t, String> >::Element *E = p_path_morph_mesh_names.find(mesh_name);
+ ERR_CONTINUE(E == NULL);
+ for (size_t k = 0; k < anim_mesh->mNumKeys; k++) {
+ for (size_t j = 0; j < anim_mesh->mKeys[k].mNumValuesAndWeights; j++) {
+ const Map<uint32_t, String>::Element *F = E->get().find(anim_mesh->mKeys[k].mValues[j]);
+ ERR_CONTINUE(F == NULL);
+ const String prop = "blend_shapes/" + F->get();
+ const NodePath node_path = String(path) + ":" + prop;
+ ERR_CONTINUE(ap->get_owner()->has_node(node_path) == false);
+ int32_t blend_track_idx = -1;
+ if (animation->find_track(node_path) == -1) {
+ blend_track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_VALUE);
+ animation->track_set_interpolation_type(blend_track_idx, Animation::INTERPOLATION_LINEAR);
+ animation->track_set_path(blend_track_idx, node_path);
+ } else {
+ blend_track_idx = animation->find_track(node_path);
+ }
+ float t = anim_mesh->mKeys[k].mTime / ticks_per_second;
+ float w = anim_mesh->mKeys[k].mWeights[j];
+ animation->track_insert_key(blend_track_idx, t, w);
+ }
+ }
+ }
+ }
+ animation->set_length(length);
+ if (animation->get_track_count()) {
+ ap->add_animation(name, animation);
+ }
+}
+
+void EditorSceneImporterAssimp::_insert_pivot_anim_track(const Vector<MeshInstance *> p_meshes, const String p_node_name, Vector<const aiNodeAnim *> F, AnimationPlayer *ap, Skeleton *sk, float &length, float ticks_per_second, Ref<Animation> animation, int p_bake_fps, const String &p_path, const aiScene *p_scene) {
+ NodePath node_path;
+ if (sk != NULL) {
+ const String path = ap->get_owner()->get_path_to(sk);
+ if (path.empty()) {
+ return;
+ }
+ if (sk->find_bone(p_node_name) == -1) {
+ return;
+ }
+ node_path = path + ":" + p_node_name;
+ } else {
+ Node *node = ap->get_owner()->find_node(p_node_name);
+ if (node == NULL) {
+ return;
+ }
+ const String path = ap->get_owner()->get_path_to(node);
+ node_path = path;
+ }
+ if (node_path.is_empty()) {
+ return;
+ }
+
+ Vector<Vector3> pos_values;
+ Vector<float> pos_times;
+ Vector<Vector3> scale_values;
+ Vector<float> scale_times;
+ Vector<Quat> rot_values;
+ Vector<float> rot_times;
+ Vector3 base_pos;
+ Quat base_rot;
+ Vector3 base_scale = Vector3(1, 1, 1);
+ bool is_translation = false;
+ bool is_rotation = false;
+ bool is_scaling = false;
+ for (int32_t k = 0; k < F.size(); k++) {
+ String p_track_type = _ai_string_to_string(F[k]->mNodeName).split(ASSIMP_FBX_KEY)[1];
+ if (p_track_type == "_Translation") {
+ is_translation = is_translation || true;
+ } else if (p_track_type == "_Rotation") {
+ is_rotation = is_rotation || true;
+ } else if (p_track_type == "_Scaling") {
+ is_scaling = is_scaling || true;
+ } else {
+ continue;
+ }
+ ERR_CONTINUE(ap->get_owner()->has_node(node_path) == false);
+
+ if (F[k]->mNumRotationKeys || F[k]->mNumPositionKeys || F[k]->mNumScalingKeys) {
+
+ if (is_rotation) {
+ for (size_t i = 0; i < F[k]->mNumRotationKeys; i++) {
+ length = MAX(length, F[k]->mRotationKeys[i].mTime / ticks_per_second);
+ }
+ }
+ if (is_translation) {
+ for (size_t i = 0; i < F[k]->mNumPositionKeys; i++) {
+ length = MAX(length, F[k]->mPositionKeys[i].mTime / ticks_per_second);
+ }
+ }
+ if (is_scaling) {
+ for (size_t i = 0; i < F[k]->mNumScalingKeys; i++) {
+ length = MAX(length, F[k]->mScalingKeys[i].mTime / ticks_per_second);
+ }
+ }
+
+ if (is_rotation == false && is_translation == false && is_scaling == false) {
+ return;
+ }
+
+ if (is_rotation) {
+ if (F[k]->mNumRotationKeys != 0) {
+ aiQuatKey key = F[k]->mRotationKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ real_t w = key.mValue.w;
+ Quat q(x, y, z, w);
+ q = q.normalized();
+ base_rot = q;
+ }
+ }
+
+ if (is_translation) {
+ if (F[k]->mNumPositionKeys != 0) {
+ aiVectorKey key = F[k]->mPositionKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ base_pos = Vector3(x, y, z);
+ }
+ }
+
+ if (is_scaling) {
+ if (F[k]->mNumScalingKeys != 0) {
+ aiVectorKey key = F[k]->mScalingKeys[0];
+ real_t x = key.mValue.x;
+ real_t y = key.mValue.y;
+ real_t z = key.mValue.z;
+ base_scale = Vector3(x, y, z);
+ }
+ }
+ if (is_translation) {
+ for (size_t p = 0; p < F[k]->mNumPositionKeys; p++) {
+ aiVector3D pos = F[k]->mPositionKeys[p].mValue;
+ pos_values.push_back(Vector3(pos.x, pos.y, pos.z));
+ pos_times.push_back(F[k]->mPositionKeys[p].mTime / ticks_per_second);
+ }
+ }
+
+ if (is_rotation) {
+ for (size_t r = 0; r < F[k]->mNumRotationKeys; r++) {
+ aiQuaternion quat = F[k]->mRotationKeys[r].mValue;
+ rot_values.push_back(Quat(quat.x, quat.y, quat.z, quat.w).normalized());
+ rot_times.push_back(F[k]->mRotationKeys[r].mTime / ticks_per_second);
+ }
+ }
+
+ if (is_scaling) {
+ for (size_t sc = 0; sc < F[k]->mNumScalingKeys; sc++) {
+ aiVector3D scale = F[k]->mScalingKeys[sc].mValue;
+ scale_values.push_back(Vector3(scale.x, scale.y, scale.z));
+ scale_times.push_back(F[k]->mScalingKeys[sc].mTime / ticks_per_second);
+ }
+ }
+ }
+ }
+ int32_t track_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_TRANSFORM);
+ animation->track_set_path(track_idx, node_path);
+ float increment = 1.0 / float(p_bake_fps);
+ float time = 0.0;
+ bool last = false;
+ while (true) {
+ Vector3 pos = Vector3();
+ Quat rot = Quat();
+ Vector3 scale = Vector3(1.0f, 1.0f, 1.0f);
+ if (is_translation && pos_values.size()) {
+ pos = _interpolate_track<Vector3>(pos_times, pos_values, time, AssetImportAnimation::INTERP_LINEAR);
+ Transform anim_xform;
+ String ext = p_path.get_file().get_extension().to_lower();
+ if (ext == "fbx") {
+ aiNode *ai_node = _ai_find_node(p_scene->mRootNode, p_node_name);
+ Transform mesh_xform = _get_global_ai_node_transform(p_scene, ai_node);
+ pos = mesh_xform.origin + pos;
+ real_t factor = 1.0f;
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("UnitScaleFactor", factor);
+ factor = factor * 0.01f;
+ }
+ pos = pos * factor;
+ }
+ }
+ if (is_rotation && rot_values.size()) {
+ rot = _interpolate_track<Quat>(rot_times, rot_values, time, AssetImportAnimation::INTERP_LINEAR).normalized();
+ }
+ if (is_scaling && scale_values.size()) {
+ scale = _interpolate_track<Vector3>(scale_times, scale_values, time, AssetImportAnimation::INTERP_LINEAR);
+ }
+ animation->track_set_interpolation_type(track_idx, Animation::INTERPOLATION_LINEAR);
+ animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
+
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+}
+
+float EditorSceneImporterAssimp::_get_fbx_fps(int32_t time_mode, const aiScene *p_scene) {
+ switch (time_mode) {
+ case AssetImportFbx::TIME_MODE_DEFAULT: return 24; //hack
+ case AssetImportFbx::TIME_MODE_120: return 120;
+ case AssetImportFbx::TIME_MODE_100: return 100;
+ case AssetImportFbx::TIME_MODE_60: return 60;
+ case AssetImportFbx::TIME_MODE_50: return 50;
+ case AssetImportFbx::TIME_MODE_48: return 48;
+ case AssetImportFbx::TIME_MODE_30: return 30;
+ case AssetImportFbx::TIME_MODE_30_DROP: return 30;
+ case AssetImportFbx::TIME_MODE_NTSC_DROP_FRAME: return 29.9700262f;
+ case AssetImportFbx::TIME_MODE_NTSC_FULL_FRAME: return 29.9700262f;
+ case AssetImportFbx::TIME_MODE_PAL: return 25;
+ case AssetImportFbx::TIME_MODE_CINEMA: return 24;
+ case AssetImportFbx::TIME_MODE_1000: return 1000;
+ case AssetImportFbx::TIME_MODE_CINEMA_ND: return 23.976f;
+ case AssetImportFbx::TIME_MODE_CUSTOM:
+ int32_t frame_rate;
+ p_scene->mMetaData->Get("FrameRate", frame_rate);
+ return frame_rate;
+ }
+ return 0;
+}
+
+Transform EditorSceneImporterAssimp::_get_global_ai_node_transform(const aiScene *p_scene, const aiNode *p_current_node) {
+ aiNode const *current_node = p_current_node;
+ Transform xform;
+ while (current_node != NULL) {
+ xform = _ai_matrix_transform(current_node->mTransformation) * xform;
+ current_node = current_node->mParent;
+ }
+ return xform;
+}
+
+void EditorSceneImporterAssimp::_generate_node_bone(const aiScene *p_scene, const aiNode *p_node, Map<String, bool> &p_mesh_bones, Skeleton *p_skeleton, const String p_path, const int32_t p_max_bone_weights) {
+ for (size_t i = 0; i < p_node->mNumMeshes; i++) {
+ const unsigned int mesh_idx = p_node->mMeshes[i];
+ const aiMesh *ai_mesh = p_scene->mMeshes[mesh_idx];
+ for (size_t j = 0; j < ai_mesh->mNumBones; j++) {
+ String bone_name = _ai_string_to_string(ai_mesh->mBones[j]->mName);
+ if (p_skeleton->find_bone(bone_name) != -1) {
+ continue;
+ }
+ p_mesh_bones.insert(bone_name, true);
+ p_skeleton->add_bone(bone_name);
+ int32_t idx = p_skeleton->find_bone(bone_name);
+ Transform xform = _ai_matrix_transform(ai_mesh->mBones[j]->mOffsetMatrix);
+ String ext = p_path.get_file().get_extension().to_lower();
+ if (ext == "fbx") {
+ Transform mesh_xform = _get_global_ai_node_transform(p_scene, p_node);
+ mesh_xform.basis = Basis();
+ xform = mesh_xform.affine_inverse() * xform;
+ }
+ p_skeleton->set_bone_rest(idx, xform.affine_inverse());
+ }
+ }
+}
+
+void EditorSceneImporterAssimp::_generate_node_bone_parents(const aiScene *p_scene, const aiNode *p_node, Map<String, bool> &p_mesh_bones, Skeleton *p_skeleton, const MeshInstance *p_mi) {
+ for (size_t i = 0; i < p_node->mNumMeshes; i++) {
+ const unsigned int mesh_idx = p_node->mMeshes[i];
+ const aiMesh *ai_mesh = p_scene->mMeshes[mesh_idx];
+
+ for (size_t j = 0; j < ai_mesh->mNumBones; j++) {
+ aiNode *bone_node = p_scene->mRootNode->FindNode(ai_mesh->mBones[j]->mName);
+ ERR_CONTINUE(bone_node == NULL);
+ aiNode *bone_node_parent = bone_node->mParent;
+ while (bone_node_parent != NULL) {
+ String bone_parent_name = _ai_string_to_string(bone_node_parent->mName);
+ bone_parent_name = bone_parent_name.split(ASSIMP_FBX_KEY)[0];
+ if (bone_parent_name == p_mi->get_name()) {
+ break;
+ }
+ if (p_mi->get_parent() == NULL) {
+ break;
+ }
+ if (bone_parent_name == p_mi->get_parent()->get_name()) {
+ break;
+ }
+ if (bone_node_parent->mParent == p_scene->mRootNode) {
+ break;
+ }
+ if (p_skeleton->find_bone(bone_parent_name) == -1) {
+ p_mesh_bones.insert(bone_parent_name, true);
+ }
+ bone_node_parent = bone_node_parent->mParent;
+ }
+ }
+ }
+}
+void EditorSceneImporterAssimp::_calculate_skeleton_root(Skeleton *s, const aiScene *p_scene, aiNode *&p_ai_skeleton_root, Map<String, bool> &mesh_bones, const aiNode *p_node) {
+ if (s->get_bone_count() > 0) {
+ String bone_name = s->get_bone_name(0);
+ p_ai_skeleton_root = _ai_find_node(p_scene->mRootNode, bone_name);
+ for (size_t i = 0; i < p_scene->mRootNode->mNumChildren; i++) {
+ if (p_ai_skeleton_root == NULL) {
+ break;
+ }
+ aiNode *found = p_scene->mRootNode->mChildren[i]->FindNode(p_ai_skeleton_root->mName);
+ if (found) {
+ p_ai_skeleton_root = p_scene->mRootNode->mChildren[i];
+ break;
+ }
+ }
+ }
+
+ if (p_ai_skeleton_root == NULL) {
+ p_ai_skeleton_root = p_scene->mRootNode->FindNode(p_node->mName);
+ while (p_ai_skeleton_root && p_ai_skeleton_root->mParent && p_ai_skeleton_root->mParent != p_scene->mRootNode) {
+ p_ai_skeleton_root = p_scene->mRootNode->FindNode(p_ai_skeleton_root->mName)->mParent;
+ }
+ }
+ p_ai_skeleton_root = _ai_find_node(p_scene->mRootNode, _ai_string_to_string(p_ai_skeleton_root->mName).split(ASSIMP_FBX_KEY)[0]);
+}
+
+void EditorSceneImporterAssimp::_fill_skeleton(const aiScene *p_scene, const aiNode *p_node, Spatial *p_current, Node *p_owner, Skeleton *p_skeleton, const Map<String, bool> p_mesh_bones, const Map<String, Transform> &p_bone_rests, Set<String> p_tracks, const String p_path, Set<String> &r_removed_bones) {
+ String node_name = _ai_string_to_string(p_node->mName);
+ if (p_mesh_bones.find(node_name) != NULL && p_skeleton->find_bone(node_name) == -1) {
+ r_removed_bones.insert(node_name);
+ p_skeleton->add_bone(node_name);
+ int32_t idx = p_skeleton->find_bone(node_name);
+ Transform xform = _get_global_ai_node_transform(p_scene, p_node);
+ xform = _format_rot_xform(p_path, p_scene) * xform;
+ p_skeleton->set_bone_rest(idx, xform);
+ }
+
+ for (size_t i = 0; i < p_node->mNumChildren; i++) {
+ _fill_skeleton(p_scene, p_node->mChildren[i], p_current, p_owner, p_skeleton, p_mesh_bones, p_bone_rests, p_tracks, p_path, r_removed_bones);
+ }
+}
+
+void EditorSceneImporterAssimp::_keep_node(const String &p_path, Node *p_current, Node *p_owner, Set<Node *> &r_keep_nodes) {
+ if (p_current == p_owner) {
+ r_keep_nodes.insert(p_current);
+ }
+
+ if (p_current->get_class() != Spatial().get_class()) {
+ r_keep_nodes.insert(p_current);
+ }
+
+ for (int i = 0; i < p_current->get_child_count(); i++) {
+ _keep_node(p_path, p_current->get_child(i), p_owner, r_keep_nodes);
+ }
+}
+
+void EditorSceneImporterAssimp::_filter_node(const String &p_path, Node *p_current, Node *p_owner, const Set<Node *> p_keep_nodes, Set<String> &r_removed_nodes) {
+ if (p_keep_nodes.has(p_current) == false) {
+ r_removed_nodes.insert(p_current->get_name());
+ p_current->queue_delete();
+ }
+ for (int i = 0; i < p_current->get_child_count(); i++) {
+ _filter_node(p_path, p_current->get_child(i), p_owner, p_keep_nodes, r_removed_nodes);
+ }
+}
+
+void EditorSceneImporterAssimp::_generate_node(const String &p_path, const aiScene *p_scene, const aiNode *p_node, Node *p_parent, Node *p_owner, Set<String> &r_bone_name, Set<String> p_light_names, Set<String> p_camera_names, Map<Skeleton *, MeshInstance *> &r_skeletons, const Map<String, Transform> &p_bone_rests, Vector<MeshInstance *> &r_mesh_instances, int32_t &r_mesh_count, Skeleton *p_skeleton, const int32_t p_max_bone_weights, Set<String> &r_removed_bones, Map<String, Map<uint32_t, String> > &r_name_morph_mesh_names) {
+ Spatial *child_node = NULL;
+ if (p_node == NULL) {
+ return;
+ }
+ String node_name = _ai_string_to_string(p_node->mName);
+ real_t factor = 1.0f;
+ String ext = p_path.get_file().get_extension().to_lower();
+ if (ext == "fbx") {
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("UnitScaleFactor", factor);
+ factor = factor * 0.01f;
+ }
+ }
+ {
+ Transform xform = _ai_matrix_transform(p_node->mTransformation);
+
+ child_node = memnew(Spatial);
+ p_parent->add_child(child_node);
+ child_node->set_owner(p_owner);
+ if (p_node == p_scene->mRootNode) {
+ if ((ext == "fbx") && p_node == p_scene->mRootNode) {
+ xform = xform.scaled(Vector3(factor, factor, factor));
+ Transform format_xform = _format_rot_xform(p_path, p_scene);
+ xform = format_xform * xform;
+ }
+ }
+ child_node->set_transform(xform * child_node->get_transform());
+ }
+
+ if (p_node->mNumMeshes > 0) {
+ MeshInstance *mesh_node = memnew(MeshInstance);
+ p_parent->add_child(mesh_node);
+ mesh_node->set_owner(p_owner);
+ mesh_node->set_transform(child_node->get_transform());
+ {
+ Map<String, bool> mesh_bones;
+ p_skeleton->set_use_bones_in_world_transform(true);
+ _generate_node_bone(p_scene, p_node, mesh_bones, p_skeleton, p_path, p_max_bone_weights);
+ Set<String> tracks;
+ _get_track_set(p_scene, tracks);
+ aiNode *skeleton_root = NULL;
+ _calculate_skeleton_root(p_skeleton, p_scene, skeleton_root, mesh_bones, p_node);
+ _generate_node_bone_parents(p_scene, p_node, mesh_bones, p_skeleton, mesh_node);
+ if (p_skeleton->get_bone_count() > 0) {
+ _fill_skeleton(p_scene, skeleton_root, mesh_node, p_owner, p_skeleton, mesh_bones, p_bone_rests, tracks, p_path, r_removed_bones);
+ _set_bone_parent(p_skeleton, p_owner, p_scene->mRootNode);
+ }
+ MeshInstance *mi = Object::cast_to<MeshInstance>(mesh_node);
+ if (mi) {
+ r_mesh_instances.push_back(mi);
+ }
+ _add_mesh_to_mesh_instance(p_node, p_scene, p_skeleton, p_path, mesh_node, p_owner, r_bone_name, r_mesh_count, p_max_bone_weights, r_name_morph_mesh_names);
+ }
+ if (mesh_node != NULL && p_skeleton->get_bone_count() > 0 && p_owner->find_node(p_skeleton->get_name()) == NULL) {
+ Node *node = p_owner->find_node(_ai_string_to_string(p_scene->mRootNode->mName));
+ ERR_FAIL_COND(node == NULL);
+ node->add_child(p_skeleton);
+ p_skeleton->set_owner(p_owner);
+ if (ext == "fbx") {
+ Transform mesh_xform = _get_global_ai_node_transform(p_scene, p_node);
+ mesh_xform.origin = Vector3();
+ p_skeleton->set_transform(mesh_xform);
+ }
+ r_skeletons.insert(p_skeleton, mesh_node);
+ }
+ for (size_t i = 0; i < p_node->mNumMeshes; i++) {
+ if (p_scene->mMeshes[p_node->mMeshes[i]]->HasBones()) {
+ mesh_node->set_name(node_name);
+ // Meshes without skeletons must not have skeletons
+ mesh_node->set_skeleton_path(String(mesh_node->get_path_to(p_owner)) + "/" + p_owner->get_path_to(p_skeleton));
+ }
+ }
+ child_node->get_parent()->remove_child(child_node);
+ memdelete(child_node);
+ child_node = mesh_node;
+ } else if (p_light_names.has(node_name)) {
+ Spatial *light_node = Object::cast_to<Light>(p_owner->find_node(node_name));
+ ERR_FAIL_COND(light_node == NULL);
+ if (!p_parent->has_node(light_node->get_path())) {
+ p_parent->add_child(light_node);
+ }
+ light_node->set_owner(p_owner);
+ light_node->set_transform(child_node->get_transform().scaled(Vector3(factor, factor, factor)) *
+ light_node->get_transform().scaled(Vector3(factor, factor, factor)));
+ child_node->get_parent()->remove_child(child_node);
+ memdelete(child_node);
+ child_node = light_node;
+ } else if (p_camera_names.has(node_name)) {
+ Spatial *camera_node = Object::cast_to<Camera>(p_owner->find_node(node_name));
+ ERR_FAIL_COND(camera_node == NULL);
+ if (!p_parent->has_node(camera_node->get_path())) {
+ p_parent->add_child(camera_node);
+ }
+ camera_node->set_owner(p_owner);
+ camera_node->set_transform(child_node->get_transform().scaled(Vector3(factor, factor, factor)) *
+ camera_node->get_transform().scaled(Vector3(factor, factor, factor)));
+ camera_node->scale(Vector3(factor, factor, factor));
+ child_node->get_parent()->remove_child(child_node);
+ memdelete(child_node);
+ child_node = camera_node;
+ }
+ child_node->set_name(node_name);
+ for (size_t i = 0; i < p_node->mNumChildren; i++) {
+ _generate_node(p_path, p_scene, p_node->mChildren[i], child_node, p_owner, r_bone_name, p_light_names, p_camera_names, r_skeletons, p_bone_rests, r_mesh_instances, r_mesh_count, p_skeleton, p_max_bone_weights, r_removed_bones, r_name_morph_mesh_names);
+ }
+}
+
+aiNode *EditorSceneImporterAssimp::_ai_find_node(aiNode *ai_child_node, const String bone_name) {
+
+ if (_ai_string_to_string(ai_child_node->mName) == bone_name) {
+ return ai_child_node;
+ }
+ aiNode *target = NULL;
+ for (size_t i = 0; i < ai_child_node->mNumChildren; i++) {
+
+ target = _ai_find_node(ai_child_node->mChildren[i], bone_name);
+ if (target != NULL) {
+ return target;
+ }
+ }
+ return target;
+}
+
+Transform EditorSceneImporterAssimp::_format_rot_xform(const String p_path, const aiScene *p_scene) {
+ String ext = p_path.get_file().get_extension().to_lower();
+
+ Transform xform;
+ int32_t up_axis = 0;
+ Vector3 up_axis_vec3 = Vector3();
+
+ int32_t front_axis = 0;
+ Vector3 front_axis_vec3 = Vector3();
+
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("UpAxis", up_axis);
+ if (up_axis == AssetImportFbx::UP_VECTOR_AXIS_X) {
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("FrontAxis", front_axis);
+ if (front_axis == AssetImportFbx::FRONT_PARITY_EVEN) {
+ // y
+ } else if (front_axis == AssetImportFbx::FRONT_PARITY_ODD) {
+ // z
+ //front_axis_vec3 = Vector3(0.0f, Math::deg2rad(-180.f), 0.0f);
+ }
+ }
+ } else if (up_axis == AssetImportFbx::UP_VECTOR_AXIS_Y) {
+ up_axis_vec3 = Vector3(Math::deg2rad(-90.f), 0.0f, 0.0f);
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("FrontAxis", front_axis);
+ if (front_axis == AssetImportFbx::FRONT_PARITY_EVEN) {
+ // x
+ } else if (front_axis == AssetImportFbx::FRONT_PARITY_ODD) {
+ // z
+ }
+ }
+ } else if (up_axis == AssetImportFbx::UP_VECTOR_AXIS_Z) {
+ up_axis_vec3 = Vector3(0.0f, Math ::deg2rad(90.f), 0.0f);
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("FrontAxis", front_axis);
+ if (front_axis == AssetImportFbx::FRONT_PARITY_EVEN) {
+ // x
+ } else if (front_axis == AssetImportFbx::FRONT_PARITY_ODD) {
+ // y
+ }
+ }
+ }
+ }
+
+ int32_t up_axis_sign = 0;
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("UpAxisSign", up_axis_sign);
+ up_axis_vec3 = up_axis_vec3 * up_axis_sign;
+ }
+
+ int32_t front_axis_sign = 0;
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("FrontAxisSign", front_axis_sign);
+ front_axis_vec3 = front_axis_vec3 * front_axis_sign;
+ }
+
+ int32_t coord_axis = 0;
+ Vector3 coord_axis_vec3 = Vector3();
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("CoordAxis", coord_axis);
+ if (coord_axis == AssetImportFbx::COORD_LEFT) {
+ } else if (coord_axis == AssetImportFbx::COORD_RIGHT) {
+ }
+ }
+
+ int32_t coord_axis_sign = 0;
+ if (p_scene->mMetaData != NULL) {
+ p_scene->mMetaData->Get("CoordAxisSign", coord_axis_sign);
+ }
+
+ Quat up_quat;
+ up_quat.set_euler(up_axis_vec3);
+
+ Quat coord_quat;
+ coord_quat.set_euler(coord_axis_vec3);
+
+ Quat front_quat;
+ front_quat.set_euler(front_axis_vec3);
+
+ xform.basis.set_quat(up_quat * coord_quat * front_quat);
+ return xform;
+}
+
+void EditorSceneImporterAssimp::_get_track_set(const aiScene *p_scene, Set<String> &tracks) {
+ for (size_t i = 0; i < p_scene->mNumAnimations; i++) {
+ for (size_t j = 0; j < p_scene->mAnimations[i]->mNumChannels; j++) {
+ aiString ai_name = p_scene->mAnimations[i]->mChannels[j]->mNodeName;
+ String name = _ai_string_to_string(ai_name);
+ tracks.insert(name);
+ }
+ }
+}
+
+void EditorSceneImporterAssimp::_add_mesh_to_mesh_instance(const aiNode *p_node, const aiScene *p_scene, Skeleton *s, const String &p_path, MeshInstance *p_mesh_instance, Node *p_owner, Set<String> &r_bone_name, int32_t &r_mesh_count, int32_t p_max_bone_weights, Map<String, Map<uint32_t, String> > &r_name_morph_mesh_names) {
+ Ref<ArrayMesh> mesh;
+ mesh.instance();
+ bool has_uvs = false;
+ for (size_t i = 0; i < p_node->mNumMeshes; i++) {
+ const unsigned int mesh_idx = p_node->mMeshes[i];
+ const aiMesh *ai_mesh = p_scene->mMeshes[mesh_idx];
+
+ Map<uint32_t, Vector<float> > vertex_weight;
+ Map<uint32_t, Vector<String> > vertex_bone_name;
+ for (size_t b = 0; b < ai_mesh->mNumBones; b++) {
+ aiBone *bone = ai_mesh->mBones[b];
+ for (size_t w = 0; w < bone->mNumWeights; w++) {
+ String name = _ai_string_to_string(bone->mName);
+ aiVertexWeight ai_weights = bone->mWeights[w];
+ uint32_t vertexId = ai_weights.mVertexId;
+ Map<uint32_t, Vector<float> >::Element *result = vertex_weight.find(vertexId);
+ Vector<float> weights;
+ if (result != NULL) {
+ weights.append_array(result->value());
+ }
+ weights.push_back(ai_weights.mWeight);
+ if (vertex_weight.has(vertexId)) {
+ vertex_weight[vertexId] = weights;
+ } else {
+ vertex_weight.insert(vertexId, weights);
+ }
+ Map<uint32_t, Vector<String> >::Element *bone_result = vertex_bone_name.find(vertexId);
+ Vector<String> bone_names;
+ if (bone_result != NULL) {
+ bone_names.append_array(bone_result->value());
+ }
+ bone_names.push_back(name);
+ if (vertex_bone_name.has(vertexId)) {
+ vertex_bone_name[vertexId] = bone_names;
+ } else {
+ vertex_bone_name.insert(vertexId, bone_names);
+ }
+ }
+ }
+
+ Ref<SurfaceTool> st;
+ st.instance();
+ st->begin(Mesh::PRIMITIVE_TRIANGLES);
+
+ for (size_t j = 0; j < ai_mesh->mNumVertices; j++) {
+ if (ai_mesh->HasTextureCoords(0)) {
+ has_uvs = true;
+ st->add_uv(Vector2(ai_mesh->mTextureCoords[0][j].x, 1.0f - ai_mesh->mTextureCoords[0][j].y));
+ }
+ if (ai_mesh->HasTextureCoords(1)) {
+ has_uvs = true;
+ st->add_uv2(Vector2(ai_mesh->mTextureCoords[1][j].x, 1.0f - ai_mesh->mTextureCoords[1][j].y));
+ }
+ if (ai_mesh->HasVertexColors(0)) {
+ Color color = Color(ai_mesh->mColors[0]->r, ai_mesh->mColors[0]->g, ai_mesh->mColors[0]->b, ai_mesh->mColors[0]->a);
+ st->add_color(color);
+ }
+ if (ai_mesh->mNormals != NULL) {
+ const aiVector3D normals = ai_mesh->mNormals[j];
+ const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
+ st->add_normal(godot_normal);
+ if (ai_mesh->HasTangentsAndBitangents()) {
+ const aiVector3D tangents = ai_mesh->mTangents[j];
+ const Vector3 godot_tangent = Vector3(tangents.x, tangents.y, tangents.z);
+ const aiVector3D bitangent = ai_mesh->mBitangents[j];
+ const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
+ float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
+ st->add_tangent(Plane(tangents.x, tangents.y, tangents.z, d));
+ }
+ }
+
+ if (s != NULL && s->get_bone_count() > 0) {
+ Map<uint32_t, Vector<String> >::Element *I = vertex_bone_name.find(j);
+ Vector<int32_t> bones;
+ if (I != NULL) {
+ Vector<String> bone_names;
+ bone_names.append_array(I->value());
+ for (int32_t f = 0; f < bone_names.size(); f++) {
+ int32_t bone = s->find_bone(bone_names[f]);
+ ERR_EXPLAIN("Asset Importer: Mesh can't find bone " + bone_names[f]);
+ ERR_FAIL_COND(bone == -1);
+ bones.push_back(bone);
+ }
+ if (s->get_bone_count()) {
+ int32_t add = CLAMP(p_max_bone_weights - bones.size(), 0, p_max_bone_weights);
+ for (int32_t f = 0; f < add; f++) {
+ bones.push_back(0);
+ }
+ }
+ st->add_bones(bones);
+ Map<uint32_t, Vector<float> >::Element *E = vertex_weight.find(j);
+ Vector<float> weights;
+ if (E != NULL) {
+ weights = E->value();
+ if (weights.size() != p_max_bone_weights) {
+ int32_t add = CLAMP(p_max_bone_weights - weights.size(), 0, p_max_bone_weights);
+ for (int32_t f = 0; f < add; f++) {
+ weights.push_back(0.0f);
+ }
+ }
+ }
+ ERR_CONTINUE(weights.size() == 0);
+ st->add_weights(weights);
+ }
+ }
+ const aiVector3D pos = ai_mesh->mVertices[j];
+ Vector3 godot_pos = Vector3(pos.x, pos.y, pos.z);
+ st->add_vertex(godot_pos);
+ }
+ for (size_t j = 0; j < ai_mesh->mNumFaces; j++) {
+ const aiFace face = ai_mesh->mFaces[j];
+ ERR_FAIL_COND(face.mNumIndices != 3);
+ Vector<size_t> order;
+ order.push_back(2);
+ order.push_back(1);
+ order.push_back(0);
+ for (int32_t k = 0; k < order.size(); k++) {
+ st->add_index(face.mIndices[order[k]]);
+ }
+ }
+ if (ai_mesh->HasTangentsAndBitangents() == false && has_uvs) {
+ st->generate_tangents();
+ }
+ aiMaterial *ai_material = p_scene->mMaterials[ai_mesh->mMaterialIndex];
+ Ref<SpatialMaterial> mat;
+ mat.instance();
+
+ int32_t mat_two_sided = 0;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_TWOSIDED, mat_two_sided)) {
+ if (mat_two_sided > 0) {
+ mat->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ }
+ }
+
+ const String mesh_name = _ai_string_to_string(ai_mesh->mName);
+ aiString mat_name;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_NAME, mat_name)) {
+ mat->set_name(_ai_string_to_string(mat_name));
+ }
+
+ aiTextureType tex_normal = aiTextureType_NORMALS;
+ {
+ aiString ai_filename = aiString();
+ String filename = "";
+ aiTextureMapMode map_mode[2];
+
+ if (AI_SUCCESS == ai_material->GetTexture(tex_normal, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
+ filename = _ai_raw_string_to_string(ai_filename);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+
+ if (texture != NULL) {
+ if (map_mode != NULL) {
+ _set_texture_mapping_mode(map_mode, texture);
+ }
+ mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true);
+ mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ }
+ }
+ }
+ }
+
+ {
+ aiString ai_filename = aiString();
+ String filename = "";
+
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_NORMAL_TEXTURE, ai_filename)) {
+ filename = _ai_raw_string_to_string(ai_filename);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true);
+ mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ }
+ }
+ }
+ }
+
+ aiTextureType tex_emissive = aiTextureType_EMISSIVE;
+
+ if (ai_material->GetTextureCount(tex_emissive) > 0) {
+
+ aiString ai_filename = aiString();
+ String filename = "";
+ aiTextureMapMode map_mode[2];
+
+ if (AI_SUCCESS == ai_material->GetTexture(tex_emissive, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
+ filename = _ai_raw_string_to_string(ai_filename);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ _set_texture_mapping_mode(map_mode, texture);
+ mat->set_feature(SpatialMaterial::FEATURE_EMISSION, true);
+ mat->set_texture(SpatialMaterial::TEXTURE_EMISSION, texture);
+ }
+ }
+ }
+ }
+
+ aiTextureType tex_albedo = aiTextureType_DIFFUSE;
+ if (ai_material->GetTextureCount(tex_albedo) > 0) {
+
+ aiString ai_filename = aiString();
+ String filename = "";
+ aiTextureMapMode map_mode[2];
+ if (AI_SUCCESS == ai_material->GetTexture(tex_albedo, 0, &ai_filename, NULL, NULL, NULL, NULL, map_mode)) {
+ filename = _ai_raw_string_to_string(ai_filename);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ if (texture->get_data()->detect_alpha() != Image::ALPHA_NONE) {
+ _set_texture_mapping_mode(map_mode, texture);
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ }
+ }
+ }
+ } else {
+ aiColor4D clr_diffuse;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_COLOR_DIFFUSE, clr_diffuse)) {
+ if (Math::is_equal_approx(clr_diffuse.a, 1.0f) == false) {
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_albedo(Color(clr_diffuse.r, clr_diffuse.g, clr_diffuse.b, clr_diffuse.a));
+ }
+ }
+
+ aiString tex_gltf_base_color_path = aiString();
+ aiTextureMapMode map_mode[2];
+ if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE, &tex_gltf_base_color_path, NULL, NULL, NULL, NULL, map_mode)) {
+ String filename = _ai_raw_string_to_string(tex_gltf_base_color_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ if (texture->get_data()->detect_alpha() == Image::ALPHA_BLEND) {
+ _set_texture_mapping_mode(map_mode, texture);
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ }
+ }
+ } else {
+ aiColor4D pbr_base_color;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR, pbr_base_color)) {
+ if (Math::is_equal_approx(pbr_base_color.a, 1.0f) == false) {
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_albedo(Color(pbr_base_color.r, pbr_base_color.g, pbr_base_color.b, pbr_base_color.a));
+ }
+ }
+ {
+ aiString tex_fbx_pbs_base_color_path = aiString();
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_base_color_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ if (texture->get_data()->detect_alpha() == Image::ALPHA_BLEND) {
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ }
+ }
+ } else {
+ aiColor4D pbr_base_color;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR, pbr_base_color)) {
+ mat->set_albedo(Color(pbr_base_color.r, pbr_base_color.g, pbr_base_color.b, pbr_base_color.a));
+ }
+ }
+
+ aiUVTransform pbr_base_color_uv_xform;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM, pbr_base_color_uv_xform)) {
+ mat->set_uv1_offset(Vector3(pbr_base_color_uv_xform.mTranslation.x, pbr_base_color_uv_xform.mTranslation.y, 0.0f));
+ mat->set_uv1_scale(Vector3(pbr_base_color_uv_xform.mScaling.x, pbr_base_color_uv_xform.mScaling.y, 1.0f));
+ }
+ }
+
+ {
+ aiString tex_fbx_pbs_normal_path = aiString();
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE, tex_fbx_pbs_normal_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_normal_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true);
+ mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ }
+ }
+ }
+ }
+
+ aiString cull_mode;
+ if (p_node->mMetaData) {
+ p_node->mMetaData->Get("Culling", cull_mode);
+ }
+ if (cull_mode.length != 0 && cull_mode == aiString("CullingOff")) {
+ mat->set_cull_mode(SpatialMaterial::CULL_DISABLED);
+ }
+
+ {
+ aiString tex_fbx_stingray_normal_path = aiString();
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE, tex_fbx_stingray_normal_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_stingray_normal_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ mat->set_feature(SpatialMaterial::Feature::FEATURE_NORMAL_MAPPING, true);
+ mat->set_texture(SpatialMaterial::TEXTURE_NORMAL, texture);
+ }
+ }
+ }
+ }
+
+ {
+ aiString tex_fbx_pbs_base_color_path = aiString();
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE, tex_fbx_pbs_base_color_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_base_color_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ if (texture->get_data()->detect_alpha() == Image::ALPHA_BLEND) {
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ }
+ }
+ } else {
+ aiColor4D pbr_base_color;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR, pbr_base_color)) {
+ mat->set_albedo(Color(pbr_base_color.r, pbr_base_color.g, pbr_base_color.b, pbr_base_color.a));
+ }
+ }
+
+ aiUVTransform pbr_base_color_uv_xform;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM, pbr_base_color_uv_xform)) {
+ mat->set_uv1_offset(Vector3(pbr_base_color_uv_xform.mTranslation.x, pbr_base_color_uv_xform.mTranslation.y, 0.0f));
+ mat->set_uv1_scale(Vector3(pbr_base_color_uv_xform.mScaling.x, pbr_base_color_uv_xform.mScaling.y, 1.0f));
+ }
+ }
+
+ {
+ aiString tex_fbx_pbs_emissive_path = aiString();
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE, tex_fbx_pbs_emissive_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_emissive_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ _find_texture_path(p_path, path, found);
+ if (texture != NULL) {
+ if (texture->get_data()->detect_alpha() == Image::ALPHA_BLEND) {
+ mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true);
+ mat->set_depth_draw_mode(SpatialMaterial::DepthDrawMode::DEPTH_DRAW_ALPHA_OPAQUE_PREPASS);
+ }
+ mat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture);
+ }
+ }
+ } else {
+ aiColor4D pbr_emmissive_color;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR, pbr_emmissive_color)) {
+ mat->set_emission(Color(pbr_emmissive_color.r, pbr_emmissive_color.g, pbr_emmissive_color.b, pbr_emmissive_color.a));
+ }
+ }
+
+ real_t pbr_emission_intensity;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR, pbr_emission_intensity)) {
+ mat->set_emission_energy(pbr_emission_intensity);
+ }
+ }
+
+ aiString tex_gltf_pbr_metallicroughness_path;
+ if (AI_SUCCESS == ai_material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &tex_gltf_pbr_metallicroughness_path)) {
+ String filename = _ai_raw_string_to_string(tex_gltf_pbr_metallicroughness_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_texture(SpatialMaterial::TEXTURE_METALLIC, texture);
+ mat->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_BLUE);
+ mat->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, texture);
+ mat->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GREEN);
+ }
+ }
+ } else {
+ float pbr_roughness = 0.0f;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, pbr_roughness)) {
+ mat->set_roughness(pbr_roughness);
+ }
+ float pbr_metallic = 0.0f;
+
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, pbr_metallic)) {
+ mat->set_metallic(pbr_metallic);
+ }
+ }
+ {
+ aiString tex_fbx_pbs_metallic_path;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE, tex_fbx_pbs_metallic_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_metallic_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_texture(SpatialMaterial::TEXTURE_METALLIC, texture);
+ mat->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GRAYSCALE);
+ }
+ }
+ } else {
+ float pbr_metallic = 0.0f;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR, pbr_metallic)) {
+ mat->set_metallic(pbr_metallic);
+ }
+ }
+
+ aiString tex_fbx_pbs_rough_path;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_rough_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, texture);
+ mat->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GRAYSCALE);
+ }
+ }
+ } else {
+ float pbr_roughness = 0.04f;
+
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR, pbr_roughness)) {
+ mat->set_roughness(pbr_roughness);
+ }
+ }
+ }
+
+ {
+ aiString tex_fbx_pbs_metallic_path;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE, tex_fbx_pbs_metallic_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_metallic_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_texture(SpatialMaterial::TEXTURE_METALLIC, texture);
+ mat->set_metallic_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GRAYSCALE);
+ }
+ }
+ } else {
+ float pbr_metallic = 0.0f;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_METALNESS_FACTOR, pbr_metallic)) {
+ mat->set_metallic(pbr_metallic);
+ }
+ }
+
+ aiString tex_fbx_pbs_rough_path;
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE, tex_fbx_pbs_rough_path)) {
+ String filename = _ai_raw_string_to_string(tex_fbx_pbs_rough_path);
+ String path = p_path.get_base_dir() + "/" + filename.replace("\\", "/");
+ bool found = false;
+ _find_texture_path(p_path, path, found);
+ if (found) {
+ Ref<Texture> texture = _load_texture(p_scene, path);
+ if (texture != NULL) {
+ mat->set_texture(SpatialMaterial::TEXTURE_ROUGHNESS, texture);
+ mat->set_roughness_texture_channel(SpatialMaterial::TEXTURE_CHANNEL_GRAYSCALE);
+ }
+ }
+ } else {
+ float pbr_roughness = 0.04f;
+
+ if (AI_SUCCESS == ai_material->Get(AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR, pbr_roughness)) {
+ mat->set_roughness(pbr_roughness);
+ }
+ }
+ }
+
+ Array array_mesh = st->commit_to_arrays();
+ Array morphs;
+ morphs.resize(ai_mesh->mNumAnimMeshes);
+ Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_TRIANGLES;
+ Map<uint32_t, String> morph_mesh_idx_names;
+ for (size_t j = 0; j < ai_mesh->mNumAnimMeshes; j++) {
+
+ String ai_anim_mesh_name = _ai_string_to_string(ai_mesh->mAnimMeshes[j]->mName);
+ mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
+ if (ai_anim_mesh_name.empty()) {
+ ai_anim_mesh_name = String("morph_") + itos(j);
+ }
+ mesh->add_blend_shape(ai_anim_mesh_name);
+ morph_mesh_idx_names.insert(j, ai_anim_mesh_name);
+ Array array_copy;
+ array_copy.resize(VisualServer::ARRAY_MAX);
+
+ for (int l = 0; l < VisualServer::ARRAY_MAX; l++) {
+ array_copy[l] = array_mesh[l].duplicate(true);
+ }
+
+ const size_t num_vertices = ai_mesh->mAnimMeshes[j]->mNumVertices;
+ array_copy[Mesh::ARRAY_INDEX] = Variant();
+ if (ai_mesh->mAnimMeshes[j]->HasPositions()) {
+ PoolVector3Array vertices;
+ vertices.resize(num_vertices);
+ for (size_t l = 0; l < num_vertices; l++) {
+ const aiVector3D ai_pos = ai_mesh->mAnimMeshes[j]->mVertices[l];
+ Vector3 position = Vector3(ai_pos.x, ai_pos.y, ai_pos.z);
+ vertices.write()[l] = position;
+ }
+ PoolVector3Array new_vertices = array_copy[VisualServer::ARRAY_VERTEX].duplicate(true);
+
+ for (int32_t l = 0; l < vertices.size(); l++) {
+ PoolVector3Array::Write w = new_vertices.write();
+ w[l] = vertices[l];
+ }
+ ERR_CONTINUE(vertices.size() != new_vertices.size());
+ array_copy[VisualServer::ARRAY_VERTEX] = new_vertices;
+ }
+
+ int32_t color_set = 0;
+ if (ai_mesh->mAnimMeshes[j]->HasVertexColors(color_set)) {
+ PoolColorArray colors;
+ colors.resize(num_vertices);
+ for (size_t l = 0; l < num_vertices; l++) {
+ const aiColor4D ai_color = ai_mesh->mAnimMeshes[j]->mColors[color_set][l];
+ Color color = Color(ai_color.r, ai_color.g, ai_color.b, ai_color.a);
+ colors.write()[l] = color;
+ }
+ PoolColorArray new_colors = array_copy[VisualServer::ARRAY_COLOR].duplicate(true);
+
+ for (int32_t l = 0; l < colors.size(); l++) {
+ PoolColorArray::Write w = new_colors.write();
+ w[l] = colors[l];
+ }
+ array_copy[VisualServer::ARRAY_COLOR] = new_colors;
+ }
+
+ if (ai_mesh->mAnimMeshes[j]->HasNormals()) {
+ PoolVector3Array normals;
+ normals.resize(num_vertices);
+ for (size_t l = 0; l < num_vertices; l++) {
+ const aiVector3D ai_normal = ai_mesh->mAnimMeshes[i]->mNormals[l];
+ Vector3 normal = Vector3(ai_normal.x, ai_normal.y, ai_normal.z);
+ normals.write()[l] = normal;
+ }
+ PoolVector3Array new_normals = array_copy[VisualServer::ARRAY_NORMAL].duplicate(true);
+
+ for (int l = 0; l < normals.size(); l++) {
+ PoolVector3Array::Write w = new_normals.write();
+ w[l] = normals[l];
+ }
+ array_copy[VisualServer::ARRAY_NORMAL] = new_normals;
+ }
+
+ if (ai_mesh->mAnimMeshes[j]->HasTangentsAndBitangents()) {
+ PoolColorArray tangents;
+ tangents.resize(num_vertices);
+ PoolColorArray::Write w = tangents.write();
+ for (size_t l = 0; l < num_vertices; l++) {
+ _calc_tangent_from_mesh(ai_mesh, j, l, l, w);
+ }
+ PoolRealArray new_tangents = array_copy[VisualServer::ARRAY_TANGENT].duplicate(true);
+ ERR_CONTINUE(new_tangents.size() != tangents.size() * 4);
+ for (int32_t l = 0; l < tangents.size(); l++) {
+ new_tangents.write()[l + 0] = tangents[l].r;
+ new_tangents.write()[l + 1] = tangents[l].g;
+ new_tangents.write()[l + 2] = tangents[l].b;
+ new_tangents.write()[l + 3] = tangents[l].a;
+ }
+
+ array_copy[VisualServer::ARRAY_TANGENT] = new_tangents;
+ }
+
+ morphs[j] = array_copy;
+ }
+ r_name_morph_mesh_names.insert(_ai_raw_string_to_string(p_node->mName), morph_mesh_idx_names);
+ mesh->add_surface_from_arrays(primitive, array_mesh, morphs);
+ mesh->surface_set_material(i, mat);
+ mesh->surface_set_name(i, _ai_string_to_string(ai_mesh->mName));
+ r_mesh_count++;
+ print_line(String("Open Asset Import: Created mesh (including instances) ") + _ai_string_to_string(ai_mesh->mName) + " " + itos(r_mesh_count) + " of " + itos(p_scene->mNumMeshes));
+ }
+ p_mesh_instance->set_mesh(mesh);
+}
+
+Ref<Texture> EditorSceneImporterAssimp::_load_texture(const aiScene *p_scene, String p_path) {
+ Vector<String> split_path = p_path.get_basename().split("*");
+ if (split_path.size() == 2) {
+ size_t texture_idx = split_path[1].to_int();
+ ERR_FAIL_COND_V(texture_idx >= p_scene->mNumTextures, Ref<Texture>());
+ aiTexture *tex = p_scene->mTextures[texture_idx];
+ String filename = _ai_raw_string_to_string(tex->mFilename);
+ filename = filename.get_file();
+ print_verbose("Open Asset Import: Loading embedded texture " + filename);
+ if (tex->mHeight == 0) {
+ if (tex->CheckFormat("png")) {
+ Ref<Image> img = Image::_png_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
+ ERR_FAIL_COND_V(img.is_null(), Ref<Texture>());
+
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+ t->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ return t;
+ } else if (tex->CheckFormat("jpg")) {
+ Ref<Image> img = Image::_jpg_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
+ ERR_FAIL_COND_V(img.is_null(), Ref<Texture>());
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+ t->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ return t;
+ } else if (tex->CheckFormat("dds")) {
+ ERR_EXPLAIN("Open Asset Import: Embedded dds not implemented");
+ ERR_FAIL_COND_V(true, Ref<Texture>());
+ //Ref<Image> img = Image::_dds_mem_loader_func((uint8_t *)tex->pcData, tex->mWidth);
+ //ERR_FAIL_COND_V(img.is_null(), Ref<Texture>());
+ //Ref<ImageTexture> t;
+ //t.instance();
+ //t->create_from_image(img);
+ //t->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ //return t;
+ }
+ } else {
+ Ref<Image> img;
+ img.instance();
+ PoolByteArray arr;
+ uint32_t size = tex->mWidth * tex->mHeight;
+ arr.resize(size);
+ memcpy(arr.write().ptr(), tex->pcData, size);
+ ERR_FAIL_COND_V(arr.size() % 4 != 0, Ref<Texture>());
+ //ARGB8888 to RGBA8888
+ for (int32_t i = 0; i < arr.size() / 4; i++) {
+ arr.write().ptr()[(4 * i) + 3] = arr[(4 * i) + 0];
+ arr.write().ptr()[(4 * i) + 0] = arr[(4 * i) + 1];
+ arr.write().ptr()[(4 * i) + 1] = arr[(4 * i) + 2];
+ arr.write().ptr()[(4 * i) + 2] = arr[(4 * i) + 3];
+ }
+ img->create(tex->mWidth, tex->mHeight, true, Image::FORMAT_RGBA8, arr);
+ ERR_FAIL_COND_V(img.is_null(), Ref<Texture>());
+
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(img);
+ t->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY);
+ return t;
+ }
+ return Ref<Texture>();
+ }
+ Ref<Texture> p_texture = ResourceLoader::load(p_path, "Texture");
+ return p_texture;
+}
+
+void EditorSceneImporterAssimp::_calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, PoolColorArray::Write &w) {
+ const aiVector3D normals = ai_mesh->mAnimMeshes[i]->mNormals[tri_index];
+ const Vector3 godot_normal = Vector3(normals.x, normals.y, normals.z);
+ const aiVector3D tangent = ai_mesh->mAnimMeshes[i]->mTangents[tri_index];
+ const Vector3 godot_tangent = Vector3(tangent.x, tangent.y, tangent.z);
+ const aiVector3D bitangent = ai_mesh->mAnimMeshes[i]->mBitangents[tri_index];
+ const Vector3 godot_bitangent = Vector3(bitangent.x, bitangent.y, bitangent.z);
+ float d = godot_normal.cross(godot_tangent).dot(godot_bitangent) > 0.0f ? 1.0f : -1.0f;
+ Color plane_tangent = Color(tangent.x, tangent.y, tangent.z, d);
+ w[index] = plane_tangent;
+}
+
+void EditorSceneImporterAssimp::_set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<Texture> texture) {
+ ERR_FAIL_COND(map_mode == NULL);
+ aiTextureMapMode tex_mode = aiTextureMapMode::aiTextureMapMode_Wrap;
+ //for (size_t i = 0; i < 3; i++) {
+ tex_mode = map_mode[0];
+ //}
+ int32_t flags = Texture::FLAGS_DEFAULT;
+ if (tex_mode == aiTextureMapMode_Wrap) {
+ //Default
+ } else if (tex_mode == aiTextureMapMode_Clamp) {
+ flags = flags & ~Texture::FLAG_REPEAT;
+ } else if (tex_mode == aiTextureMapMode_Mirror) {
+ flags = flags | Texture::FLAG_MIRRORED_REPEAT;
+ }
+ texture->set_flags(flags);
+}
+
+void EditorSceneImporterAssimp::_find_texture_path(const String &r_p_path, String &r_path, bool &r_found) {
+
+ _Directory dir;
+
+ List<String> exts;
+ ImageLoader::get_recognized_extensions(&exts);
+
+ Vector<String> split_path = r_path.get_basename().split("*");
+ if (split_path.size() == 2) {
+ r_found = true;
+ return;
+ }
+
+ if (dir.file_exists(r_p_path.get_base_dir() + r_path.get_file())) {
+ r_path = r_p_path.get_base_dir() + r_path.get_file();
+ r_found = true;
+ return;
+ }
+
+ for (int32_t i = 0; i < exts.size(); i++) {
+ if (r_found) {
+ return;
+ }
+ if (r_found == false) {
+ _find_texture_path(r_p_path, dir, r_path, r_found, "." + exts[i]);
+ }
+ }
+}
+
+void EditorSceneImporterAssimp::_find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension) {
+ String name = path.get_basename() + extension;
+ if (dir.file_exists(name)) {
+ found = true;
+ path = name;
+ return;
+ }
+ String name_ignore_sub_directory = p_path.get_base_dir() + "/" + path.get_file().get_basename() + extension;
+ if (dir.file_exists(name_ignore_sub_directory)) {
+ found = true;
+ path = name_ignore_sub_directory;
+ return;
+ }
+
+ String name_find_texture_sub_directory = p_path.get_base_dir() + "/textures/" + path.get_file().get_basename() + extension;
+ if (dir.file_exists(name_find_texture_sub_directory)) {
+ found = true;
+ path = name_find_texture_sub_directory;
+ return;
+ }
+ String name_find_texture_upper_sub_directory = p_path.get_base_dir() + "/Textures/" + path.get_file().get_basename() + extension;
+ if (dir.file_exists(name_find_texture_upper_sub_directory)) {
+ found = true;
+ path = name_find_texture_upper_sub_directory;
+ return;
+ }
+ String name_find_texture_outside_sub_directory = p_path.get_base_dir() + "/../textures/" + path.get_file().get_basename() + extension;
+ if (dir.file_exists(name_find_texture_outside_sub_directory)) {
+ found = true;
+ path = name_find_texture_outside_sub_directory;
+ return;
+ }
+
+ String name_find_upper_texture_outside_sub_directory = p_path.get_base_dir() + "/../Textures/" + path.get_file().get_basename() + extension;
+ if (dir.file_exists(name_find_upper_texture_outside_sub_directory)) {
+ found = true;
+ path = name_find_upper_texture_outside_sub_directory;
+ return;
+ }
+}
+
+String EditorSceneImporterAssimp::_ai_string_to_string(const aiString p_string) const {
+ Vector<char> raw_name;
+ raw_name.resize(p_string.length);
+ memcpy(raw_name.ptrw(), p_string.C_Str(), p_string.length);
+ String name;
+ name.parse_utf8(raw_name.ptrw(), raw_name.size());
+ if (name.find(":") != -1) {
+ String replaced_name = name.split(":")[1];
+ print_verbose("Replacing " + name + " containing : with " + replaced_name);
+ name = replaced_name;
+ }
+ if (name.find(".") != -1) {
+ String replaced_name = name.replace(".", "");
+ print_verbose("Replacing " + name + " containing . with " + replaced_name);
+ name = replaced_name;
+ }
+ return name;
+}
+
+String EditorSceneImporterAssimp::_ai_anim_string_to_string(const aiString p_string) const {
+ Vector<char> raw_name;
+ raw_name.resize(p_string.length);
+ memcpy(raw_name.ptrw(), p_string.C_Str(), p_string.length);
+ String name;
+ name.parse_utf8(raw_name.ptrw(), raw_name.size());
+ if (name.find(":") != -1) {
+ String replaced_name = name.split(":")[1];
+ print_verbose("Replacing " + name + " containing : with " + replaced_name);
+ name = replaced_name;
+ }
+ return name;
+}
+
+String EditorSceneImporterAssimp::_ai_raw_string_to_string(const aiString p_string) const {
+ Vector<char> raw_name;
+ raw_name.resize(p_string.length);
+ memcpy(raw_name.ptrw(), p_string.C_Str(), p_string.length);
+ String name;
+ name.parse_utf8(raw_name.ptrw(), raw_name.size());
+ return name;
+}
+
+Ref<Animation> EditorSceneImporterAssimp::import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) {
+ return Ref<Animation>();
+}
+
+const Transform EditorSceneImporterAssimp::_ai_matrix_transform(const aiMatrix4x4 p_matrix) {
+ aiMatrix4x4 matrix = p_matrix;
+ Transform xform;
+ xform.set(matrix.a1, matrix.b1, matrix.c1, matrix.a2, matrix.b2, matrix.c2, matrix.a3, matrix.b3, matrix.c3, matrix.a4, matrix.b4, matrix.c4);
+ xform.basis.inverse();
+ xform.basis.transpose();
+ Vector3 scale = xform.basis.get_scale();
+ Quat rot = xform.basis.get_rotation_quat();
+ xform.basis.set_quat_scale(rot, scale);
+ return xform;
+}
diff --git a/modules/assimp/editor_scene_importer_assimp.h b/modules/assimp/editor_scene_importer_assimp.h
new file mode 100644
index 0000000000..8f9ed434ae
--- /dev/null
+++ b/modules/assimp/editor_scene_importer_assimp.h
@@ -0,0 +1,206 @@
+/*************************************************************************/
+/* editor_scene_importer_assimp.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 EDITOR_SCENE_IMPORTER_ASSIMP_H
+#define EDITOR_SCENE_IMPORTER_ASSIMP_H
+
+#ifdef TOOLS_ENABLED
+#include "core/bind/core_bind.h"
+#include "core/io/resource_importer.h"
+#include "core/vector.h"
+#include "editor/import/resource_importer_scene.h"
+#include "editor/project_settings_editor.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/3d/skeleton.h"
+#include "scene/3d/spatial.h"
+#include "scene/animation/animation_player.h"
+#include "scene/resources/animation.h"
+#include "scene/resources/surface_tool.h"
+
+#include "assimp/DefaultLogger.hpp"
+#include "assimp/LogStream.hpp"
+#include "assimp/Logger.hpp"
+#include "assimp/matrix4x4.h"
+#include "assimp/scene.h"
+#include "assimp/types.h"
+
+class AssimpStream : public Assimp::LogStream {
+public:
+ // Constructor
+ AssimpStream();
+
+ // Destructor
+ ~AssimpStream();
+ // Write something using your own functionality
+ void write(const char *message);
+};
+
+#define AI_MATKEY_FBX_MAYA_BASE_COLOR_FACTOR "$raw.Maya|baseColor", 0, 0
+#define AI_MATKEY_FBX_MAYA_METALNESS_FACTOR "$raw.Maya|metalness", 0, 0
+#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_FACTOR "$raw.Maya|diffuseRoughness", 0, 0
+
+#define AI_MATKEY_FBX_MAYA_METALNESS_TEXTURE "$raw.Maya|metalness|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_METALNESS_UV_XFORM "$raw.Maya|metalness|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_TEXTURE "$raw.Maya|diffuseRoughness|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_DIFFUSE_ROUGHNESS_UV_XFORM "$raw.Maya|diffuseRoughness|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_BASE_COLOR_TEXTURE "$raw.Maya|baseColor|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_BASE_COLOR_UV_XFORM "$raw.Maya|baseColor|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_NORMAL_TEXTURE "$raw.Maya|normalCamera|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo", aiTextureType_UNKNOWN, 0
+
+#define AI_MATKEY_FBX_NORMAL_TEXTURE "$raw.Maya|normalCamera|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_NORMAL_UV_XFORM "$raw.Maya|normalCamera|uvtrafo", aiTextureType_UNKNOWN, 0
+
+#define AI_MATKEY_FBX_MAYA_STINGRAY_DISPLACEMENT_SCALING_FACTOR "$raw.Maya|displacementscaling", 0, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_BASE_COLOR_FACTOR "$raw.Maya|base_color", 0, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_FACTOR "$raw.Maya|emissive", 0, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_FACTOR "$raw.Maya|metallic", 0, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_FACTOR "$raw.Maya|roughness", 0, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_INTENSITY_FACTOR "$raw.Maya|emissive_intensity", 0, 0
+
+#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_TEXTURE "$raw.Maya|TEX_normal_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_NORMAL_UV_XFORM "$raw.Maya|TEX_normal_map|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_TEXTURE "$raw.Maya|TEX_color_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_COLOR_UV_XFORM "$raw.Maya|TEX_color_map|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_TEXTURE "$raw.Maya|TEX_metallic_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_METALLIC_UV_XFORM "$raw.Maya|TEX_metallic_map|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_TEXTURE "$raw.Maya|TEX_roughness_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_ROUGHNESS_UV_XFORM "$raw.Maya|TEX_roughness_map|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_TEXTURE "$raw.Maya|TEX_emissive_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_EMISSIVE_UV_XFORM "$raw.Maya|TEX_emissive_map|uvtrafo", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_TEXTURE "$raw.Maya|TEX_ao_map|file", aiTextureType_UNKNOWN, 0
+#define AI_MATKEY_FBX_MAYA_STINGRAY_AO_UV_XFORM "$raw.Maya|TEX_ao_map|uvtrafo", aiTextureType_UNKNOWN, 0
+
+class EditorSceneImporterAssimp : public EditorSceneImporter {
+private:
+ GDCLASS(EditorSceneImporterAssimp, EditorSceneImporter);
+ const String ASSIMP_FBX_KEY = "_$AssimpFbx$";
+
+ struct AssetImportAnimation {
+ enum Interpolation {
+ INTERP_LINEAR,
+ INTERP_STEP,
+ INTERP_CATMULLROMSPLINE,
+ INTERP_CUBIC_SPLINE
+ };
+ };
+
+ struct AssetImportFbx {
+ enum ETimeMode {
+ TIME_MODE_DEFAULT = 0,
+ TIME_MODE_120 = 1,
+ TIME_MODE_100 = 2,
+ TIME_MODE_60 = 3,
+ TIME_MODE_50 = 4,
+ TIME_MODE_48 = 5,
+ TIME_MODE_30 = 6,
+ TIME_MODE_30_DROP = 7,
+ TIME_MODE_NTSC_DROP_FRAME = 8,
+ TIME_MODE_NTSC_FULL_FRAME = 9,
+ TIME_MODE_PAL = 10,
+ TIME_MODE_CINEMA = 11,
+ TIME_MODE_1000 = 12,
+ TIME_MODE_CINEMA_ND = 13,
+ TIME_MODE_CUSTOM = 14,
+ TIME_MODE_TIME_MODE_COUNT = 15
+ };
+ enum UpAxis {
+ UP_VECTOR_AXIS_X = 1,
+ UP_VECTOR_AXIS_Y = 2,
+ UP_VECTOR_AXIS_Z = 3
+ };
+ enum FrontAxis {
+ FRONT_PARITY_EVEN = 1,
+ FRONT_PARITY_ODD = 2,
+ };
+
+ enum CoordAxis {
+ COORD_RIGHT = 0,
+ COORD_LEFT = 1
+ };
+ };
+ Spatial *_generate_scene(const String &p_path, const aiScene *scene, const uint32_t p_flags, int p_bake_fps, const int32_t p_max_bone_weights);
+ void _fill_kept_node(Set<Node *> &keep_nodes);
+ String _find_skeleton_bone_root(Map<Skeleton *, MeshInstance *> &skeletons, Map<MeshInstance *, String> &meshes, Spatial *root);
+ void _set_bone_parent(Skeleton *s, Node *p_owner, aiNode *p_node);
+ Transform _get_global_ai_node_transform(const aiScene *p_scene, const aiNode *p_current_node);
+ void _generate_node_bone(const aiScene *p_scene, const aiNode *p_node, Map<String, bool> &p_mesh_bones, Skeleton *p_skeleton, const String p_path, const int32_t p_max_bone_weights);
+ void _generate_node_bone_parents(const aiScene *p_scene, const aiNode *p_node, Map<String, bool> &p_mesh_bones, Skeleton *p_skeleton, const MeshInstance *p_mi);
+ void _calculate_skeleton_root(Skeleton *s, const aiScene *p_scene, aiNode *&p_ai_skeleton_root, Map<String, bool> &mesh_bones, const aiNode *p_node);
+ void _fill_skeleton(const aiScene *p_scene, const aiNode *p_node, Spatial *p_current, Node *p_owner, Skeleton *p_skeleton, const Map<String, bool> p_mesh_bones, const Map<String, Transform> &p_bone_rests, Set<String> p_tracks, const String p_path, Set<String> &r_removed_bones);
+ void _keep_node(const String &p_path, Node *p_current, Node *p_owner, Set<Node *> &r_keep_nodes);
+ void _filter_node(const String &p_path, Node *p_current, Node *p_owner, const Set<Node *> p_keep_nodes, Set<String> &r_removed_nodes);
+ void _generate_node(const String &p_path, const aiScene *p_scene, const aiNode *p_node, Node *p_parent, Node *p_owner, Set<String> &r_bone_name, Set<String> p_light_names, Set<String> p_camera_names, Map<Skeleton *, MeshInstance *> &r_skeletons, const Map<String, Transform> &p_bone_rests, Vector<MeshInstance *> &r_mesh_instances, int32_t &r_mesh_count, Skeleton *p_skeleton, const int32_t p_max_bone_weights, Set<String> &r_removed_bones, Map<String, Map<uint32_t, String> > &r_name_morph_mesh_names);
+ aiNode *_ai_find_node(aiNode *ai_child_node, const String bone_name);
+ Transform _format_rot_xform(const String p_path, const aiScene *p_scene);
+ void _get_track_set(const aiScene *p_scene, Set<String> &tracks);
+ void _insert_animation_track(const aiScene *p_scene, const String p_path, int p_bake_fps, Ref<Animation> animation, float ticks_per_second, float length, const Skeleton *sk, const aiNodeAnim *track, String node_name, NodePath node_path);
+ void _add_mesh_to_mesh_instance(const aiNode *p_node, const aiScene *p_scene, Skeleton *s, const String &p_path, MeshInstance *p_mesh_instance, Node *p_owner, Set<String> &r_bone_name, int32_t &r_mesh_count, int32_t p_max_bone_weights, Map<String, Map<uint32_t, String> > &r_name_morph_mesh_names);
+ Ref<Texture> _load_texture(const aiScene *p_scene, String p_path);
+ void _calc_tangent_from_mesh(const aiMesh *ai_mesh, int i, int tri_index, int index, PoolColorArray::Write &w);
+ void _set_texture_mapping_mode(aiTextureMapMode *map_mode, Ref<Texture> texture);
+ void _find_texture_path(const String &p_path, String &path, bool &r_found);
+ void _find_texture_path(const String &p_path, _Directory &dir, String &path, bool &found, String extension);
+ String _ai_string_to_string(const aiString p_string) const;
+ String _ai_anim_string_to_string(const aiString p_string) const;
+ String _ai_raw_string_to_string(const aiString p_string) const;
+ void _import_animation(const String p_path, const Vector<MeshInstance *> p_meshes, const aiScene *p_scene, AnimationPlayer *ap, int32_t p_index, int p_bake_fps, Map<Skeleton *, MeshInstance *> p_skeletons, const Set<String> p_removed_nodes, const Set<String> removed_bones, const Map<String, Map<uint32_t, String> > p_path_morph_mesh_names);
+ void _insert_pivot_anim_track(const Vector<MeshInstance *> p_meshes, const String p_node_name, Vector<const aiNodeAnim *> F, AnimationPlayer *ap, Skeleton *sk, float &length, float ticks_per_second, Ref<Animation> animation, int p_bake_fps, const String &p_path, const aiScene *p_scene);
+ float _get_fbx_fps(int32_t time_mode, const aiScene *p_scene);
+ template <class T>
+ T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time, AssetImportAnimation::Interpolation p_interp);
+ const Transform _ai_matrix_transform(const aiMatrix4x4 p_matrix);
+ void _register_project_setting_import(const String generic, const String import_setting_string, const Vector<String> &exts, List<String> *r_extensions, const bool p_enabled) const;
+
+ struct ImportFormat {
+ Vector<String> extensions;
+ bool is_default;
+ };
+
+protected:
+ static void _bind_methods();
+
+public:
+ EditorSceneImporterAssimp() {
+ Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
+ unsigned int severity = Assimp::Logger::Info | Assimp::Logger::Err | Assimp::Logger::Warn;
+ Assimp::DefaultLogger::get()->attachStream(new AssimpStream(), severity);
+ }
+ ~EditorSceneImporterAssimp() {
+ Assimp::DefaultLogger::kill();
+ }
+
+ virtual void get_extensions(List<String> *r_extensions) const;
+ virtual uint32_t get_import_flags() const;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = NULL);
+ virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps);
+};
+#endif
+#endif
diff --git a/modules/assimp/godot_update_assimp.sh b/modules/assimp/godot_update_assimp.sh
new file mode 100644
index 0000000000..dcf1e6d4a2
--- /dev/null
+++ b/modules/assimp/godot_update_assimp.sh
@@ -0,0 +1,261 @@
+rm -rf ../../thirdparty/assimp
+cd ../../thirdparty/
+git clone https://github.com/assimp/assimp.git
+cd assimp
+rm -rf code/3DSExporter.h
+rm -rf code/3DSLoader.h
+rm -rf code/3MFXmlTags.h
+rm -rf code/ABCImporter.h
+rm -rf code/ACLoader.h
+rm -rf code/AMFImporter_Macro.hpp
+rm -rf code/ASELoader.h
+rm -rf code/assbin_chunks.h
+rm -rf code/AssbinExporter.h
+rm -rf code/AssbinLoader.h
+rm -rf code/AssimpCExport.cpp
+rm -rf code/AssxmlExporter.h
+rm -rf code/B3DImporter.h
+# rm -rf code/BaseProcess.cpp
+# rm -rf code/BaseProcess.h
+# rm -rf code/Bitmap.cpp
+rm -rf code/BlenderBMesh.cpp
+rm -rf code/BlenderBMesh.h
+rm -rf code/BlenderCustomData.cpp
+rm -rf code/BlenderCustomData.h
+rm -rf code/BlenderIntermediate.h
+rm -rf code/BlenderLoader.h
+rm -rf code/BlenderModifier.h
+rm -rf code/BlenderSceneGen.h
+rm -rf code/BlenderTessellator.h
+rm -rf code/BVHLoader.h
+rm -rf code/C4DImporter.h
+# rm -rf code/CalcTangentsProcess.h
+# rm -rf code/CInterfaceIOWrapper.cpp
+# rm -rf code/CInterfaceIOWrapper.h
+rm -rf code/COBLoader.h
+rm -rf code/COBScene.h
+rm -rf code/ColladaExporter.h
+rm -rf code/ColladaLoader.h
+# rm -rf code/ComputeUVMappingProcess.h
+# rm -rf code/ConvertToLHProcess.h
+# rm -rf code/CreateAnimMesh.cpp
+rm -rf code/CSMLoader.h
+rm -rf code/D3MFExporter.h
+rm -rf code/D3MFImporter.h
+rm -rf code/D3MFOpcPackage.h
+# rm -rf code/DeboneProcess.h
+# rm -rf code/DefaultIOStream.cpp
+# rm -rf code/DefaultIOSystem.cpp
+# rm -rf code/DefaultProgressHandler.h
+# rm -rf code/DropFaceNormalsProcess.cpp
+# rm -rf code/DropFaceNormalsProcess.h
+rm -rf code/DXFHelper.h
+rm -rf code/DXFLoader.h
+# rm -rf code/EmbedTexturesProcess.cpp
+# rm -rf code/EmbedTexturesProcess.h
+# rm -rf code/FBXCommon.h
+# rm -rf code/FBXCompileConfig.h
+# rm -rf code/FBXDeformer.cpp
+# rm -rf code/FBXDocumentUtil.cpp
+# rm -rf code/FBXDocumentUtil.h
+# rm -rf code/FBXExporter.h
+# rm -rf code/FBXExportNode.h
+# rm -rf code/FBXExportProperty.h
+# rm -rf code/FBXImporter.cpp
+# rm -rf code/FBXImporter.h
+# rm -rf code/FBXImportSettings.h
+# rm -rf code/FBXMeshGeometry.h
+# rm -rf code/FBXModel.cpp
+# rm -rf code/FBXNodeAttribute.cpp
+# rm -rf code/FBXParser.h
+# rm -rf code/FBXProperties.cpp
+# rm -rf code/FBXProperties.h
+# rm -rf code/FBXTokenizer.cpp
+# rm -rf code/FBXTokenizer.h
+# rm -rf code/FBXUtil.cpp
+# rm -rf code/FBXUtil.h
+# rm -rf code/FileLogStream.h
+# rm -rf code/FindDegenerates.h
+# rm -rf code/FindInstancesProcess.h
+# rm -rf code/FindInvalidDataProcess.h
+rm -rf code/FIReader.hpp
+# rm -rf code/FixNormalsStep.cpp
+# rm -rf code/FixNormalsStep.h
+# rm -rf code/GenFaceNormalsProcess.cpp
+# rm -rf code/GenFaceNormalsProcess.h
+# rm -rf code/GenVertexNormalsProcess.cpp
+# rm -rf code/GenVertexNormalsProcess.h
+rm -rf code/glTF2Asset.h
+rm -rf code/glTF2Asset.inl
+rm -rf code/glTF2AssetWriter.inl
+rm -rf code/glTF2Exporter.cpp
+rm -rf code/glTF2Importer.cpp
+rm -rf code/glTF2AssetWriter.h
+rm -rf code/glTFAsset.h
+rm -rf code/glTFAsset.inl
+rm -rf code/glTFAssetWriter.inl
+rm -rf code/glTFExporter.cpp
+rm -rf code/glTFImporter.cpp
+rm -rf code/glTF2Exporter.h
+rm -rf code/glTF2Importer.h
+rm -rf code/glTFAssetWriter.h
+rm -rf code/glTFExporter.h
+rm -rf code/glTFImporter.h
+rm -rf code/HalfLifeFileData.h
+rm -rf code/HMPFileData.h
+rm -rf code/HMPLoader.h
+rm -rf code/HMPLoader.cpp
+rm -rf code/IFF.h
+# rm -rf code/Importer.h
+# rm -rf code/ImproveCacheLocality.h
+rm -rf code/IRRLoader.h
+rm -rf code/IRRMeshLoader.h
+rm -rf code/IRRShared.h
+# rm -rf code/JoinVerticesProcess.h
+# rm -rf code/LimitBoneWeightsProcess.cpp
+# rm -rf code/LimitBoneWeightsProcess.h
+rm -rf code/LWSLoader.h
+rm -rf code/makefile.mingw
+# rm -rf code/MakeVerboseFormat.cpp
+# rm -rf code/MakeVerboseFormat.h
+# rm -rf code/MaterialSystem.h
+rm -rf code/MD2FileData.h
+rm -rf code/MD2Loader.h
+rm -rf code/MD2NormalTable.h
+rm -rf code/MD3FileData.h
+rm -rf code/MD3Loader.h
+rm -rf code/MD4FileData.h
+rm -rf code/MD5Loader.h
+rm -rf code/MD5Parser.cpp
+rm -rf code/MDCFileData.h
+rm -rf code/MDCLoader.h
+rm -rf code/MDLDefaultColorMap.h
+# rm -rf code/MMDCpp14.h
+# rm -rf code/MMDImporter.h
+rm -rf code/MS3DLoader.h
+rm -rf code/NDOLoader.h
+rm -rf code/NFFLoader.h
+rm -rf code/ObjExporter.h
+rm -rf code/ObjFileImporter.h
+rm -rf code/ObjFileMtlImporter.h
+rm -rf code/ObjFileParser.h
+rm -rf code/ObjTools.h
+rm -rf code/ObjExporter.cpp
+rm -rf code/ObjFileImporter.cpp
+rm -rf code/ObjFileMtlImporter.cpp
+rm -rf code/ObjFileParser.cpp
+rm -rf code/OFFLoader.h
+rm -rf code/OFFLoader.cpp
+rm -rf code/OgreImporter.cpp
+rm -rf code/OgreImporter.h
+rm -rf code/OgreParsingUtils.h
+rm -rf code/OgreXmlSerializer.h
+rm -rf code/OgreXmlSerializer.cpp
+rm -rf code/OgreBinarySerializer.cpp
+rm -rf code/OpenGEXExporter.cpp
+rm -rf code/OpenGEXExporter.h
+rm -rf code/OpenGEXImporter.h
+rm -rf code/OpenGEXStructs.h
+rm -rf code/OpenGEXImporter.cpp
+# rm -rf code/OptimizeGraph.h
+# rm -rf code/OptimizeMeshes.cpp
+# rm -rf code/OptimizeMeshes.h
+rm -rf code/PlyExporter.h
+rm -rf code/PlyLoader.h
+# rm -rf code/PolyTools.h
+# rm -rf code/PostStepRegistry.cpp
+# rm -rf code/PretransformVertices.h
+rm -rf code/Q3BSPFileData.h
+rm -rf code/Q3BSPFileImporter.h
+rm -rf code/Q3BSPFileParser.cpp
+rm -rf code/Q3BSPFileParser.h
+rm -rf code/Q3BSPZipArchive.cpp
+rm -rf code/Q3BSPZipArchive.h
+rm -rf code/Q3DLoader.h
+rm -rf code/Q3DLoader.cpp
+rm -rf code/Q3BSPFileImporter.cpp
+rm -rf code/RawLoader.h
+# rm -rf code/RemoveComments.cpp
+# rm -rf code/RemoveRedundantMaterials.cpp
+# rm -rf code/RemoveRedundantMaterials.h
+# rm -rf code/RemoveVCProcess.h
+# rm -rf code/ScaleProcess.cpp
+# rm -rf code/ScaleProcess.h
+# rm -rf code/scene.cpp
+# rm -rf code/ScenePreprocessor.cpp
+# rm -rf code/ScenePreprocessor.h
+# rm -rf code/ScenePrivate.h
+# rm -rf code/SGSpatialSort.cpp
+rm -rf code/SIBImporter.h
+rm -rf code/SMDLoader.cpp
+# rm -rf code/simd.cpp
+# rm -rf code/simd.h
+# rm -rf code/SortByPTypeProcess.h
+# rm -rf code/SplitByBoneCountProcess.h
+# rm -rf code/SplitLargeMeshes.h
+# rm -rf code/StdOStreamLogStream.h
+rm -rf code/StepExporter.h
+rm -rf code/StepExporter.cpp
+rm -rf code/STLExporter.cpp
+rm -rf code/STLExporter.h
+rm -rf code/STLLoader.h
+rm -rf code/STLLoader.cpp
+# rm -rf code/TargetAnimation.cpp
+# rm -rf code/TargetAnimation.h
+rm -rf code/TerragenLoader.h
+rm -rf code/TerragenLoader.cpp
+# rm -rf code/TextureTransform.h
+# rm -rf code/TriangulateProcess.h
+rm -rf code/UnrealLoader.h
+# rm -rf code/ValidateDataStructure.h
+# rm -rf code/Version.cpp
+# rm -rf code/VertexTriangleAdjacency.cpp
+# rm -rf code/VertexTriangleAdjacency.h
+# rm -rf code/Win32DebugLogStream.h
+rm -rf code/X3DImporter_Macro.hpp
+rm -rf code/X3DImporter_Metadata.cpp
+rm -rf code/X3DImporter_Networking.cpp
+rm -rf code/X3DImporter_Texturing.cpp
+rm -rf code/X3DImporter_Shape.cpp
+rm -rf code/X3DImporter_Rendering.cpp
+rm -rf code/X3DImporter_Postprocess.cpp
+rm -rf code/X3DImporter_Light.cpp
+rm -rf code/X3DImporter_Group.cpp
+rm -rf code/X3DImporter_Geometry3D.cpp
+rm -rf code/X3DImporter_Geometry2D.cpp
+rm -rf code/X3DImporter.cpp
+rm -rf code/X3DExporter.cpp
+rm -rf code/X3DVocabulary.cpp
+rm -rf code/XFileExporter.h
+rm -rf code/XFileExporter.cpp
+rm -rf code/XFileHelper.h
+rm -rf code/XFileHelper.cpp
+rm -rf code/XFileImporter.h
+rm -rf code/XFileImporter.cpp
+rm -rf code/XFileParser.h
+rm -rf code/XFileParser.cpp
+rm -rf code/XGLLoader.h
+rm -rf code/XGLLoader.cpp
+rm -rf code/Importer
+rm -rf .git
+rm -rf cmake-modules
+rm -rf doc
+rm -rf packaging
+rm -rf port
+rm -rf samples
+rm -rf scripts
+rm -rf test
+rm -rf tools
+rm -rf contrib/zlib
+rm -rf contrib/android-cmake
+rm -rf contrib/gtest
+rm -rf contrib/clipper
+rm -rf contrib/irrXML
+rm -rf contrib/Open3DGC
+rm -rf contrib/openddlparser
+rm -rf contrib/poly2tri
+rm -rf contrib/rapidjson
+rm -rf contrib/unzip
+rm -rf contrib/zip
+rm -rf contrib/stb_image
+rm .travis*
diff --git a/modules/assimp/register_types.cpp b/modules/assimp/register_types.cpp
new file mode 100644
index 0000000000..0afb1e72bf
--- /dev/null
+++ b/modules/assimp/register_types.cpp
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* register_types.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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"
+
+#include "editor/editor_node.h"
+#include "editor_scene_importer_assimp.h"
+
+#ifdef TOOLS_ENABLED
+static void _editor_init() {
+ Ref<EditorSceneImporterAssimp> import_assimp;
+ import_assimp.instance();
+ ResourceImporterScene::get_singleton()->add_importer(import_assimp);
+}
+#endif
+
+void register_assimp_types() {
+
+#ifdef TOOLS_ENABLED
+ ClassDB::register_class<EditorSceneImporterAssimp>();
+ EditorNode::add_init_callback(_editor_init);
+#endif
+}
+
+void unregister_assimp_types() {
+}
diff --git a/modules/assimp/register_types.h b/modules/assimp/register_types.h
new file mode 100644
index 0000000000..f841cd26b2
--- /dev/null
+++ b/modules/assimp/register_types.h
@@ -0,0 +1,32 @@
+/*************************************************************************/
+/* register_types.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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_assimp_types();
+void unregister_assimp_types();
diff --git a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
index a4dc61d0bc..1f91349f32 100644
--- a/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
+++ b/modules/bullet/doc_classes/BulletPhysicsDirectBodyState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.1">
+<class name="BulletPhysicsDirectBodyState" inherits="PhysicsDirectBodyState" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/bullet/doc_classes/BulletPhysicsServer.xml b/modules/bullet/doc_classes/BulletPhysicsServer.xml
index 1486936cf4..8adc659b2c 100644
--- a/modules/bullet/doc_classes/BulletPhysicsServer.xml
+++ b/modules/bullet/doc_classes/BulletPhysicsServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.1">
+<class name="BulletPhysicsServer" inherits="PhysicsServer" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 1aba31f03d..b590d63167 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -510,16 +510,17 @@ void HeightMapShapeBullet::set_data(const Variant &p_data) {
// Compute min and max heights if not specified.
if (!d.has("min_height") && !d.has("max_height")) {
- PoolVector<real_t>::Read r = heights.read();
- int heights_size = heights.size();
+ PoolVector<real_t>::Read r = l_heights.read();
+ int heights_size = l_heights.size();
for (int i = 0; i < heights_size; ++i) {
real_t h = r[i];
- if (h < l_min_height)
+ if (h < l_min_height) {
l_min_height = h;
- else if (h > l_max_height)
+ } else if (h > l_max_height) {
l_max_height = h;
+ }
}
}
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index f274fff3f3..775ec67ba6 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -806,8 +806,8 @@ CSGBrush *CSGMesh::_build_brush() {
uvw[as + j + 1] = uv[1];
uvw[as + j + 2] = uv[2];
- sw[j / 3] = !flat;
- mw[j / 3] = mat;
+ sw[(as + j) / 3] = !flat;
+ mw[(as + j) / 3] = mat;
}
} else {
int as = vertices.size();
@@ -849,8 +849,8 @@ CSGBrush *CSGMesh::_build_brush() {
uvw[as + j + 1] = uv[1];
uvw[as + j + 2] = uv[2];
- sw[j / 3] = !flat;
- mw[j / 3] = mat;
+ sw[(as + j) / 3] = !flat;
+ mw[(as + j) / 3] = mat;
}
}
}
diff --git a/modules/csg/doc_classes/CSGBox.xml b/modules/csg/doc_classes/CSGBox.xml
index 5ec7b5089d..1684850f0a 100644
--- a/modules/csg/doc_classes/CSGBox.xml
+++ b/modules/csg/doc_classes/CSGBox.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGBox" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGBox" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
A CSG Box shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGCombiner.xml b/modules/csg/doc_classes/CSGCombiner.xml
index 69c5df5840..819a4a3a22 100644
--- a/modules/csg/doc_classes/CSGCombiner.xml
+++ b/modules/csg/doc_classes/CSGCombiner.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCombiner" inherits="CSGShape" category="Core" version="3.1">
+<class name="CSGCombiner" inherits="CSGShape" category="Core" version="3.2">
<brief_description>
A CSG node that allows you to combine other CSG modifiers.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGCylinder.xml b/modules/csg/doc_classes/CSGCylinder.xml
index 92b170ed1f..50a88d6773 100644
--- a/modules/csg/doc_classes/CSGCylinder.xml
+++ b/modules/csg/doc_classes/CSGCylinder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGCylinder" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGCylinder" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
A CSG Cylinder shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGMesh.xml b/modules/csg/doc_classes/CSGMesh.xml
index 58e2bc1c4b..fc9815d7c0 100644
--- a/modules/csg/doc_classes/CSGMesh.xml
+++ b/modules/csg/doc_classes/CSGMesh.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGMesh" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGMesh" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
A CSG Mesh shape that uses a mesh resource.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGPolygon.xml b/modules/csg/doc_classes/CSGPolygon.xml
index a33e5557cb..ae75f7e01b 100644
--- a/modules/csg/doc_classes/CSGPolygon.xml
+++ b/modules/csg/doc_classes/CSGPolygon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPolygon" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGPolygon" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
Extrudes a 2D polygon shape to create a 3D mesh.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGPrimitive.xml b/modules/csg/doc_classes/CSGPrimitive.xml
index 2591bab7e3..502a8230e4 100644
--- a/modules/csg/doc_classes/CSGPrimitive.xml
+++ b/modules/csg/doc_classes/CSGPrimitive.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGPrimitive" inherits="CSGShape" category="Core" version="3.1">
+<class name="CSGPrimitive" inherits="CSGShape" category="Core" version="3.2">
<brief_description>
Base class for CSG primitives.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGShape.xml b/modules/csg/doc_classes/CSGShape.xml
index d304d0179f..ccfc5a04c0 100644
--- a/modules/csg/doc_classes/CSGShape.xml
+++ b/modules/csg/doc_classes/CSGShape.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGShape" inherits="VisualInstance" category="Core" version="3.1">
+<class name="CSGShape" inherits="VisualInstance" category="Core" version="3.2">
<brief_description>
The CSG base class.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGSphere.xml b/modules/csg/doc_classes/CSGSphere.xml
index a0069879cb..088c9f14eb 100644
--- a/modules/csg/doc_classes/CSGSphere.xml
+++ b/modules/csg/doc_classes/CSGSphere.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGSphere" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGSphere" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
A CSG Sphere shape.
</brief_description>
diff --git a/modules/csg/doc_classes/CSGTorus.xml b/modules/csg/doc_classes/CSGTorus.xml
index 187d71a2fa..946637bd2c 100644
--- a/modules/csg/doc_classes/CSGTorus.xml
+++ b/modules/csg/doc_classes/CSGTorus.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSGTorus" inherits="CSGPrimitive" category="Core" version="3.1">
+<class name="CSGTorus" inherits="CSGPrimitive" category="Core" version="3.2">
<brief_description>
A CSG Torus shape.
</brief_description>
diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
index c9a7d96ae7..c1bec533dd 100644
--- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
+++ b/modules/enet/doc_classes/NetworkedMultiplayerENet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1">
+<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2">
<brief_description>
PacketPeer implementation using the ENet library.
</brief_description>
diff --git a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
index be86ff0541..afb014d608 100644
--- a/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
+++ b/modules/gdnative/doc_classes/ARVRInterfaceGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.1">
+<class name="ARVRInterfaceGDNative" inherits="ARVRInterface" category="Core" version="3.2">
<brief_description>
GDNative wrapper for an ARVR interface
</brief_description>
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index ca0457623f..e5a59aad07 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDNative" inherits="Reference" category="Core" version="3.1">
+<class name="GDNative" inherits="Reference" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 754a6d2514..ba5278d440 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.1">
+<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml
index 4433179726..ba481a6d6e 100644
--- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml
+++ b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1">
+<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
index 37d5b79e7a..c50f9eee22 100644
--- a/modules/gdnative/doc_classes/NativeScript.xml
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NativeScript" inherits="Script" category="Core" version="3.1">
+<class name="NativeScript" inherits="Script" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/PacketPeerGDNative.xml b/modules/gdnative/doc_classes/PacketPeerGDNative.xml
index 0ae54bc9c7..f4d7d22f5b 100644
--- a/modules/gdnative/doc_classes/PacketPeerGDNative.xml
+++ b/modules/gdnative/doc_classes/PacketPeerGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerGDNative" inherits="PacketPeer" category="Core" version="3.1">
+<class name="PacketPeerGDNative" inherits="PacketPeer" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml
index 1876d06c20..8510708124 100644
--- a/modules/gdnative/doc_classes/PluginScript.xml
+++ b/modules/gdnative/doc_classes/PluginScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PluginScript" inherits="Script" category="Core" version="3.1">
+<class name="PluginScript" inherits="Script" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml b/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml
index 61a7f60499..8e7f4698ff 100644
--- a/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml
+++ b/modules/gdnative/doc_classes/ResourceFormatLoaderVideoStreamGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceFormatLoaderVideoStreamGDNative" inherits="ResourceFormatLoader" category="Core" version="3.1">
+<class name="ResourceFormatLoaderVideoStreamGDNative" inherits="ResourceFormatLoader" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/StreamPeerGDNative.xml b/modules/gdnative/doc_classes/StreamPeerGDNative.xml
index d86cd2c25a..eddebf4889 100644
--- a/modules/gdnative/doc_classes/StreamPeerGDNative.xml
+++ b/modules/gdnative/doc_classes/StreamPeerGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerGDNative" inherits="StreamPeer" category="Core" version="3.1">
+<class name="StreamPeerGDNative" inherits="StreamPeer" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/doc_classes/VideoStreamGDNative.xml b/modules/gdnative/doc_classes/VideoStreamGDNative.xml
index 20575c768b..d5c5ed7ccf 100644
--- a/modules/gdnative/doc_classes/VideoStreamGDNative.xml
+++ b/modules/gdnative/doc_classes/VideoStreamGDNative.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamGDNative" inherits="VideoStream" category="Core" version="3.1">
+<class name="VideoStreamGDNative" inherits="VideoStream" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index b99c5d31ab..7eb4294732 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -279,7 +279,7 @@ List<ClassAPI> generate_c_api_classes() {
MethodInfo &method_info = m->get();
//method name
- method_api.method_name = m->get().name;
+ method_api.method_name = method_info.name;
//method return type
if (method_api.method_name.find(":") != -1) {
method_api.return_type = method_api.method_name.get_slice(":", 1);
@@ -321,6 +321,8 @@ List<ClassAPI> generate_c_api_classes() {
arg_type = arg_info.hint_string;
} else if (arg_info.type == Variant::NIL) {
arg_type = "Variant";
+ } else if (arg_info.type == Variant::OBJECT) {
+ arg_type = arg_info.class_name;
} else {
arg_type = Variant::get_type_name(arg_info.type);
}
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 4cefdbd7cb..46796c68eb 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScript" inherits="Script" category="Core" version="3.1">
+<class name="GDScript" inherits="Script" category="Core" version="3.2">
<brief_description>
A script implemented in the GDScript programming language.
</brief_description>
diff --git a/modules/gdscript/doc_classes/GDScriptFunctionState.xml b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
index c205cedef5..f38f39b612 100644
--- a/modules/gdscript/doc_classes/GDScriptFunctionState.xml
+++ b/modules/gdscript/doc_classes/GDScriptFunctionState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.1">
+<class name="GDScriptFunctionState" inherits="Reference" category="Core" version="3.2">
<brief_description>
State of a function call after yielding.
</brief_description>
diff --git a/modules/gdscript/doc_classes/GDScriptNativeClass.xml b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
index 90935b5c22..e86b69c31c 100644
--- a/modules/gdscript/doc_classes/GDScriptNativeClass.xml
+++ b/modules/gdscript/doc_classes/GDScriptNativeClass.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.1">
+<class name="GDScriptNativeClass" inherits="Reference" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 5f521c682a..ae67521749 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -139,17 +139,32 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.native_type = result.script_type->get_instance_base_type();
} break;
case GDScriptParser::DataType::CLASS: {
- result.kind = GDScriptDataType::GDSCRIPT;
- if (!p_datatype.class_type->owner) {
- result.script_type = Ref<GDScript>(main_script);
- } else {
- result.script_type = class_map[p_datatype.class_type->name];
+ // Locate class by constructing the path to it and following that path
+ GDScriptParser::ClassNode *class_type = p_datatype.class_type;
+ List<StringName> names;
+ while (class_type->owner) {
+ names.push_back(class_type->name);
+ class_type = class_type->owner;
}
- result.native_type = result.script_type->get_instance_base_type();
+
+ Ref<GDScript> script = Ref<GDScript>(main_script);
+ while (names.back()) {
+ if (!script->subclasses.has(names.back()->get())) {
+ ERR_PRINT("Parser bug: Cannot locate datatype class.");
+ result.has_type = false;
+ return GDScriptDataType();
+ }
+ script = script->subclasses[names.back()->get()];
+ names.pop_back();
+ }
+
+ result.kind = GDScriptDataType::GDSCRIPT;
+ result.script_type = script;
+ result.native_type = script->get_instance_base_type();
} break;
default: {
ERR_PRINT("Parser bug: converting unresolved type.");
- result.has_type = false;
+ return GDScriptDataType();
}
}
@@ -460,12 +475,14 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
codegen.alloc_stack(slevel);
}
- switch (cn->cast_type.kind) {
- case GDScriptParser::DataType::BUILTIN: {
+ GDScriptDataType cast_type = _gdtype_from_datatype(cn->cast_type);
+
+ switch (cast_type.kind) {
+ case GDScriptDataType::BUILTIN: {
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);
codegen.opcodes.push_back(cn->cast_type.builtin_type);
} break;
- case GDScriptParser::DataType::NATIVE: {
+ case GDScriptDataType::NATIVE: {
int class_idx;
if (GDScriptLanguage::get_singleton()->get_global_map().has(cn->cast_type.native_type)) {
@@ -478,32 +495,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_NATIVE); // perform operator
codegen.opcodes.push_back(class_idx); // variable type
} break;
- case GDScriptParser::DataType::CLASS: {
-
- Variant script;
- int idx = -1;
- if (!cn->cast_type.class_type->owner) {
- script = codegen.script;
- } else {
- StringName name = cn->cast_type.class_type->name;
- if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) {
- idx = codegen.get_name_map_pos(name);
- idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS;
- } else {
- script = class_map[name];
- }
- }
-
- if (idx < 0) {
- idx = codegen.get_constant_pos(script);
- idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access)
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_CAST_TO_SCRIPT); // perform operator
- codegen.opcodes.push_back(idx); // variable type
- } break;
- case GDScriptParser::DataType::SCRIPT:
- case GDScriptParser::DataType::GDSCRIPT: {
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
Variant script = cn->cast_type.script_type;
int idx = codegen.get_constant_pos(script);
@@ -1149,18 +1142,18 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
if (src_address_b < 0)
return -1;
- GDScriptParser::DataType assign_type = on->arguments[0]->get_datatype();
+ GDScriptDataType assign_type = _gdtype_from_datatype(on->arguments[0]->get_datatype());
if (assign_type.has_type && !on->arguments[1]->get_datatype().has_type) {
// Typed assignment
switch (assign_type.kind) {
- case GDScriptParser::DataType::BUILTIN: {
+ case GDScriptDataType::BUILTIN: {
codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); // perform operator
codegen.opcodes.push_back(assign_type.builtin_type); // variable type
codegen.opcodes.push_back(dst_address_a); // argument 1
codegen.opcodes.push_back(src_address_b); // argument 2
} break;
- case GDScriptParser::DataType::NATIVE: {
+ case GDScriptDataType::NATIVE: {
int class_idx;
if (GDScriptLanguage::get_singleton()->get_global_map().has(assign_type.native_type)) {
@@ -1175,34 +1168,8 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
codegen.opcodes.push_back(dst_address_a); // argument 1
codegen.opcodes.push_back(src_address_b); // argument 2
} break;
- case GDScriptParser::DataType::CLASS: {
-
- Variant script;
- int idx = -1;
- if (!assign_type.class_type->owner) {
- script = codegen.script;
- } else {
- StringName name = assign_type.class_type->name;
- if (codegen.script->subclasses.has(name) && class_map[name] == codegen.script->subclasses[name]) {
- idx = codegen.get_name_map_pos(name);
- idx |= GDScriptFunction::ADDR_TYPE_CLASS_CONSTANT << GDScriptFunction::ADDR_BITS;
- } else {
- script = class_map[name];
- }
- }
-
- if (idx < 0) {
- idx = codegen.get_constant_pos(script);
- idx |= GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS; //make it a local constant (faster access)
- }
-
- codegen.opcodes.push_back(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT); // perform operator
- codegen.opcodes.push_back(idx); // variable type
- codegen.opcodes.push_back(dst_address_a); // argument 1
- codegen.opcodes.push_back(src_address_b); // argument 2
- } break;
- case GDScriptParser::DataType::SCRIPT:
- case GDScriptParser::DataType::GDSCRIPT: {
+ case GDScriptDataType::SCRIPT:
+ case GDScriptDataType::GDSCRIPT: {
Variant script = assign_type.script_type;
int idx = codegen.get_constant_pos(script);
@@ -1845,22 +1812,21 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return OK;
}
-Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+
+ parsing_classes.insert(p_script);
if (p_class->owner && p_class->owner->owner) {
// Owner is not root
- StringName owner_name = p_class->owner->name;
- if (!parsed_classes.has(owner_name)) {
- if (parsing_classes.has(owner_name)) {
- _set_error("Cyclic class reference for '" + String(owner_name) + "'.", p_class);
+ if (!parsed_classes.has(p_script->_owner)) {
+ if (parsing_classes.has(p_script->_owner)) {
+ _set_error("Cyclic class reference for '" + String(p_class->name) + "'.", p_class);
return ERR_PARSE_ERROR;
}
- parsing_classes.insert(owner_name);
- Error err = _parse_class_level(class_map[owner_name].ptr(), class_map[owner_name]->_owner, p_class->owner, p_keep_state);
+ Error err = _parse_class_level(p_script->_owner, p_class->owner, p_keep_state);
if (err) {
return err;
}
- parsing_classes.erase(owner_name);
}
}
@@ -1878,47 +1844,26 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->_signals.clear();
p_script->initializer = NULL;
- p_script->subclasses.clear();
- p_script->_owner = p_owner;
p_script->tool = p_class->tool;
p_script->name = p_class->name;
Ref<GDScriptNativeClass> native;
+ GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type);
// Inheritance
- switch (p_class->base_type.kind) {
- case GDScriptParser::DataType::CLASS: {
- StringName base_name = p_class->base_type.class_type->name;
- // Make sure dependency is parsed first
- if (!parsed_classes.has(base_name)) {
- if (parsing_classes.has(base_name)) {
- _set_error("Cyclic class reference for '" + String(base_name) + "'.", p_class);
- return ERR_PARSE_ERROR;
- }
- parsing_classes.insert(base_name);
- Error err = _parse_class_level(class_map[base_name].ptr(), class_map[base_name]->_owner, p_class->base_type.class_type, p_keep_state);
- if (err) {
- return err;
- }
- parsing_classes.erase(base_name);
- }
- Ref<GDScript> base = class_map[base_name];
- p_script->base = base;
- p_script->_base = p_script->base.ptr();
- p_script->member_indices = base->member_indices;
- } break;
- case GDScriptParser::DataType::GDSCRIPT: {
- Ref<GDScript> base = p_class->base_type.script_type;
- p_script->base = base;
- p_script->_base = p_script->base.ptr();
- p_script->member_indices = base->member_indices;
- } break;
- case GDScriptParser::DataType::NATIVE: {
- int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_class->base_type.native_type];
+ switch (base_type.kind) {
+ case GDScriptDataType::NATIVE: {
+ int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
ERR_FAIL_COND_V(native.is_null(), ERR_BUG);
p_script->native = native;
} break;
+ case GDScriptDataType::GDSCRIPT: {
+ Ref<GDScript> base = base_type.script_type;
+ p_script->base = base;
+ p_script->_base = base.ptr();
+ p_script->member_indices = base->member_indices;
+ } break;
default: {
_set_error("Parser bug: invalid inheritance.", p_class);
return ERR_BUG;
@@ -2012,24 +1957,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->_signals[name] = p_class->_signals[i].arguments;
}
- if (p_class->owner) {
- parsed_classes.insert(p_class->name);
- if (parsing_classes.has(p_class->name)) {
- parsing_classes.erase(p_class->name);
- }
- }
+ parsed_classes.insert(p_script);
+ parsing_classes.erase(p_script);
//parse sub-classes
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
- Ref<GDScript> subclass = class_map[name];
+ GDScript *subclass = p_script->subclasses[name].ptr();
// Subclass might still be parsing, just skip it
- if (!parsed_classes.has(name) && !parsing_classes.has(name)) {
- parsing_classes.insert(name);
- Error err = _parse_class_level(subclass.ptr(), p_script, p_class->subclasses[i], p_keep_state);
+ if (!parsed_classes.has(subclass) && !parsing_classes.has(subclass)) {
+ Error err = _parse_class_level(subclass, p_class->subclasses[i], p_keep_state);
if (err)
return err;
}
@@ -2040,7 +1980,6 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
#endif
p_script->constants.insert(name, subclass); //once parsed, goes to the list of constants
- p_script->subclasses.insert(name, subclass);
}
return OK;
@@ -2139,9 +2078,9 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
- Ref<GDScript> subclass = class_map[name];
+ GDScript *subclass = p_script->subclasses[name].ptr();
- Error err = _parse_class_blocks(subclass.ptr(), p_class->subclasses[i], p_keep_state);
+ Error err = _parse_class_blocks(subclass, p_class->subclasses[i], p_keep_state);
if (err) {
return err;
}
@@ -2151,7 +2090,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
return OK;
}
-void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
Map<StringName, Ref<GDScript> > old_subclasses;
@@ -2159,6 +2098,8 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
old_subclasses = p_script->subclasses;
}
+ p_script->subclasses.clear();
+
for (int i = 0; i < p_class->subclasses.size(); i++) {
StringName name = p_class->subclasses[i]->name;
@@ -2170,10 +2111,10 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
subclass.instance();
}
- subclass->_owner = const_cast<GDScript *>(p_script);
- class_map.insert(name, subclass);
+ subclass->_owner = p_script;
+ p_script->subclasses.insert(name, subclass);
- _make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state);
+ _make_scripts(subclass.ptr(), p_class->subclasses[i], false);
}
}
@@ -2192,7 +2133,8 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
// Create scripts for subclasses beforehand so they can be referenced
_make_scripts(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
- Error err = _parse_class_level(p_script, NULL, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
+ p_script->_owner = NULL;
+ Error err = _parse_class_level(p_script, static_cast<const GDScriptParser::ClassNode *>(root), p_keep_state);
if (err)
return err;
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 8440807a56..2cf630ba72 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -38,9 +38,8 @@
class GDScriptCompiler {
const GDScriptParser *parser;
- Map<StringName, Ref<GDScript> > class_map;
- Set<StringName> parsed_classes;
- Set<StringName> parsing_classes;
+ Set<GDScript *> parsed_classes;
+ Set<GDScript *> parsing_classes;
GDScript *main_script;
struct CodeGen {
@@ -149,9 +148,9 @@ class GDScriptCompiler {
int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false);
Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
- Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
- void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ void _make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line;
int err_column;
StringName source;
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 44d44462ca..46c9efd54f 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -768,11 +768,30 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
(void)VariantParser::parse(&ss, r_ret, errs, line);
} break;
case VAR_TO_BYTES: {
- VALIDATE_ARG_COUNT(1);
+ bool full_objects = false;
+ if (p_arg_count < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_ret = Variant();
+ return;
+ } else if (p_arg_count > 2) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 2;
+ r_ret = Variant();
+ } else if (p_arg_count == 2) {
+ if (p_args[1]->get_type() != Variant::BOOL) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::BOOL;
+ r_ret = Variant();
+ return;
+ }
+ full_objects = *p_args[1];
+ }
PoolByteArray barr;
int len;
- Error err = encode_variant(*p_args[0], NULL, len);
+ Error err = encode_variant(*p_args[0], NULL, len, full_objects);
if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -784,15 +803,35 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(*p_args[0], w.ptr(), len);
+ encode_variant(*p_args[0], w.ptr(), len, full_objects);
}
r_ret = barr;
} break;
case BYTES_TO_VAR: {
- VALIDATE_ARG_COUNT(1);
+ bool allow_objects = false;
+ if (p_arg_count < 1) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 1;
+ r_ret = Variant();
+ return;
+ } else if (p_arg_count > 2) {
+ r_error.error = Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument = 2;
+ r_ret = Variant();
+ } else if (p_arg_count == 2) {
+ if (p_args[1]->get_type() != Variant::BOOL) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::BOOL;
+ r_ret = Variant();
+ return;
+ }
+ allow_objects = *p_args[1];
+ }
+
if (p_args[0]->get_type() != Variant::POOL_BYTE_ARRAY) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
- r_error.argument = 0;
+ r_error.argument = 1;
r_error.expected = Variant::POOL_BYTE_ARRAY;
r_ret = Variant();
return;
@@ -802,7 +841,7 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
Variant ret;
{
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) {
r_ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
@@ -1805,13 +1844,15 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
} break;
case VAR_TO_BYTES: {
- MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT));
+ MethodInfo mi("var2bytes", PropertyInfo(Variant::NIL, "var", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), PropertyInfo(Variant::BOOL, "full_objects"));
+ mi.default_arguments.push_back(false);
mi.return_val.type = Variant::POOL_BYTE_ARRAY;
return mi;
} break;
case BYTES_TO_VAR: {
- MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"));
+ MethodInfo mi(Variant::NIL, "bytes2var", PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes"), PropertyInfo(Variant::BOOL, "allow_objects"));
+ mi.default_arguments.push_back(false);
mi.return_val.type = Variant::NIL;
mi.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
return mi;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index da69181a43..e75b8a14a3 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -777,7 +777,8 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
}
_add_warning(GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, -1, identifier.operator String());
}
- } // fallthrough
+ FALLTHROUGH;
+ }
case GDScriptTokenizer::TK_OP_ASSIGN: {
lv->assignments += 1;
lv->usages--; // Assignment is not really usage
@@ -2225,6 +2226,8 @@ GDScriptParser::PatternNode *GDScriptParser::_parse_pattern(bool p_static) {
void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static) {
int indent_level = tab_level.back()->get();
+ p_block->has_return = true;
+
while (true) {
while (tokenizer->get_token() == GDScriptTokenizer::TK_NEWLINE && _parse_newline())
@@ -2282,8 +2285,8 @@ void GDScriptParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBran
current_block = p_block;
- if (catch_all && branch->body->has_return) {
- p_block->has_return = true;
+ if (!branch->body->has_return) {
+ p_block->has_return = false;
}
p_branches.push_back(branch);
@@ -3634,7 +3637,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
return;
}
- }; //fallthrough to function
+ FALLTHROUGH;
+ }
case GDScriptTokenizer::TK_PR_FUNCTION: {
bool _static = false;
@@ -4084,7 +4088,8 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
break;
}
- }; //fallthrough to use the same
+ FALLTHROUGH;
+ }
case Variant::REAL: {
if (tokenizer->get_token() == GDScriptTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier() == "EASE") {
@@ -4509,6 +4514,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
#ifdef DEBUG_ENABLED
_add_warning(GDScriptWarning::DEPRECATED_KEYWORD, tokenizer->get_token_line(), "slave", "puppet");
#endif
+ FALLTHROUGH;
case GDScriptTokenizer::TK_PR_PUPPET: {
//may be fallthrough from export, ignore if so
@@ -4576,7 +4582,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
continue;
} break;
case GDScriptTokenizer::TK_PR_VAR: {
- //variale declaration and (eventual) initialization
+ // variable declaration and (eventual) initialization
ClassNode::Member member;
@@ -5288,7 +5294,8 @@ String GDScriptParser::DataType::to_string() const {
if (!gds_class.empty()) {
return gds_class;
}
- } // fallthrough
+ FALLTHROUGH;
+ }
case SCRIPT: {
if (is_meta_type) {
return script_type->get_class_name().operator String();
@@ -8044,7 +8051,8 @@ void GDScriptParser::_check_block_types(BlockNode *p_block) {
if (cn->value.get_type() == Variant::STRING) {
break;
}
- } // falthrough
+ FALLTHROUGH;
+ }
default: {
_mark_line_as_safe(statement->line);
_reduce_node_type(statement); // Test for safety anyway
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 8b22d6f085..abc739d645 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -744,7 +744,7 @@ void GDScriptTokenizerText::_advance() {
}
INCPOS(1);
is_node_path = true;
-
+ FALLTHROUGH;
case '\'':
case '"': {
@@ -1199,7 +1199,8 @@ Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer)
Variant v;
int len;
- Error err = decode_variant(v, b, total_len, &len);
+ // An object cannot be constant, never decode objects
+ Error err = decode_variant(v, b, total_len, &len, false);
if (err)
return err;
b += len;
@@ -1367,11 +1368,12 @@ Vector<uint8_t> GDScriptTokenizerBuffer::parse_code_string(const String &p_code)
for (Map<int, Variant>::Element *E = rev_constant_map.front(); E; E = E->next()) {
int len;
- Error err = encode_variant(E->get(), NULL, len);
+ // Objects cannot be constant, never encode objects
+ Error err = encode_variant(E->get(), NULL, len, false);
ERR_FAIL_COND_V(err != OK, Vector<uint8_t>());
int pos = buf.size();
buf.resize(pos + len);
- encode_variant(E->get(), &buf.write[pos], len);
+ encode_variant(E->get(), &buf.write[pos], len, false);
}
for (Map<int, uint32_t>::Element *E = rev_line_map.front(); E; E = E->next()) {
diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml
index 2ea116d79b..655be4eb20 100644
--- a/modules/gridmap/doc_classes/GridMap.xml
+++ b/modules/gridmap/doc_classes/GridMap.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GridMap" inherits="Spatial" category="Core" version="3.1">
+<class name="GridMap" inherits="Spatial" category="Core" version="3.2">
<brief_description>
Node for 3D tile-based maps.
</brief_description>
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 359d654433..0a75ad4784 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.1">
+<class name="MobileVRInterface" inherits="ARVRInterface" category="Core" version="3.2">
<brief_description>
Generic mobile VR implementation
</brief_description>
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index e33b238f45..dfdb4a0b3a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1577,7 +1577,7 @@ MonoObject *CSharpInstance::_internal_new_managed() {
// Search the constructor first, to fail with an error if it's not found before allocating anything else.
GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
if (ctor == NULL) {
- ERR_PRINTS("Cannot create script instance because the class does not define a default constructor: " + script->get_path());
+ ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + script->get_path());
ERR_EXPLAIN("Constructor not found");
ERR_FAIL_V(NULL);
@@ -1966,7 +1966,7 @@ bool CSharpScript::_update_exports() {
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
if (ctor == NULL) {
- ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a default constructor: " + get_path());
+ ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a parameterless constructor: " + get_path());
ERR_EXPLAIN("Constructor not found");
ERR_FAIL_V(NULL);
@@ -2460,7 +2460,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
if (ctor == NULL) {
if (p_argcount == 0) {
- ERR_PRINTS("Cannot create script instance because the class does not define a default constructor: " + get_path());
+ ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + get_path());
}
ERR_EXPLAIN("Constructor not found");
diff --git a/modules/mono/doc_classes/@C#.xml b/modules/mono/doc_classes/@C#.xml
index 082bc30fd8..a821713d0d 100644
--- a/modules/mono/doc_classes/@C#.xml
+++ b/modules/mono/doc_classes/@C#.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="@C#" category="Core" version="3.1">
+<class name="@C#" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index a1f7399653..7f22388132 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="CSharpScript" inherits="Script" category="Core" version="3.1">
+<class name="CSharpScript" inherits="Script" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
index 921c1ca825..21835e639c 100644
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ b/modules/mono/doc_classes/GodotSharp.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" category="Core" version="3.1">
+<class name="GodotSharp" inherits="Object" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index a6b5c1535b..84e2303cf6 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -98,7 +98,7 @@
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(7)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(8)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
@@ -277,7 +277,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
} else if (code_tag) {
xml_output.append("[");
pos = brk_pos + 1;
- } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ")) {
+ } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) {
String link_target = tag.substr(tag.find(" ") + 1, tag.length());
String link_tag = tag.substr(0, tag.find(" "));
@@ -386,6 +386,97 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
xml_output.append(link_target);
xml_output.append("</c>");
}
+ } else if (link_tag == "const") {
+ if (!target_itype || !target_itype->is_object_type) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (target_itype) {
+ OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data());
+ } else {
+ OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data());
+ }
+ }
+
+ // TODO Map what we can
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) {
+ String target_name = (String)target_cname;
+
+ // Try to find as a global constant
+ const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants);
+
+ if (target_iconst) {
+ // Found global constant
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE "." BINDINGS_GLOBAL_SCOPE_CLASS ".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ // Try to find as global enum constant
+ const EnumInterface *target_ienum = NULL;
+
+ for (const List<EnumInterface>::Element *E = global_enums.front(); E; E = E->next()) {
+ target_ienum = &E->get();
+ target_iconst = find_constant_by_name(target_name, target_ienum->constants);
+ if (target_iconst)
+ break;
+ }
+
+ if (target_iconst) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_ienum->cname);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve global constant reference in documentation: " + link_target);
+
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ }
+ }
+ } else {
+ String target_name = (String)target_cname;
+
+ // Try to find the constant in the current class
+ const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants);
+
+ if (target_iconst) {
+ // Found constant in current class
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ // Try to find as enum constant in the current class
+ const EnumInterface *target_ienum = NULL;
+
+ for (const List<EnumInterface>::Element *E = target_itype->enums.front(); E; E = E->next()) {
+ target_ienum = &E->get();
+ target_iconst = find_constant_by_name(target_name, target_ienum->constants);
+ if (target_iconst)
+ break;
+ }
+
+ if (target_iconst) {
+ xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
+ xml_output.append(target_itype->proxy_name);
+ xml_output.append(".");
+ xml_output.append(target_ienum->cname);
+ xml_output.append(".");
+ xml_output.append(target_iconst->proxy_name);
+ xml_output.append("\"/>");
+ } else {
+ ERR_PRINTS("Cannot resolve constant reference in documentation: " + link_target);
+
+ xml_output.append("<c>");
+ xml_output.append(link_target);
+ xml_output.append("</c>");
+ }
+ }
+ }
}
pos = brk_end + 1;
@@ -414,7 +505,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
} else if (tag == "Nil") {
xml_output.append("<see langword=\"null\"/>");
} else if (tag.begins_with("@")) {
- // @Global Scope, @GDScript, etc
+ // @GlobalScope, @GDScript, etc
xml_output.append("<c>");
xml_output.append(tag);
xml_output.append("</c>");
@@ -1912,20 +2003,13 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
String vararg_arg = "arg" + argc_str;
String real_argc_str = itos(p_imethod.arguments.size() - 1); // Arguments count without vararg
- p_output.push_back("\tVector<Variant> varargs;\n"
- "\tint vararg_length = mono_array_length(");
+ p_output.push_back("\tint vararg_length = mono_array_length(");
p_output.push_back(vararg_arg);
p_output.push_back(");\n\tint total_length = ");
p_output.push_back(real_argc_str);
- p_output.push_back(" + vararg_length;\n\t");
- p_output.push_back(err_fail_macro);
- p_output.push_back("(varargs.resize(vararg_length) != OK");
- p_output.push_back(fail_ret);
- p_output.push_back(");\n\tVector<Variant*> " C_LOCAL_PTRCALL_ARGS ";\n\t");
- p_output.push_back(err_fail_macro);
- p_output.push_back("(call_args.resize(total_length) != OK");
- p_output.push_back(fail_ret);
- p_output.push_back(");\n");
+ p_output.push_back(" + vararg_length;\n"
+ "\tArgumentsVector<Variant> varargs(vararg_length);\n"
+ "\tArgumentsVector<const Variant *> " C_LOCAL_PTRCALL_ARGS "(total_length);\n");
p_output.push_back(c_in_statements);
p_output.push_back("\tfor (int i = 0; i < vararg_length; i++) " OPEN_BLOCK
"\t\tMonoObject* elem = mono_array_get(");
@@ -1934,7 +2018,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
"\t\tvarargs.set(i, GDMonoMarshal::mono_object_to_variant(elem));\n"
"\t\t" C_LOCAL_PTRCALL_ARGS ".set(");
p_output.push_back(real_argc_str);
- p_output.push_back(" + i, &varargs.write[i]);\n\t" CLOSE_BLOCK);
+ p_output.push_back(" + i, &varargs.get(i));\n\t" CLOSE_BLOCK);
} else {
p_output.push_back(c_in_statements);
p_output.push_back("\tconst void* " C_LOCAL_PTRCALL_ARGS "[");
@@ -1956,7 +2040,7 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
p_output.push_back(CS_PARAM_METHODBIND "->call(" CS_PARAM_INSTANCE ", ");
- p_output.push_back(p_imethod.arguments.size() ? "(const Variant**)" C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
+ p_output.push_back(p_imethod.arguments.size() ? C_LOCAL_PTRCALL_ARGS ".ptr()" : "NULL");
p_output.push_back(", total_length, vcall_error);\n");
// See the comment on the C_LOCAL_VARARG_RET declaration
@@ -2413,6 +2497,7 @@ void BindingsGenerator::_default_argument_from_variant(const Variant &p_val, Arg
r_iarg.default_argument = "null";
break;
}
+ FALLTHROUGH;
case Variant::DICTIONARY:
case Variant::_RID:
r_iarg.default_argument = "new %s()";
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index 7eaebeabbd..42071f9c0d 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -497,6 +497,7 @@ class BindingsGenerator {
StringName type_Object;
StringName type_Reference;
StringName type_String;
+ StringName type_at_GlobalScope;
StringName enum_Error;
NameCache() {
@@ -509,6 +510,7 @@ class BindingsGenerator {
type_Object = StaticCString::create("Object");
type_Reference = StaticCString::create("Reference");
type_String = StaticCString::create("String");
+ type_at_GlobalScope = StaticCString::create("@GlobalScope");
enum_Error = StaticCString::create("Error");
}
@@ -527,6 +529,15 @@ class BindingsGenerator {
return NULL;
}
+ const ConstantInterface *find_constant_by_name(const String &p_name, const List<ConstantInterface> &p_constants) const {
+ for (const List<ConstantInterface>::Element *E = p_constants.front(); E; E = E->next()) {
+ if (E->get().name == p_name)
+ return &E->get();
+ }
+
+ return NULL;
+ }
+
inline String get_unique_sig(const TypeInterface &p_type) {
if (p_type.is_reference)
return "Ref";
diff --git a/modules/mono/glue/Managed/Files/DynamicObject.cs b/modules/mono/glue/Managed/Files/DynamicObject.cs
new file mode 100644
index 0000000000..9504415664
--- /dev/null
+++ b/modules/mono/glue/Managed/Files/DynamicObject.cs
@@ -0,0 +1,213 @@
+
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq.Expressions;
+using System.Runtime.CompilerServices;
+
+namespace Godot
+{
+ /// <summary>
+ /// Represents an <see cref="Godot.Object"/> whose members can be dynamically accessed at runtime through the Variant API.
+ /// </summary>
+ /// <remarks>
+ /// <para>
+ /// The <see cref="Godot.DynamicGodotObject"/> class enables access to the Variant
+ /// members of a <see cref="Godot.Object"/> instance at runtime.
+ /// </para>
+ /// <para>
+ /// This allows accessing the class members using their original names in the engine as well as the members from the
+ /// script attached to the <see cref="Godot.Object"/>, regardless of the scripting language it was written in.
+ /// </para>
+ /// </remarks>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the engine members of a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic sprite = GetNode("Sprite").DynamicGodotObject;
+ /// sprite.add_child(this);
+ ///
+ /// if ((sprite.hframes * sprite.vframes) > 0)
+ /// sprite.frame = 0;
+ /// </code>
+ /// </example>
+ /// <example>
+ /// This sample shows how to use <see cref="Godot.DynamicGodotObject"/> to dynamically access the members of the script attached to a <see cref="Godot.Object"/>.
+ /// <code>
+ /// dynamic childNode = GetNode("ChildNode").DynamicGodotObject;
+ ///
+ /// if (childNode.print_allowed)
+ /// {
+ /// childNode.message = "Hello from C#";
+ /// childNode.print_message(3);
+ /// }
+ /// </code>
+ /// The <c>ChildNode</c> node has the following GDScript script attached:
+ /// <code>
+ /// // # ChildNode.gd
+ /// // var print_allowed = true
+ /// // var message = ""
+ /// //
+ /// // func print_message(times):
+ /// // for i in times:
+ /// // print(message)
+ /// </code>
+ /// </example>
+ public class DynamicGodotObject : DynamicObject
+ {
+ /// <summary>
+ /// Gets the <see cref="Godot.Object"/> associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </summary>
+ public Object Value { get; }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Godot.DynamicGodotObject"/> class.
+ /// </summary>
+ /// <param name="godotObject">
+ /// The <see cref="Godot.Object"/> that will be associated with this <see cref="Godot.DynamicGodotObject"/>.
+ /// </param>
+ /// <exception cref="System.ArgumentNullException">
+ /// Thrown when the <paramref name="godotObject"/> parameter is null.
+ /// </exception>
+ public DynamicGodotObject(Object godotObject)
+ {
+ if (godotObject == null)
+ throw new ArgumentNullException(nameof(godotObject));
+
+ this.Value = godotObject;
+ }
+
+ public override IEnumerable<string> GetDynamicMemberNames()
+ {
+ return godot_icall_DynamicGodotObject_SetMemberList(Object.GetPtr(Value));
+ }
+
+ public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
+ {
+ switch (binder.Operation)
+ {
+ case ExpressionType.Equal:
+ case ExpressionType.NotEqual:
+ if (binder.ReturnType == typeof(bool) || binder.ReturnType.IsAssignableFrom(typeof(bool)))
+ {
+ if (arg == null)
+ {
+ bool boolResult = Object.IsInstanceValid(Value);
+
+ if (binder.Operation == ExpressionType.Equal)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+
+ if (arg is Object other)
+ {
+ bool boolResult = (Value == other);
+
+ if (binder.Operation == ExpressionType.NotEqual)
+ boolResult = !boolResult;
+
+ result = boolResult;
+ return true;
+ }
+ }
+
+ break;
+ default:
+ // We're not implementing operators <, <=, >, and >= (LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual).
+ // These are used on the actual pointers in variant_op.cpp. It's better to let the user do that explicitly.
+ break;
+ }
+
+ return base.TryBinaryOperation(binder, arg, out result);
+ }
+
+ public override bool TryConvert(ConvertBinder binder, out object result)
+ {
+ if (binder.Type == typeof(Object))
+ {
+ result = Value;
+ return true;
+ }
+
+ if (typeof(Object).IsAssignableFrom(binder.Type))
+ {
+ // Throws InvalidCastException when the cast fails
+ result = Convert.ChangeType(Value, binder.Type);
+ return true;
+ }
+
+ return base.TryConvert(binder, out result);
+ }
+
+ public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), name, out result);
+ }
+ }
+
+ return base.TryGetIndex(binder, indexes, out result);
+ }
+
+ public override bool TryGetMember(GetMemberBinder binder, out object result)
+ {
+ return godot_icall_DynamicGodotObject_GetMember(Object.GetPtr(Value), binder.Name, out result);
+ }
+
+ public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
+ {
+ return godot_icall_DynamicGodotObject_InvokeMember(Object.GetPtr(Value), binder.Name, args, out result);
+ }
+
+ public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
+ {
+ if (indexes.Length == 1)
+ {
+ if (indexes[0] is string name)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), name, value);
+ }
+ }
+
+ return base.TrySetIndex(binder, indexes, value);
+ }
+
+ public override bool TrySetMember(SetMemberBinder binder, object value)
+ {
+ return godot_icall_DynamicGodotObject_SetMember(Object.GetPtr(Value), binder.Name, value);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static string[] godot_icall_DynamicGodotObject_SetMemberList(IntPtr godotObject);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_InvokeMember(IntPtr godotObject, string name, object[] args, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_GetMember(IntPtr godotObject, string name, out object result);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ internal extern static bool godot_icall_DynamicGodotObject_SetMember(IntPtr godotObject, string name, object value);
+
+ #region We don't override these methods
+
+ // Looks like this is not usable from C#
+ //public override bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
+
+ // Object members cannot be deleted
+ //public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
+ //public override bool TryDeleteMember(DeleteMemberBinder binder);
+
+ // Invokation on the object itself, e.g.: obj(param)
+ //public override bool TryInvoke(InvokeBinder binder, object[] args, out object result);
+
+ // No unnary operations to handle
+ //public override bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
+
+ #endregion
+ }
+}
diff --git a/modules/mono/glue/Managed/Files/GD.cs b/modules/mono/glue/Managed/Files/GD.cs
index 3afaf5d08b..d968f8a78f 100644
--- a/modules/mono/glue/Managed/Files/GD.cs
+++ b/modules/mono/glue/Managed/Files/GD.cs
@@ -13,12 +13,12 @@ namespace Godot
{
public static partial class GD
{
- public static object Bytes2Var(byte[] bytes)
+ public static object Bytes2Var(byte[] bytes, bool allow_objects = false)
{
- return godot_icall_GD_bytes2var(bytes);
+ return godot_icall_GD_bytes2var(bytes, allow_objects);
}
- public static object Convert(object what, int type)
+ public static object Convert(object what, Variant.Type type)
{
return godot_icall_GD_convert(what, type);
}
@@ -186,9 +186,9 @@ namespace Godot
return godot_icall_GD_type_exists(type);
}
- public static byte[] Var2Bytes(object var)
+ public static byte[] Var2Bytes(object var, bool full_objects = false)
{
- return godot_icall_GD_var2bytes(var);
+ return godot_icall_GD_var2bytes(var, full_objects);
}
public static string Var2Str(object var)
@@ -197,10 +197,10 @@ namespace Godot
}
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static object godot_icall_GD_bytes2var(byte[] bytes);
+ internal extern static object godot_icall_GD_bytes2var(byte[] bytes, bool allow_objects);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static object godot_icall_GD_convert(object what, int type);
+ internal extern static object godot_icall_GD_convert(object what, Variant.Type type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static int godot_icall_GD_hash(object var);
@@ -251,7 +251,7 @@ namespace Godot
internal extern static bool godot_icall_GD_type_exists(string type);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal extern static byte[] godot_icall_GD_var2bytes(object what);
+ internal extern static byte[] godot_icall_GD_var2bytes(object what, bool full_objects);
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static string godot_icall_GD_var2str(object var);
diff --git a/modules/mono/glue/Managed/Files/Object.base.cs b/modules/mono/glue/Managed/Files/Object.base.cs
index 41fc43996f..e152d56871 100644
--- a/modules/mono/glue/Managed/Files/Object.base.cs
+++ b/modules/mono/glue/Managed/Files/Object.base.cs
@@ -73,11 +73,39 @@ namespace Godot
disposed = true;
}
+ /// <summary>
+ /// Returns a new <see cref="Godot.SignalAwaiter"/> awaiter configured to complete when the instance
+ /// <paramref name="source"/> emits the signal specified by the <paramref name="signal"/> parameter.
+ /// </summary>
+ /// <param name="source">
+ /// The instance the awaiter will be listening to.
+ /// </param>
+ /// <param name="signal">
+ /// The signal the awaiter will be waiting for.
+ /// </param>
+ /// <example>
+ /// This sample prints a message once every frame up to 100 times.
+ /// <code>
+ /// public override void _Ready()
+ /// {
+ /// for (int i = 0; i < 100; i++)
+ /// {
+ /// await ToSignal(GetTree(), "idle_frame");
+ /// GD.Print($"Frame {i}");
+ /// }
+ /// }
+ /// </code>
+ /// </example>
public SignalAwaiter ToSignal(Object source, string signal)
{
return new SignalAwaiter(source, signal, this);
}
+ /// <summary>
+ /// Gets a new <see cref="Godot.DynamicGodotObject"/> associated with this instance.
+ /// </summary>
+ public dynamic DynamicObject => new DynamicGodotObject(this);
+
[MethodImpl(MethodImplOptions.InternalCall)]
internal extern static IntPtr godot_icall_Object_Ctor(Object obj);
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
new file mode 100644
index 0000000000..8c0f308c15
--- /dev/null
+++ b/modules/mono/glue/arguments_vector.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* arguments_vector.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 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 ARGUMENTS_VECTOR_H
+#define ARGUMENTS_VECTOR_H
+
+#include "core/os/memory.h"
+
+template <typename T, int POOL_SIZE = 5>
+struct ArgumentsVector {
+
+private:
+ T pool[POOL_SIZE];
+ T *_ptr;
+ int size;
+
+ ArgumentsVector();
+ ArgumentsVector(const ArgumentsVector &);
+
+public:
+ T *ptr() { return _ptr; }
+ T &get(int p_idx) { return _ptr[p_idx]; }
+ void set(int p_idx, const T &p_value) { _ptr[p_idx] = p_value; }
+
+ explicit ArgumentsVector(int p_size) :
+ size(p_size) {
+ if (p_size <= POOL_SIZE) {
+ _ptr = pool;
+ } else {
+ _ptr = memnew_arr(T, p_size);
+ }
+ }
+
+ ~ArgumentsVector() {
+ if (size > POOL_SIZE) {
+ memdelete_arr(_ptr);
+ }
+ }
+};
+
+#endif // ARGUMENTS_VECTOR_H
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index fad02b01d3..b690de0d20 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -36,9 +36,11 @@
#include "core/string_name.h"
#include "../csharp_script.h"
+#include "../mono_gd/gd_mono_class.h"
#include "../mono_gd/gd_mono_internals.h"
#include "../mono_gd/gd_mono_utils.h"
#include "../signal_awaiter_utils.h"
+#include "arguments_vector.h"
Object *godot_icall_Object_Ctor(MonoObject *p_obj) {
Object *instance = memnew(Object);
@@ -75,7 +77,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
}
}
-void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer) {
+void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) {
#ifdef DEBUG_ENABLED
CRASH_COND(p_ptr == NULL);
// This is only called with Reference derived classes
@@ -155,6 +157,67 @@ Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal,
return SignalAwaiterUtils::connect_signal_awaiter(p_source, signal, p_target, p_awaiter);
}
+MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
+ List<PropertyInfo> property_list;
+ p_ptr->get_property_list(&property_list);
+
+ MonoArray *result = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), property_list.size());
+
+ int i = 0;
+ for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name);
+ mono_array_set(result, MonoString *, i, boxed);
+ i++;
+ }
+
+ return result;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+
+ int argc = mono_array_length(p_args);
+
+ ArgumentsVector<Variant> arg_store(argc);
+ ArgumentsVector<const Variant *> args(argc);
+
+ for (int i = 0; i < argc; i++) {
+ MonoObject *elem = mono_array_get(p_args, MonoObject *, i);
+ arg_store.set(i, GDMonoMarshal::mono_object_to_variant(elem));
+ args.set(i, &arg_store.get(i));
+ }
+
+ Variant::CallError error;
+ Variant result = p_ptr->call(StringName(name), args.ptr(), argc, error);
+
+ *r_result = GDMonoMarshal::variant_to_mono_object(result);
+
+ return error.error == OK;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+
+ bool valid;
+ Variant value = p_ptr->get(StringName(name), &valid);
+
+ if (valid) {
+ *r_result = GDMonoMarshal::variant_to_mono_object(value);
+ }
+
+ return valid;
+}
+
+MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value) {
+ String name = GDMonoMarshal::mono_string_to_godot(p_name);
+ Variant value = GDMonoMarshal::mono_object_to_variant(p_value);
+
+ bool valid;
+ p_ptr->set(StringName(name), value, &valid);
+
+ return valid;
+}
+
void godot_register_object_icalls() {
mono_add_internal_call("Godot.Object::godot_icall_Object_Ctor", (void *)godot_icall_Object_Ctor);
mono_add_internal_call("Godot.Object::godot_icall_Object_Disposed", (void *)godot_icall_Object_Disposed);
@@ -162,6 +225,10 @@ void godot_register_object_icalls() {
mono_add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", (void *)godot_icall_Object_ClassDB_get_method);
mono_add_internal_call("Godot.Object::godot_icall_Object_weakref", (void *)godot_icall_Object_weakref);
mono_add_internal_call("Godot.SignalAwaiter::godot_icall_SignalAwaiter_connect", (void *)godot_icall_SignalAwaiter_connect);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMemberList", (void *)godot_icall_DynamicGodotObject_SetMemberList);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_InvokeMember", (void *)godot_icall_DynamicGodotObject_InvokeMember);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_GetMember", (void *)godot_icall_DynamicGodotObject_GetMember);
+ mono_add_internal_call("Godot.DynamicGodotObject::godot_icall_DynamicGodotObject_SetMember", (void *)godot_icall_DynamicGodotObject_SetMember);
}
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/glue/base_object_glue.h b/modules/mono/glue/base_object_glue.h
index e126fac6ca..9b5224a347 100644
--- a/modules/mono/glue/base_object_glue.h
+++ b/modules/mono/glue/base_object_glue.h
@@ -42,7 +42,7 @@ Object *godot_icall_Object_Ctor(MonoObject *p_obj);
void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr);
-void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, bool p_is_finalizer);
+void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer);
MethodBind *godot_icall_Object_ClassDB_get_method(MonoString *p_type, MonoString *p_method);
@@ -50,6 +50,16 @@ MonoObject *godot_icall_Object_weakref(Object *p_obj);
Error godot_icall_SignalAwaiter_connect(Object *p_source, MonoString *p_signal, Object *p_target, MonoObject *p_awaiter);
+// DynamicGodotObject
+
+MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr);
+
+MonoBoolean godot_icall_DynamicGodotObject_InvokeMember(Object *p_ptr, MonoString *p_name, MonoArray *p_args, MonoObject **r_result);
+
+MonoBoolean godot_icall_DynamicGodotObject_GetMember(Object *p_ptr, MonoString *p_name, MonoObject **r_result);
+
+MonoBoolean godot_icall_DynamicGodotObject_SetMember(Object *p_ptr, MonoString *p_name, MonoObject *p_value);
+
// Register internal calls
void godot_register_object_icalls();
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 1065ff0868..1aad1c53bc 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -81,7 +81,7 @@ void godot_icall_Array_Clear(Array *ptr) {
ptr->clear();
}
-bool godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
+MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item) {
return ptr->find(GDMonoMarshal::mono_object_to_variant(item)) != -1;
}
@@ -113,7 +113,7 @@ void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item) {
ptr->insert(index, GDMonoMarshal::mono_object_to_variant(item));
}
-bool godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
+MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
if (idx >= 0) {
ptr->remove(idx);
@@ -208,21 +208,21 @@ void godot_icall_Dictionary_Clear(Dictionary *ptr) {
ptr->clear();
}
-bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value) {
// no dupes
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
return ret != NULL && *ret == GDMonoMarshal::mono_object_to_variant(value);
}
-bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
+MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key) {
return ptr->has(GDMonoMarshal::mono_object_to_variant(key));
}
-bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
+MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key) {
return ptr->erase(GDMonoMarshal::mono_object_to_variant(key));
}
-bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
+MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value) {
Variant varKey = GDMonoMarshal::mono_object_to_variant(key);
// no dupes
@@ -235,7 +235,7 @@ bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject
return false;
}
-bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
+MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == NULL) {
*value = NULL;
@@ -245,7 +245,7 @@ bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoOb
return true;
}
-bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
+MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class) {
Variant *ret = ptr->getptr(GDMonoMarshal::mono_object_to_variant(key));
if (ret == NULL) {
*value = NULL;
diff --git a/modules/mono/glue/collections_glue.h b/modules/mono/glue/collections_glue.h
index c0056d3bce..85a2e243a2 100644
--- a/modules/mono/glue/collections_glue.h
+++ b/modules/mono/glue/collections_glue.h
@@ -55,7 +55,7 @@ void godot_icall_Array_Add(Array *ptr, MonoObject *item);
void godot_icall_Array_Clear(Array *ptr);
-bool godot_icall_Array_Contains(Array *ptr, MonoObject *item);
+MonoBoolean godot_icall_Array_Contains(Array *ptr, MonoObject *item);
void godot_icall_Array_CopyTo(Array *ptr, MonoArray *array, int array_index);
@@ -63,7 +63,7 @@ int godot_icall_Array_IndexOf(Array *ptr, MonoObject *item);
void godot_icall_Array_Insert(Array *ptr, int index, MonoObject *item);
-bool godot_icall_Array_Remove(Array *ptr, MonoObject *item);
+MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item);
void godot_icall_Array_RemoveAt(Array *ptr, int index);
@@ -93,17 +93,17 @@ void godot_icall_Dictionary_Add(Dictionary *ptr, MonoObject *key, MonoObject *va
void godot_icall_Dictionary_Clear(Dictionary *ptr);
-bool godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
+MonoBoolean godot_icall_Dictionary_Contains(Dictionary *ptr, MonoObject *key, MonoObject *value);
-bool godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
+MonoBoolean godot_icall_Dictionary_ContainsKey(Dictionary *ptr, MonoObject *key);
-bool godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
+MonoBoolean godot_icall_Dictionary_RemoveKey(Dictionary *ptr, MonoObject *key);
-bool godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
+MonoBoolean godot_icall_Dictionary_Remove(Dictionary *ptr, MonoObject *key, MonoObject *value);
-bool godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
+MonoBoolean godot_icall_Dictionary_TryGetValue(Dictionary *ptr, MonoObject *key, MonoObject **value);
-bool godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class);
+MonoBoolean godot_icall_Dictionary_TryGetValue_Generic(Dictionary *ptr, MonoObject *key, MonoObject **value, uint32_t type_encoding, GDMonoClass *type_class);
void godot_icall_Dictionary_Generic_GetValueTypeInfo(MonoReflectionType *refltype, uint32_t *type_encoding, GDMonoClass **type_class);
diff --git a/modules/mono/glue/gd_glue.cpp b/modules/mono/glue/gd_glue.cpp
index 5edf49d2bf..d756131ac9 100644
--- a/modules/mono/glue/gd_glue.cpp
+++ b/modules/mono/glue/gd_glue.cpp
@@ -41,11 +41,11 @@
#include "../mono_gd/gd_mono_utils.h"
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes) {
+MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects) {
Variant ret;
PoolByteArray varr = GDMonoMarshal::mono_array_to_PoolByteArray(p_bytes);
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, p_allow_objects);
if (err != OK) {
ret = RTR("Not enough bytes for decoding bytes, or invalid format.");
}
@@ -175,7 +175,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
return GDMonoMarshal::variant_to_mono_object(ret);
}
-bool godot_icall_GD_type_exists(MonoString *p_type) {
+MonoBoolean godot_icall_GD_type_exists(MonoString *p_type) {
return ClassDB::class_exists(GDMonoMarshal::mono_string_to_godot(p_type));
}
@@ -187,19 +187,19 @@ void godot_icall_GD_pushwarning(MonoString *p_str) {
WARN_PRINTS(GDMonoMarshal::mono_string_to_godot(p_str));
}
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var) {
+MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects) {
Variant var = GDMonoMarshal::mono_object_to_variant(p_var);
PoolByteArray barr;
int len;
- Error err = encode_variant(var, NULL, len);
+ Error err = encode_variant(var, NULL, len, p_full_objects);
ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
ERR_FAIL_COND_V(err != OK, NULL);
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(var, w.ptr(), len);
+ encode_variant(var, w.ptr(), len, p_full_objects);
}
return GDMonoMarshal::PoolByteArray_to_mono_array(barr);
diff --git a/modules/mono/glue/gd_glue.h b/modules/mono/glue/gd_glue.h
index ba75d85343..910979aae3 100644
--- a/modules/mono/glue/gd_glue.h
+++ b/modules/mono/glue/gd_glue.h
@@ -35,7 +35,7 @@
#include "../mono_gd/gd_mono_marshal.h"
-MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes);
+MonoObject *godot_icall_GD_bytes2var(MonoArray *p_bytes, MonoBoolean p_allow_objects);
MonoObject *godot_icall_GD_convert(MonoObject *p_what, int32_t p_type);
@@ -69,9 +69,9 @@ MonoString *godot_icall_GD_str(MonoArray *p_what);
MonoObject *godot_icall_GD_str2var(MonoString *p_str);
-bool godot_icall_GD_type_exists(MonoString *p_type);
+MonoBoolean godot_icall_GD_type_exists(MonoString *p_type);
-MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var);
+MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_objects);
MonoString *godot_icall_GD_var2str(MonoObject *p_var);
diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h
index b6e8ac6909..1836130b76 100644
--- a/modules/mono/glue/glue_header.h
+++ b/modules/mono/glue/glue_header.h
@@ -74,4 +74,6 @@ void godot_register_glue_header_icalls() {
} \
Object *m_instance = ci->creation_func();
+#include "arguments_vector.h"
+
#endif // MONO_GLUE_ENABLED
diff --git a/modules/mono/mono_reg_utils.py b/modules/mono/mono_reg_utils.py
index c8ebb54ded..583708bf07 100644
--- a/modules/mono/mono_reg_utils.py
+++ b/modules/mono/mono_reg_utils.py
@@ -40,7 +40,7 @@ def _reg_open_key_bits(key, subkey, bits):
def _find_mono_in_reg(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'SdkInstallRoot')
+ value = winreg.QueryValueEx(hKey, 'SdkInstallRoot')[0]
return value
except (WindowsError, OSError):
return None
@@ -49,7 +49,7 @@ def _find_mono_in_reg(subkey, bits):
def _find_mono_in_reg_old(subkey, bits):
try:
with _reg_open_key_bits(winreg.HKEY_LOCAL_MACHINE, subkey, bits) as hKey:
- default_clr, regtype = winreg.QueryValueEx(hKey, 'DefaultCLR')
+ default_clr = winreg.QueryValueEx(hKey, 'DefaultCLR')[0]
if default_clr:
return _find_mono_in_reg(subkey + '\\' + default_clr, bits)
return None
@@ -91,7 +91,13 @@ def find_msbuild_tools_path_reg():
if not val:
raise ValueError('Value of `installationPath` entry is empty')
- return os.path.join(val, "MSBuild\\15.0\\Bin")
+ # Since VS2019, the directory is simply named "Current"
+ msbuild_dir = os.path.join(val, 'MSBuild\\Current\\Bin')
+ if os.path.isdir(msbuild_dir):
+ return msbuild_dir
+
+ # Directory name "15.0" is used in VS 2017
+ return os.path.join(val, 'MSBuild\\15.0\\Bin')
raise ValueError('Cannot find `installationPath` entry')
except ValueError as e:
@@ -106,7 +112,7 @@ def find_msbuild_tools_path_reg():
try:
subkey = r'SOFTWARE\Microsoft\MSBuild\ToolsVersions\14.0'
with _reg_open_key(winreg.HKEY_LOCAL_MACHINE, subkey) as hKey:
- value, regtype = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')
+ value = winreg.QueryValueEx(hKey, 'MSBuildToolsPath')[0]
return value
except (WindowsError, OSError):
return ''
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index d7f9b22c31..98aeadc8c8 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -202,9 +202,9 @@ String find_msbuild_tools_path() {
}
// Since VS2019, the directory is simply named "Current"
- String msBuildDirectory = val + "MSBuild\\Current\\Bin";
- if (DirAccess::exists(msBuildDirectory)) {
- return msBuildDirectory;
+ String msbuild_dir = val + "MSBuild\\Current\\Bin";
+ if (DirAccess::exists(msbuild_dir)) {
+ return msbuild_dir;
}
// Directory name "15.0" is used in VS 2017
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index a91114b2f7..25f104b221 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="NoiseTexture" inherits="Texture" category="Core" version="3.1">
+<class name="NoiseTexture" inherits="Texture" category="Core" version="3.2">
<brief_description>
[OpenSimplexNoise] filled texture.
</brief_description>
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index 31f13f341c..b5bc35df69 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenSimplexNoise" inherits="Resource" category="Core" version="3.1">
+<class name="OpenSimplexNoise" inherits="Resource" category="Core" version="3.2">
<brief_description>
Noise generator based on Open Simplex.
</brief_description>
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
index aa656c575a..b72144c679 100644
--- a/modules/opus/SCsub
+++ b/modules/opus/SCsub
@@ -220,10 +220,15 @@ if env['builtin_opus']:
]
env_opus.Append(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths])
- if env["platform"] == "android" or env["platform"] == "iphone":
- if ("arch" in env and env["arch"] == "arm") or ("android_arch" in env and env["android_arch"] in ["armv6", "armv7"]):
+ if env["platform"] == "android":
+ if ("android_arch" in env and env["android_arch"] in ["armv6", "armv7"]):
env_opus.Append(CFLAGS=["-DOPUS_ARM_OPT"])
- elif ("arch" in env and env["arch"] == "arm64") or ("android_arch" in env and env["android_arch"] == "arm64v8"):
+ elif ("android_arch" in env and env["android_arch"] == "arm64v8"):
+ env_opus.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
+ elif env["platform"] == "iphone":
+ if ("arch" in env and env["arch"] == "arm"):
+ env_opus.Append(CFLAGS=["-DOPUS_ARM_OPT"])
+ elif ("arch" in env and env["arch"] == "arm64"):
env_opus.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
env_thirdparty = env_opus.Clone()
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 75e8903ff8..20857572f3 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegEx" inherits="Reference" category="Core" version="3.1">
+<class name="RegEx" inherits="Reference" category="Core" version="3.2">
<brief_description>
Class for searching text for patterns using regular expressions.
</brief_description>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index 3d070d2786..9efec91bdc 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="RegExMatch" inherits="Reference" category="Core" version="3.1">
+<class name="RegExMatch" inherits="Reference" category="Core" version="3.2">
<brief_description>
Contains the results of a regex search.
</brief_description>
diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
index e2281babf7..574ff1ff2a 100644
--- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
+++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.1">
+<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core" version="3.2">
<brief_description>
OGG Vorbis audio stream driver.
</brief_description>
diff --git a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
index 018f4734ec..ade485e717 100644
--- a/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
+++ b/modules/stb_vorbis/doc_classes/ResourceImporterOGGVorbis.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.1">
+<class name="ResourceImporterOGGVorbis" inherits="ResourceImporter" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index e7c4727332..2bd8ad862f 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.1">
+<class name="VideoStreamTheora" inherits="VideoStream" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index e69d9a0ae3..bd84a28c84 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -107,22 +107,31 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
}
}
- if (idxR == -1) {
- ERR_PRINT("TinyEXR: R channel not found.");
- // @todo { free exr_image }
- return ERR_FILE_CORRUPT;
- }
+ if (exr_header.num_channels == 1) {
+ // Grayscale channel only.
+ idxR = 0;
+ idxG = 0;
+ idxB = 0;
+ idxA = 0;
+ } else {
+ // Assume RGB(A)
+ if (idxR == -1) {
+ ERR_PRINT("TinyEXR: R channel not found.");
+ // @todo { free exr_image }
+ return ERR_FILE_CORRUPT;
+ }
- if (idxG == -1) {
- ERR_PRINT("TinyEXR: G channel not found.")
- // @todo { free exr_image }
- return ERR_FILE_CORRUPT;
- }
+ if (idxG == -1) {
+ ERR_PRINT("TinyEXR: G channel not found.")
+ // @todo { free exr_image }
+ return ERR_FILE_CORRUPT;
+ }
- if (idxB == -1) {
- ERR_PRINT("TinyEXR: B channel not found.")
- // @todo { free exr_image }
- return ERR_FILE_CORRUPT;
+ if (idxB == -1) {
+ ERR_PRINT("TinyEXR: B channel not found.")
+ // @todo { free exr_image }
+ return ERR_FILE_CORRUPT;
+ }
}
// EXR image data loaded, now parse it into Godot-friendly image data
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index b98327c60d..0f967c993b 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNP" inherits="Reference" category="Core" version="3.1">
+<class name="UPNP" inherits="Reference" category="Core" version="3.2">
<brief_description>
UPNP network functions.
</brief_description>
diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml
index 9de8042daf..c9b695a651 100644
--- a/modules/upnp/doc_classes/UPNPDevice.xml
+++ b/modules/upnp/doc_classes/UPNPDevice.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="UPNPDevice" inherits="Reference" category="Core" version="3.1">
+<class name="UPNPDevice" inherits="Reference" category="Core" version="3.2">
<brief_description>
UPNP device.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 70849c5a80..f4a9bc68e6 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScript" inherits="Script" category="Core" version="3.1">
+<class name="VisualScript" inherits="Script" category="Core" version="3.2">
<brief_description>
A script implemented in the Visual Script programming environment.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
index 5ec155fbc6..ce49cdf3a0 100644
--- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptBasicTypeConstant" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node representing a constant from the base types.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index 3a1d773058..dd14d60327 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptBuiltinFunc" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node used to call built-in functions.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
index dc9044e9ed..32b5924cdc 100644
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptClassConstant" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Gets a constant from a given class.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml
index a4a890ea8a..990e0ecb85 100644
--- a/modules/visual_script/doc_classes/VisualScriptComment.xml
+++ b/modules/visual_script/doc_classes/VisualScriptComment.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptComment" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node used to annotate the script.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml
index a7b1028c0c..94c075205d 100644
--- a/modules/visual_script/doc_classes/VisualScriptCondition.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCondition.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptCondition" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node which branches the flow.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml
index ed633c4135..0fc4e87db4 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptConstant" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Gets a contant's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
index 14c44c6970..05fc3f318d 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptConstructor" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node which calls a base type constructor.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
index ff3ed66e81..0ad4e7c1f5 100644
--- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptCustomNode" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A scripted Visual Script node.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
index d3158df357..b933a25f1d 100644
--- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
+++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptDeconstruct" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node which deconstructs a base type instance into its parts.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEditor.xml b/modules/visual_script/doc_classes/VisualScriptEditor.xml
index fc49cfc07b..be4606b57c 100644
--- a/modules/visual_script/doc_classes/VisualScriptEditor.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEditor.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.1">
+<class name="VisualScriptEditor" inherits="Object" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
index 4bb05525bd..3282269811 100644
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptEmitSignal" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Emits a specified signal.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
index 93d7ce3516..3e52fb818c 100644
--- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptEngineSingleton" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
A Visual Script node returning a singleton from [@GlobalScope]
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml
index 343e83cb55..4760685bfb 100644
--- a/modules/visual_script/doc_classes/VisualScriptExpression.xml
+++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptExpression" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml
index ec8e955cf7..dc021196cd 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptFunction" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
index f6116cf539..e978437542 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptFunctionCall" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
index c75dd0cdbc..a5e15b8da2 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.1">
+<class name="VisualScriptFunctionState" inherits="Reference" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
index 9d43204f02..2d609ed262 100644
--- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptGlobalConstant" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
index 73c1f47e1a..16499e9ec9 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptIndexGet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
index 652c29a9ac..06844ac4ae 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptIndexSet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
index ab4c23012b..01887e0764 100644
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptInputAction" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml
index 7090621bd7..496c24dee4 100644
--- a/modules/visual_script/doc_classes/VisualScriptIterator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIterator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptIterator" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Steps through items in a given input.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
index 5c8ee6453c..cd7286b59b 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptLocalVar" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Gets a local variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
index f2e6c48907..f8fe2f4b6b 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptLocalVarSet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Changes a local variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
index d456e880b7..733b48203d 100644
--- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptMathConstant" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Commonly used mathematical constants.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml
index 941a0cd91a..86bd469d5c 100644
--- a/modules/visual_script/doc_classes/VisualScriptNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.1">
+<class name="VisualScriptNode" inherits="Resource" category="Core" version="3.2">
<brief_description>
A node which is part of a [VisualScript].
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml
index e60d50c977..d722477653 100644
--- a/modules/visual_script/doc_classes/VisualScriptOperator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptOperator" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml
index 5a2886ccac..b811252c42 100644
--- a/modules/visual_script/doc_classes/VisualScriptPreload.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptPreload" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Creates a new [Resource] or loads one from the filesystem.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index 60cc8fdd4f..7f652b7012 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptPropertyGet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
index 8f29e9d152..ef9938c6a7 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptPropertySet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
index f6300e03f0..2a5c56cf69 100644
--- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
+++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptResourcePath" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml
index 0ca3e3b612..7daddc7639 100644
--- a/modules/visual_script/doc_classes/VisualScriptReturn.xml
+++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptReturn" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Exits a function and returns an optional value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
index 7704eaba04..8604a0f5eb 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSceneNode" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Node reference.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
index 2c2af9262d..72a2faaa78 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSceneTree" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml
index 0731fc77e1..c87f77ea65 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelect.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSelect" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Chooses between two input values.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml
index 61a73e104c..42c75e56a6 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelf.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelf.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSelf" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Outputs a reference to the current instance.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml
index c71e068045..c26c72dd50 100644
--- a/modules/visual_script/doc_classes/VisualScriptSequence.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSequence" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Executes a series of Sequence ports.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
index 46aeebab9c..712b4ed09b 100644
--- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSubCall" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
index a00811a29b..0053733b34 100644
--- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptSwitch" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Branches program flow based on a given input's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
index 0bdc4ce89d..85b3980e21 100644
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptTypeCast" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
index 06178a399d..27bf223aac 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptVariableGet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Gets a variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
index 5969f25060..c55c72d55e 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptVariableSet" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Changes a variable's value.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml
index b9e7f6a553..b7ed56e7d2 100644
--- a/modules/visual_script/doc_classes/VisualScriptWhile.xml
+++ b/modules/visual_script/doc_classes/VisualScriptWhile.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptWhile" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
Conditional loop.
</brief_description>
diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml
index c4698f746a..5aa0f76a55 100644
--- a/modules/visual_script/doc_classes/VisualScriptYield.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYield.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptYield" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
index b67e4ab1b8..8e3b2aec1d 100644
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.1">
+<class name="VisualScriptYieldSignal" inherits="VisualScriptNode" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 9f2d1a49c0..0d379205e4 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -183,10 +183,10 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINTRAW:
case VAR_TO_STR:
case STR_TO_VAR:
- case VAR_TO_BYTES:
- case BYTES_TO_VAR:
case TYPE_EXISTS:
return 1;
+ case VAR_TO_BYTES:
+ case BYTES_TO_VAR:
case MATH_ATAN2:
case MATH_FMOD:
case MATH_FPOSMOD:
@@ -491,12 +491,18 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
return PropertyInfo(Variant::STRING, "string");
} break;
case VAR_TO_BYTES: {
- return PropertyInfo(Variant::NIL, "var");
+ if (p_idx == 0)
+ return PropertyInfo(Variant::NIL, "var");
+ else
+ return PropertyInfo(Variant::BOOL, "full_objects");
} break;
case BYTES_TO_VAR: {
- return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes");
+ if (p_idx == 0)
+ return PropertyInfo(Variant::POOL_BYTE_ARRAY, "bytes");
+ else
+ return PropertyInfo(Variant::BOOL, "allow_objects");
} break;
case COLORN: {
@@ -655,11 +661,15 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
} break;
case VAR_TO_BYTES: {
- t = Variant::POOL_BYTE_ARRAY;
+ if (p_idx == 0)
+ t = Variant::POOL_BYTE_ARRAY;
+ else
+ t = Variant::BOOL;
} break;
case BYTES_TO_VAR: {
-
+ if (p_idx == 1)
+ t = Variant::BOOL;
} break;
case COLORN: {
t = Variant::COLOR;
@@ -1192,9 +1202,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
} break;
case VisualScriptBuiltinFunc::VAR_TO_BYTES: {
+ if (p_inputs[1]->get_type() != Variant::BOOL) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::BOOL;
+ return;
+ }
PoolByteArray barr;
int len;
- Error err = encode_variant(*p_inputs[0], NULL, len);
+ bool full_objects = *p_inputs[1];
+ Error err = encode_variant(*p_inputs[0], NULL, len, full_objects);
if (err) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
@@ -1206,7 +1223,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
barr.resize(len);
{
PoolByteArray::Write w = barr.write();
- encode_variant(*p_inputs[0], w.ptr(), len);
+ encode_variant(*p_inputs[0], w.ptr(), len, full_objects);
}
*r_return = barr;
} break;
@@ -1216,15 +1233,21 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::POOL_BYTE_ARRAY;
-
+ return;
+ }
+ if (p_inputs[1]->get_type() != Variant::BOOL) {
+ r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 1;
+ r_error.expected = Variant::BOOL;
return;
}
PoolByteArray varr = *p_inputs[0];
+ bool allow_objects = *p_inputs[1];
Variant ret;
{
PoolByteArray::Read r = varr.read();
- Error err = decode_variant(ret, r.ptr(), varr.size(), NULL);
+ Error err = decode_variant(ret, r.ptr(), varr.size(), NULL, allow_objects);
if (err != OK) {
r_error_str = RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml
index c02a7a8016..33dff0e93b 100644
--- a/modules/webm/doc_classes/VideoStreamWebm.xml
+++ b/modules/webm/doc_classes/VideoStreamWebm.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.1">
+<class name="VideoStreamWebm" inherits="VideoStream" category="Core" version="3.2">
<brief_description>
</brief_description>
<description>
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index ffb6d40e30..cb85fe864d 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" category="Core" version="3.1">
+<class name="WebSocketClient" inherits="WebSocketMultiplayerPeer" category="Core" version="3.2">
<brief_description>
A WebSocket client implementation
</brief_description>
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index 1a841f85ed..139480c31f 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" category="Core" version="3.1">
+<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" category="Core" version="3.2">
<brief_description>
Base class for WebSocket server and client.
</brief_description>
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index 5dda012899..3b3692dd87 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketPeer" inherits="PacketPeer" category="Core" version="3.1">
+<class name="WebSocketPeer" inherits="PacketPeer" category="Core" version="3.2">
<brief_description>
A class representing a specific WebSocket connection.
</brief_description>
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index 2932bf782a..4740bd6dcf 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" category="Core" version="3.1">
+<class name="WebSocketServer" inherits="WebSocketMultiplayerPeer" category="Core" version="3.2">
<brief_description>
A WebSocket server implementation
</brief_description>
diff --git a/modules/websocket/packet_buffer.h b/modules/websocket/packet_buffer.h
index 47786a87a6..057fecfb56 100644
--- a/modules/websocket/packet_buffer.h
+++ b/modules/websocket/packet_buffer.h
@@ -59,7 +59,7 @@ public:
ERR_FAIL_V(ERR_OUT_OF_MEMORY);
}
#else
- ERR_FAIL_COND_V(p_payload && _payload.space_left() < p_size, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_COND_V(p_payload && (uint32_t)_payload.space_left() < p_size, ERR_OUT_OF_MEMORY);
ERR_FAIL_COND_V(p_info && _packets.space_left() < 1, ERR_OUT_OF_MEMORY);
#endif