summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bullet/area_bullet.h1
-rw-r--r--modules/bullet/soft_body_bullet.cpp9
-rw-r--r--modules/csg/csg.cpp2
-rw-r--r--modules/csg/csg.h2
-rw-r--r--modules/csg/csg_shape.cpp3
-rw-r--r--modules/denoise/config.py5
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp3
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp7
-rw-r--r--modules/fbx/doc_classes/EditorSceneImporterFBX.xml32
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp77
-rw-r--r--modules/fbx/editor_scene_importer_fbx.h8
-rw-r--r--modules/fbx/register_types.cpp4
-rw-r--r--modules/fbx/tools/import_utils.cpp24
-rw-r--r--modules/gdnative/gdnative/gdnative.cpp6
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp3
-rw-r--r--modules/gdnative/nativescript/nativescript.h3
-rw-r--r--modules/gdnative/pluginscript/pluginscript_instance.h2
-rw-r--r--modules/gdscript/gdscript.cpp10
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp195
-rw-r--r--modules/gdscript/gdscript_analyzer.h4
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp6
-rw-r--r--modules/gdscript/gdscript_compiler.cpp84
-rw-r--r--modules/gdscript/gdscript_editor.cpp15
-rw-r--r--modules/gdscript/gdscript_parser.cpp57
-rw-r--r--modules/gdscript/gdscript_parser.h4
-rw-r--r--modules/gdscript/gdscript_vm.cpp7
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp2
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd19
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_functions.gd16
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_functions.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_inline.gd46
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_inline.out10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd32
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd19
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out3
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lua_assign.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lua_assign.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd42
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out34
-rw-r--r--modules/gltf/doc_classes/EditorSceneImporterGLTF.xml9
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp8
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h4
-rw-r--r--modules/gltf/gltf_document.cpp257
-rw-r--r--modules/gltf/gltf_document.h4
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.cpp3
-rw-r--r--modules/gltf/register_types.cpp4
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp126
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h3
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl4
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl27
-rw-r--r--modules/lightmapper_rd/lm_raster.glsl12
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.h2
-rw-r--r--modules/mbedtls/ssl_context_mbedtls.h2
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.h2
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp2
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml1
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp69
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h9
-rw-r--r--modules/mono/SCsub3
-rw-r--r--modules/mono/build_scripts/mono_reg_utils.py1
-rw-r--r--modules/mono/config.py2
-rw-r--r--modules/mono/csharp_script.cpp18
-rw-r--r--modules/mono/csharp_script.h4
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs15
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp97
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp30
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h5
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp2
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp2
-rw-r--r--modules/ogg/SCsub3
-rw-r--r--modules/opus/SCsub252
-rw-r--r--modules/opus/config.py6
-rw-r--r--modules/opus/register_types.cpp37
-rw-r--r--modules/opus/register_types.h37
-rw-r--r--modules/raycast/config.py2
-rw-r--r--modules/regex/config.py2
-rw-r--r--modules/text_server_adv/SCsub6
-rw-r--r--modules/text_server_adv/text_server_adv.cpp380
-rw-r--r--modules/text_server_adv/text_server_adv.h44
-rw-r--r--modules/text_server_fb/text_server_fb.cpp69
-rw-r--r--modules/text_server_fb/text_server_fb.h6
-rw-r--r--modules/theora/config.py2
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/theora/video_stream_theora.cpp4
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script_editor.cpp2
-rw-r--r--modules/visual_script/visual_script_nodes.h6
-rw-r--r--modules/webm/SCsub48
-rw-r--r--modules/webm/config.py19
-rw-r--r--modules/webm/doc_classes/VideoStreamWebm.xml28
-rw-r--r--modules/webm/libvpx/SCsub382
-rw-r--r--modules/webm/register_types.cpp47
-rw-r--r--modules/webm/register_types.h37
-rw-r--r--modules/webm/video_stream_webm.cpp469
-rw-r--r--modules/webm/video_stream_webm.h135
-rw-r--r--modules/websocket/websocket_client.cpp2
-rw-r--r--modules/websocket/websocket_macros.h6
-rw-r--r--modules/websocket/websocket_server.cpp8
-rw-r--r--modules/websocket/wsl_server.h2
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml2
-rw-r--r--modules/webxr/webxr_interface_js.cpp86
-rw-r--r--modules/webxr/webxr_interface_js.h3
-rw-r--r--modules/xatlas_unwrap/register_types.cpp2
125 files changed, 1546 insertions, 2236 deletions
diff --git a/modules/bullet/area_bullet.h b/modules/bullet/area_bullet.h
index 7cf666c119..c8b516c951 100644
--- a/modules/bullet/area_bullet.h
+++ b/modules/bullet/area_bullet.h
@@ -145,7 +145,6 @@ public:
virtual void dispatch_callbacks();
void call_event(CollisionObjectBullet *p_otherObject, PhysicsServer3D::AreaBodyStatus p_status);
- void set_on_state_change(ObjectID p_id, const StringName &p_method, const Variant &p_udata = Variant());
void scratch();
void clear_overlaps(bool p_notify);
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 371800d8f3..3a2370ff31 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -71,7 +71,7 @@ void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering
return;
}
- /// Update visual server vertices
+ /// Update rendering server vertices
const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes);
const int nodes_count = nodes.size();
@@ -116,6 +116,7 @@ void SoftBodyBullet::set_soft_mesh(RID p_mesh) {
}
Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0);
+ ERR_FAIL_COND(arrays.is_empty());
bool success = set_trimesh_body_shape(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
if (!success) {
@@ -298,11 +299,11 @@ bool SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector
ERR_FAIL_COND_V(p_indices.is_empty(), false);
ERR_FAIL_COND_V(p_vertices.is_empty(), false);
- /// Parse visual server indices to physical indices.
- /// Merge all overlapping vertices and create a map of physical vertices to visual server
+ /// Parse rendering server indices to physical indices.
+ /// Merge all overlapping vertices and create a map of physical vertices to rendering server
{
- /// This is the map of visual server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map
+ /// This is the map of rendering server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map
Vector<int> vs_indices_to_physics_table;
{ // Map vertices
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 53694035dc..5ffe644495 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -408,7 +408,7 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b
} break;
- case OPERATION_SUBSTRACTION: {
+ case OPERATION_SUBTRACTION: {
int face_count = 0;
for (int i = 0; i < mesh_merge.faces.size(); i++) {
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index c872860486..b1fe933268 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -67,7 +67,7 @@ struct CSGBrushOperation {
enum Operation {
OPERATION_UNION,
OPERATION_INTERSECTION,
- OPERATION_SUBSTRACTION,
+ OPERATION_SUBTRACTION,
};
void merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index e4297a593e..863936ab8c 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -192,7 +192,7 @@ CSGBrush *CSGShape3D::_get_brush() {
bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap);
break;
case CSGShape3D::OPERATION_SUBTRACTION:
- bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap);
+ bop.merge_brushes(CSGBrushOperation::OPERATION_SUBTRACTION, *n, *nn2, *nn, snap);
break;
}
memdelete(n);
@@ -576,6 +576,7 @@ void CSGShape3D::_validate_property(PropertyInfo &property) const {
} else if (is_collision_prefixed && !bool(get("use_collision"))) {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
+ GeometryInstance3D::_validate_property(property);
}
Array CSGShape3D::get_meshes() const {
diff --git a/modules/denoise/config.py b/modules/denoise/config.py
index 49a1f036ed..6f650354cb 100644
--- a/modules/denoise/config.py
+++ b/modules/denoise/config.py
@@ -1,11 +1,12 @@
def can_build(env, platform):
# Thirdparty dependency OpenImage Denoise includes oneDNN library
- # which only supports 64-bit architectures.
+ # and the version we use only supports x86_64.
# It's also only relevant for tools build and desktop platforms,
# as doing lightmap generation and denoising on Android or HTML5
# would be a bit far-fetched.
desktop_platforms = ["linuxbsd", "osx", "windows"]
- return env["tools"] and platform in desktop_platforms and env["bits"] == "64" and env["arch"] != "arm64"
+ supported_arch = env["bits"] == "64" and env["arch"] != "arm64" and not env["arch"].startswith("rv")
+ return env["tools"] and platform in desktop_platforms and supported_arch
def configure(env):
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index 7343bf87af..e1eacc68b3 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -357,7 +357,6 @@ ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, c
mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED);
// Add surfaces.
- int in_mesh_surface_id = 0;
for (const SurfaceId *surface_id = surfaces.next(nullptr); surface_id != nullptr; surface_id = surfaces.next(surface_id)) {
SurfaceData *surface = surfaces.getptr(*surface_id);
@@ -377,8 +376,6 @@ ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, c
} else {
mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes);
}
-
- in_mesh_surface_id += 1;
}
ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D);
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
index 3dc163964c..11eed2576f 100644
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -104,6 +104,13 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
+ {
+ Transform3D base_xform = bone->node->pivot_transform->LocalTransform;
+
+ skeleton->set_bone_pose_position(bone_index, base_xform.origin);
+ skeleton->set_bone_pose_rotation(bone_index, base_xform.basis.get_rotation_quaternion());
+ skeleton->set_bone_pose_scale(bone_index, base_xform.basis.get_scale());
+ }
// lookup parent ID
if (bone->valid_parent && state.fbx_bone_map.has(bone->parent_bone_id)) {
diff --git a/modules/fbx/doc_classes/EditorSceneImporterFBX.xml b/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
deleted file mode 100644
index 6f83871772..0000000000
--- a/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterFBX" inherits="EditorSceneImporter" version="4.0">
- <brief_description>
- FBX 3D asset importer.
- </brief_description>
- <description>
- This is an FBX 3D asset importer with full support for most FBX features.
- If exporting a FBX scene from Autodesk Maya, use these FBX export settings:
- [codeblock]
- - Smoothing Groups
- - Smooth Mesh
- - Triangluate (for meshes with blend shapes)
- - Bake Animation
- - Resample All
- - Deformed Models
- - Skins
- - Blend Shapes
- - Curve Filters
- - Constant Key Reducer
- - Auto Tangents Only
- - *Do not check* Constraints (as it will break the file)
- - Can check Embed Media (embeds textures into the exported FBX file)
- - Note that when importing embedded media, the texture and mesh will be a single immutable file.
- - You will have to re-export then re-import the FBX if the texture has changed.
- - Units: Centimeters
- - Up Axis: Y
- - Binary format in FBX 2017
- [/codeblock]
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index e4de204cf1..9bdeafbf91 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -56,7 +56,7 @@
#include <string>
-void EditorSceneImporterFBX::get_extensions(List<String> *r_extensions) const {
+void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) const {
// register FBX as the one and only format for FBX importing
const String import_setting_string = "filesystem/import/fbx/";
const String fbx_str = "fbx";
@@ -65,7 +65,7 @@ void EditorSceneImporterFBX::get_extensions(List<String> *r_extensions) const {
_register_project_setting_import(fbx_str, import_setting_string, exts, r_extensions, true);
}
-void EditorSceneImporterFBX::_register_project_setting_import(const String generic,
+void EditorSceneFormatImporterFBX::_register_project_setting_import(const String generic,
const String import_setting_string,
const Vector<String> &exts,
List<String> *r_extensions,
@@ -79,11 +79,11 @@ void EditorSceneImporterFBX::_register_project_setting_import(const String gener
}
}
-uint32_t EditorSceneImporterFBX::get_import_flags() const {
+uint32_t EditorSceneFormatImporterFBX::get_import_flags() const {
return IMPORT_SCENE;
}
-Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps,
+Node3D *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err) {
// done for performance when re-importing lots of files when testing importer in verbose only!
if (OS::get_singleton()->is_stdout_verbose()) {
@@ -232,7 +232,7 @@ Node3D *EditorSceneImporterFBX::import_scene(const String &p_path, uint32_t p_fl
}
template <class T>
-struct EditorSceneImporterAssetImportInterpolate {
+struct EditorSceneFormatImporterAssetImportInterpolate {
T lerp(const T &a, const T &b, float c) const {
return a + (b - a) * c;
}
@@ -258,7 +258,7 @@ struct EditorSceneImporterAssetImportInterpolate {
//thank you for existing, partial specialization
template <>
-struct EditorSceneImporterAssetImportInterpolate<Quaternion> {
+struct EditorSceneFormatImporterAssetImportInterpolate<Quaternion> {
Quaternion lerp(const Quaternion &a, const Quaternion &b, float c) const {
ERR_FAIL_COND_V(!a.is_normalized(), Quaternion());
ERR_FAIL_COND_V(!b.is_normalized(), Quaternion());
@@ -282,7 +282,7 @@ struct EditorSceneImporterAssetImportInterpolate<Quaternion> {
};
template <class T>
-T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, float p_time,
+T EditorSceneFormatImporterFBX::_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;
@@ -293,7 +293,7 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const
idx++;
}
- EditorSceneImporterAssetImportInterpolate<T> interp;
+ EditorSceneFormatImporterAssetImportInterpolate<T> interp;
switch (p_interp) {
case AssetImportAnimation::INTERP_LINEAR: {
@@ -352,7 +352,7 @@ T EditorSceneImporterFBX::_interpolate_track(const Vector<float> &p_times, const
ERR_FAIL_V(p_values[0]);
}
-Node3D *EditorSceneImporterFBX::_generate_scene(
+Node3D *EditorSceneFormatImporterFBX::_generate_scene(
const String &p_path,
const FBXDocParser::Document *p_document,
const uint32_t p_flags,
@@ -1011,9 +1011,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// track count is 5.
// next track id is 5.
const uint64_t target_id = track.key;
- int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D);
- // animation->track_set_path(track_idx, node_path);
Ref<FBXBone> bone;
// note we must not run the below code if the entry doesn't exist, it will create dummy entries which is very bad.
@@ -1037,22 +1035,21 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// if this is a skeleton mapped track we can just set the path for the track.
// todo: implement node paths here at some
+ NodePath track_path;
if (state.fbx_bone_map.size() > 0 && state.fbx_bone_map.has(target_id)) {
if (bone->fbx_skeleton.is_valid() && bone.is_valid()) {
Ref<FBXSkeleton> fbx_skeleton = bone->fbx_skeleton;
String bone_path = state.root->get_path_to(fbx_skeleton->skeleton);
bone_path += ":" + fbx_skeleton->skeleton->get_bone_name(bone->godot_bone_id);
print_verbose("[doc] track bone path: " + bone_path);
- NodePath path = bone_path;
- animation->track_set_path(track_idx, path);
+ track_path = bone_path;
}
} else if (state.fbx_target_map.has(target_id)) {
//print_verbose("[doc] we have a valid target for a node animation");
Ref<FBXNode> target_node = state.fbx_target_map[target_id];
if (target_node.is_valid() && target_node->godot_node != nullptr) {
String node_path = state.root->get_path_to(target_node->godot_node);
- NodePath path = node_path;
- animation->track_set_path(track_idx, path);
+ track_path = node_path;
//print_verbose("[doc] node animation path: " + node_path);
}
} else {
@@ -1186,6 +1183,30 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale();
print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")");
+ int position_idx = -1;
+ if (pos_values.size()) {
+ position_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_POSITION_3D);
+ animation->track_set_path(position_idx, track_path);
+ animation->track_set_imported(position_idx, true);
+ }
+
+ int rotation_idx = -1;
+ if (pos_values.size()) {
+ rotation_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_ROTATION_3D);
+ animation->track_set_path(rotation_idx, track_path);
+ animation->track_set_imported(rotation_idx, true);
+ }
+
+ int scale_idx = -1;
+ if (pos_values.size()) {
+ scale_idx = animation->get_track_count();
+ animation->add_track(Animation::TYPE_SCALE_3D);
+ animation->track_set_path(scale_idx, track_path);
+ animation->track_set_imported(scale_idx, true);
+ }
+
while (true) {
Vector3 pos = def_pos;
Quaternion rot = def_rot;
@@ -1206,21 +1227,15 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
AssetImportAnimation::INTERP_LINEAR);
}
- // node animations must also include pivots
- if (skeleton_bone >= 0) {
- Transform3D xform = Transform3D();
- xform.basis.set_quaternion_scale(rot, scale);
- xform.origin = pos;
- const Transform3D t = bone_rest.affine_inverse() * xform;
-
- // populate this again
- rot = t.basis.get_rotation_quaternion();
- rot.normalize();
- scale = t.basis.get_scale();
- pos = t.origin;
+ if (position_idx >= 0) {
+ animation->position_track_insert_key(position_idx, time, pos);
+ }
+ if (rotation_idx >= 0) {
+ animation->rotation_track_insert_key(rotation_idx, time, rot);
+ }
+ if (scale_idx >= 0) {
+ animation->scale_track_insert_key(scale_idx, time, scale);
}
-
- animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
if (last) {
break;
@@ -1279,7 +1294,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
return scene_root;
}
-void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone,
+void EditorSceneFormatImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone,
ImportState &state, const FBXDocParser::Document *p_doc,
uint64_t p_id) {
const std::vector<const FBXDocParser::Connection *> &conns = p_doc->GetConnectionsByDestinationSequenced(p_id, "Model");
@@ -1368,7 +1383,7 @@ void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone,
}
}
-void EditorSceneImporterFBX::BuildDocumentNodes(
+void EditorSceneFormatImporterFBX::BuildDocumentNodes(
Ref<PivotTransform> parent_transform,
ImportState &state,
const FBXDocParser::Document *p_doc,
diff --git a/modules/fbx/editor_scene_importer_fbx.h b/modules/fbx/editor_scene_importer_fbx.h
index 4a3b78480b..7845e079c2 100644
--- a/modules/fbx/editor_scene_importer_fbx.h
+++ b/modules/fbx/editor_scene_importer_fbx.h
@@ -57,9 +57,9 @@
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
-class EditorSceneImporterFBX : public EditorSceneImporter {
+class EditorSceneFormatImporterFBX : public EditorSceneFormatImporter {
private:
- GDCLASS(EditorSceneImporterFBX, EditorSceneImporter);
+ GDCLASS(EditorSceneFormatImporterFBX, EditorSceneFormatImporter);
struct AssetImportAnimation {
enum Interpolation {
@@ -122,8 +122,8 @@ private:
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;
public:
- EditorSceneImporterFBX() {}
- ~EditorSceneImporterFBX() {}
+ EditorSceneFormatImporterFBX() {}
+ ~EditorSceneFormatImporterFBX() {}
virtual void get_extensions(List<String> *r_extensions) const override;
virtual uint32_t get_import_flags() const override;
diff --git a/modules/fbx/register_types.cpp b/modules/fbx/register_types.cpp
index a75da8f3a9..d5e520a060 100644
--- a/modules/fbx/register_types.cpp
+++ b/modules/fbx/register_types.cpp
@@ -35,7 +35,7 @@
#ifdef TOOLS_ENABLED
static void _editor_init() {
- Ref<EditorSceneImporterFBX> import_fbx;
+ Ref<EditorSceneFormatImporterFBX> import_fbx;
import_fbx.instantiate();
ResourceImporterScene::get_singleton()->add_importer(import_fbx);
}
@@ -46,7 +46,7 @@ void register_fbx_types() {
ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(EditorSceneImporterFBX);
+ GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
ClassDB::set_current_api(prev_api);
diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp
index 66b0153308..bb95d120af 100644
--- a/modules/fbx/tools/import_utils.cpp
+++ b/modules/fbx/tools/import_utils.cpp
@@ -45,27 +45,27 @@ Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
switch (mode) {
case FBXDocParser::Model::RotOrder_EulerXYZ:
- ret.set_euler_zyx(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_XYZ);
break;
case FBXDocParser::Model::RotOrder_EulerXZY:
- ret.set_euler_yzx(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_XZY);
break;
case FBXDocParser::Model::RotOrder_EulerYZX:
- ret.set_euler_xzy(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_YZX);
break;
case FBXDocParser::Model::RotOrder_EulerYXZ:
- ret.set_euler_zxy(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_YXZ);
break;
case FBXDocParser::Model::RotOrder_EulerZXY:
- ret.set_euler_yxz(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_ZXY);
break;
case FBXDocParser::Model::RotOrder_EulerZYX:
- ret.set_euler_xyz(p_rotation);
+ ret.set_euler(p_rotation, Basis::EULER_ORDER_ZYX);
break;
case FBXDocParser::Model::RotOrder_SphericXYZ:
@@ -89,22 +89,22 @@ Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basi
// by simply invert its order: https://www.cs.utexas.edu/~theshark/courses/cs354/lectures/cs354-14.pdf
switch (mode) {
case FBXDocParser::Model::RotOrder_EulerXYZ:
- return p_rotation.get_euler_zyx();
+ return p_rotation.get_euler(Basis::EULER_ORDER_XYZ);
case FBXDocParser::Model::RotOrder_EulerXZY:
- return p_rotation.get_euler_yzx();
+ return p_rotation.get_euler(Basis::EULER_ORDER_XZY);
case FBXDocParser::Model::RotOrder_EulerYZX:
- return p_rotation.get_euler_xzy();
+ return p_rotation.get_euler(Basis::EULER_ORDER_YZX);
case FBXDocParser::Model::RotOrder_EulerYXZ:
- return p_rotation.get_euler_zxy();
+ return p_rotation.get_euler(Basis::EULER_ORDER_YXZ);
case FBXDocParser::Model::RotOrder_EulerZXY:
- return p_rotation.get_euler_yxz();
+ return p_rotation.get_euler(Basis::EULER_ORDER_ZXY);
case FBXDocParser::Model::RotOrder_EulerZYX:
- return p_rotation.get_euler_xyz();
+ return p_rotation.get_euler(Basis::EULER_ORDER_ZYX);
case FBXDocParser::Model::RotOrder_SphericXYZ:
// TODO
diff --git a/modules/gdnative/gdnative/gdnative.cpp b/modules/gdnative/gdnative/gdnative.cpp
index b84ce2d192..e0de1a0505 100644
--- a/modules/gdnative/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative/gdnative.cpp
@@ -129,13 +129,13 @@ void GDAPI godot_free(void *p_ptr) {
// Helper print functions.
void GDAPI godot_print_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR);
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_ERROR);
}
void GDAPI godot_print_warning(const char *p_description, const char *p_function, const char *p_file, int p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING);
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_WARNING);
}
void GDAPI godot_print_script_error(const char *p_description, const char *p_function, const char *p_file, int p_line) {
- _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_SCRIPT);
+ _err_print_error(p_function, p_file, p_line, p_description, false, ERR_HANDLER_SCRIPT);
}
void _gdnative_report_version_mismatch(const godot_object *p_library, const char *p_ext, godot_gdnative_api_version p_want, godot_gdnative_api_version p_have) {
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index fb46bafb3c..368eb67fa6 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -1139,15 +1139,12 @@ void NativeScriptLanguage::profiling_start() {
MutexLock lock(mutex);
profile_data.clear();
- profiling = true;
#endif
}
void NativeScriptLanguage::profiling_stop() {
#ifdef DEBUG_ENABLED
MutexLock lock(mutex);
-
- profiling = false;
#endif
}
diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h
index a7647e8c59..2364c6c0f6 100644
--- a/modules/gdnative/nativescript/nativescript.h
+++ b/modules/gdnative/nativescript/nativescript.h
@@ -269,7 +269,6 @@ private:
};
Map<StringName, ProfileData> profile_data;
- bool profiling = false;
public:
// These two maps must only be touched on the main thread
@@ -295,8 +294,6 @@ public:
return singleton;
}
- void _hacky_api_anchor();
-
_FORCE_INLINE_ void set_language_index(int p_idx) { lang_idx = p_idx; }
#ifndef NO_THREADS
diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h
index bdae265db2..81e711bafc 100644
--- a/modules/gdnative/pluginscript/pluginscript_instance.h
+++ b/modules/gdnative/pluginscript/pluginscript_instance.h
@@ -69,8 +69,6 @@ public:
virtual ScriptLanguage *get_language();
- void set_path(const String &p_path);
-
virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const;
virtual void refcount_incremented();
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 2bae838543..42865242d3 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -545,7 +545,7 @@ void GDScript::_update_doc() {
for (int i = 0; i < signals.size(); i++) {
DocData::MethodDoc signal_doc;
if (doc_signals.has(signals[i].name)) {
- DocData::signal_doc_from_methodinfo(signal_doc, signals[i], signals[i].name);
+ DocData::signal_doc_from_methodinfo(signal_doc, signals[i], doc_signals[signals[i].name]);
} else {
DocData::signal_doc_from_methodinfo(signal_doc, signals[i], String());
}
@@ -835,7 +835,7 @@ Error GDScript::reload(bool p_keep_state) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
// TODO: Show all error messages.
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_PARSE_ERROR);
}
@@ -849,7 +849,7 @@ Error GDScript::reload(bool p_keep_state) {
const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
while (e != nullptr) {
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
e = e->next();
}
ERR_FAIL_V(ERR_PARSE_ERROR);
@@ -869,7 +869,7 @@ Error GDScript::reload(bool p_keep_state) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
}
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_COMPILATION_FAILED);
} else {
return err;
@@ -879,7 +879,7 @@ Error GDScript::reload(bool p_keep_state) {
for (const GDScriptWarning &warning : parser.get_warnings()) {
if (EngineDebugger::is_active()) {
Vector<ScriptLanguage::StackInfo> si;
- EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
+ EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), false, ERR_HANDLER_WARNING, si);
}
}
#endif
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 3abd8672fa..cd8fd361c5 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -470,6 +470,8 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type);
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
+ container_type.is_meta_type = false;
+ container_type.is_constant = false;
result.set_container_element_type(container_type);
}
}
@@ -875,18 +877,34 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
- // Do functions now.
+ // Do functions and properties now.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::FUNCTION) {
- continue;
- }
+ if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
+ resolve_function_body(member.function);
+
+ // Apply annotations.
+ for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
+ E->apply(parser, member.function);
+ }
+ } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {
+ if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
+ if (member.variable->getter != nullptr) {
+ member.variable->getter->set_datatype(member.variable->datatype);
- resolve_function_body(member.function);
+ resolve_function_body(member.variable->getter);
+ }
+ if (member.variable->setter != nullptr) {
+ resolve_function_signature(member.variable->setter);
+
+ if (member.variable->setter->parameters.size() > 0) {
+ member.variable->setter->parameters[0]->datatype_specifier = member.variable->datatype_specifier;
+ member.variable->setter->parameters[0]->set_datatype(member.get_datatype());
+ }
- // Apply annotations.
- for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
- E->apply(parser, member.function);
+ resolve_function_body(member.variable->setter);
+ }
+ }
}
}
@@ -902,17 +920,80 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
resolve_class_body(member.m_class);
}
- // Check unused variables.
+ // Check unused variables and datatypes of property getters and setters.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) {
- continue;
- }
+ if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
- if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
- parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
- }
+ if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
+ parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
+ }
+#endif
+
+ if (member.variable->property == GDScriptParser::VariableNode::PROP_SETGET) {
+ GDScriptParser::FunctionNode *getter_function = nullptr;
+ GDScriptParser::FunctionNode *setter_function = nullptr;
+
+ bool has_valid_getter = false;
+ bool has_valid_setter = false;
+
+ if (member.variable->getter_pointer != nullptr) {
+ if (p_class->has_function(member.variable->getter_pointer->name)) {
+ getter_function = p_class->get_member(member.variable->getter_pointer->name).function;
+ }
+
+ if (getter_function == nullptr) {
+ push_error(vformat(R"(Getter "%s" not found.)", member.variable->getter_pointer->name), member.variable);
+
+ } else if (getter_function->parameters.size() != 0 || getter_function->datatype.has_no_type()) {
+ push_error(vformat(R"(Function "%s" cannot be used as getter because of its signature.)", getter_function->identifier->name), member.variable);
+
+ } else if (!is_type_compatible(member.variable->datatype, getter_function->datatype, true)) {
+ push_error(vformat(R"(Function with return type "%s" cannot be used as getter for a property of type "%s".)", getter_function->datatype.to_string(), member.variable->datatype.to_string()), member.variable);
+
+ } else {
+ has_valid_getter = true;
+
+#ifdef DEBUG_ENABLED
+ if (member.variable->datatype.builtin_type == Variant::INT && getter_function->datatype.builtin_type == Variant::FLOAT) {
+ parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
+ }
+#endif
+ }
+ }
+
+ if (member.variable->setter_pointer != nullptr) {
+ if (p_class->has_function(member.variable->setter_pointer->name)) {
+ setter_function = p_class->get_member(member.variable->setter_pointer->name).function;
+ }
+
+ if (setter_function == nullptr) {
+ push_error(vformat(R"(Setter "%s" not found.)", member.variable->setter_pointer->name), member.variable);
+
+ } else if (setter_function->parameters.size() != 1) {
+ push_error(vformat(R"(Function "%s" cannot be used as setter because of its signature.)", setter_function->identifier->name), member.variable);
+
+ } else if (!is_type_compatible(member.variable->datatype, setter_function->parameters[0]->datatype, true)) {
+ push_error(vformat(R"(Function with argument type "%s" cannot be used as setter for a property of type "%s".)", setter_function->parameters[0]->datatype.to_string(), member.variable->datatype.to_string()), member.variable);
+
+ } else {
+ has_valid_setter = true;
+
+#ifdef DEBUG_ENABLED
+ if (member.variable->datatype.builtin_type == Variant::FLOAT && setter_function->parameters[0]->datatype.builtin_type == Variant::INT) {
+ parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
+ }
#endif
+ }
+ }
+
+ if (member.variable->datatype.is_variant() && has_valid_getter && has_valid_setter) {
+ if (!is_type_compatible(getter_function->datatype, setter_function->parameters[0]->datatype, true)) {
+ push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable);
+ }
+ }
+ }
+ }
}
}
@@ -989,7 +1070,7 @@ void GDScriptAnalyzer::resolve_node(GDScriptParser::Node *p_node) {
case GDScriptParser::Node::SUBSCRIPT:
case GDScriptParser::Node::TERNARY_OPERATOR:
case GDScriptParser::Node::UNARY_OPERATOR:
- reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node));
+ reduce_expression(static_cast<GDScriptParser::ExpressionNode *>(p_node), true);
break;
case GDScriptParser::Node::BREAK:
case GDScriptParser::Node::BREAKPOINT:
@@ -1529,12 +1610,20 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame
void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
GDScriptParser::DataType result;
+ GDScriptParser::DataType expected_type;
+ bool has_expected_type = false;
+
+ if (parser->current_function != nullptr) {
+ expected_type = parser->current_function->get_datatype();
+ has_expected_type = true;
+ }
+
if (p_return->return_value != nullptr) {
reduce_expression(p_return->return_value);
if (p_return->return_value->type == GDScriptParser::Node::ARRAY) {
// Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
- if (parser->current_function->get_datatype().has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
- update_array_literal_element_type(parser->current_function->get_datatype(), static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
+ if (has_expected_type && expected_type.has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
}
}
result = p_return->return_value->get_datatype();
@@ -1546,30 +1635,31 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
result.is_constant = true;
}
- GDScriptParser::DataType function_type = parser->current_function->get_datatype();
- function_type.is_meta_type = false;
- if (function_type.is_hard_type()) {
- if (!is_type_compatible(function_type, result)) {
- // Try other way. Okay but not safe.
- if (!is_type_compatible(result, function_type)) {
- push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), function_type.to_string()), p_return);
- } else {
- // TODO: Add warning.
- mark_node_unsafe(p_return);
- }
+ if (has_expected_type) {
+ expected_type.is_meta_type = false;
+ if (expected_type.is_hard_type()) {
+ if (!is_type_compatible(expected_type, result)) {
+ // Try other way. Okay but not safe.
+ if (!is_type_compatible(result, expected_type)) {
+ push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return);
+ } else {
+ // TODO: Add warning.
+ mark_node_unsafe(p_return);
+ }
#ifdef DEBUG_ENABLED
- } else if (function_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
- parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
- } else if (result.is_variant()) {
- mark_node_unsafe(p_return);
+ } else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
+ parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
+ } else if (result.is_variant()) {
+ mark_node_unsafe(p_return);
#endif
+ }
}
}
p_return->set_datatype(result);
}
-void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression) {
+void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root) {
// This one makes some magic happen.
if (p_expression == nullptr) {
@@ -1597,7 +1687,7 @@ void GDScriptAnalyzer::reduce_expression(GDScriptParser::ExpressionNode *p_expre
reduce_binary_op(static_cast<GDScriptParser::BinaryOpNode *>(p_expression));
break;
case GDScriptParser::Node::CALL:
- reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression));
+ reduce_call(static_cast<GDScriptParser::CallNode *>(p_expression), p_is_root);
break;
case GDScriptParser::Node::CAST:
reduce_cast(static_cast<GDScriptParser::CastNode *>(p_expression));
@@ -1713,6 +1803,7 @@ void GDScriptAnalyzer::update_array_literal_element_type(const GDScriptParser::D
}
}
if (all_same_type) {
+ element_type.is_constant = false;
array_type.set_container_element_type(element_type);
} else if (all_have_type) {
push_error(vformat(R"(Variant array is not compatible with an array of type "%s".)", p_base_type.get_container_element_type().to_string()), p_array_literal);
@@ -1838,16 +1929,25 @@ void GDScriptAnalyzer::reduce_await(GDScriptParser::AwaitNode *p_await) {
p_await->set_datatype(await_type);
return;
}
+
+ GDScriptParser::DataType awaiting_type;
+
if (p_await->to_await->type == GDScriptParser::Node::CALL) {
reduce_call(static_cast<GDScriptParser::CallNode *>(p_await->to_await), true);
+ awaiting_type = p_await->to_await->get_datatype();
} else {
reduce_expression(p_await->to_await);
}
- p_await->is_constant = p_await->to_await->is_constant;
- p_await->reduced_value = p_await->to_await->reduced_value;
+ if (p_await->to_await->is_constant) {
+ p_await->is_constant = p_await->to_await->is_constant;
+ p_await->reduced_value = p_await->to_await->reduced_value;
- GDScriptParser::DataType awaiting_type = p_await->to_await->get_datatype();
+ awaiting_type = p_await->to_await->get_datatype();
+ } else {
+ awaiting_type.kind = GDScriptParser::DataType::VARIANT;
+ awaiting_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ }
p_await->set_datatype(awaiting_type);
@@ -1967,7 +2067,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
p_binary_op->set_datatype(result);
}
-void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_await) {
+void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await, bool p_is_root) {
bool all_is_constant = true;
Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
for (int i = 0; i < p_call->arguments.size(); i++) {
@@ -2326,7 +2426,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
}
}
- if (call_type.is_coroutine && !is_await) {
+ if (call_type.is_coroutine && !p_is_await && !p_is_root) {
push_error(vformat(R"*(Function "%s()" is a coroutine, so it must be called with "await".)*", p_call->function_name), p_call->callee);
}
@@ -2594,6 +2694,11 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->is_constant = false;
return;
} break;
+ case GDScriptParser::ClassNode::Member::CLASS: {
+ resolve_class_interface(member.m_class);
+ p_identifier->set_datatype(member.m_class->get_datatype());
+ return;
+ } break;
default:
break;
}
@@ -2608,10 +2713,13 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
const StringName &native = base.native_type;
if (class_exists(native)) {
- PropertyInfo prop_info;
MethodInfo method_info;
- if (ClassDB::get_property_info(native, name, &prop_info)) {
- p_identifier->set_datatype(type_from_property(prop_info));
+ if (ClassDB::has_property(native, name)) {
+ StringName getter_name = ClassDB::get_property_getter(native, name);
+ MethodBind *getter = ClassDB::get_method(native, getter_name);
+ if (getter != nullptr) {
+ p_identifier->set_datatype(type_from_property(getter->get_return_info()));
+ }
return;
}
if (ClassDB::get_method_info(native, name, &method_info)) {
@@ -3392,6 +3500,7 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
} else {
ERR_FAIL_V_MSG(result, "Could not find element type from property hint of a typed array.");
}
+ elem_type.is_constant = false;
result.set_container_element_type(elem_type);
}
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 2e17e15452..ce4525190b 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -78,12 +78,12 @@ class GDScriptAnalyzer {
void resolve_return(GDScriptParser::ReturnNode *p_return);
// Reduction functions.
- void reduce_expression(GDScriptParser::ExpressionNode *p_expression);
+ void reduce_expression(GDScriptParser::ExpressionNode *p_expression, bool p_is_root = false);
void reduce_array(GDScriptParser::ArrayNode *p_array);
void reduce_assignment(GDScriptParser::AssignmentNode *p_assignment);
void reduce_await(GDScriptParser::AwaitNode *p_await);
void reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_op);
- void reduce_call(GDScriptParser::CallNode *p_call, bool is_await = false);
+ void reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await = false, bool p_is_root = false);
void reduce_cast(GDScriptParser::CastNode *p_cast);
void reduce_dictionary(GDScriptParser::DictionaryNode *p_dictionary);
void reduce_get_node(GDScriptParser::GetNodeNode *p_get_node);
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index b8300cd872..6a7e4278d2 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -692,7 +692,8 @@ void GDScriptByteCodeGenerator::write_end_ternary() {
void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {
if (HAS_BUILTIN_TYPE(p_target)) {
- if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type)) {
+ if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type) &&
+ IS_BUILTIN_TYPE(p_source, Variant::get_indexed_element_type(p_target.type.builtin_type))) {
// Use indexed setter instead.
Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type);
append(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED, 3);
@@ -746,7 +747,8 @@ void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address
}
void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
- if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name)) {
+ if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name) &&
+ IS_BUILTIN_TYPE(p_source, Variant::get_member_type(p_target.type.builtin_type, p_name))) {
Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name);
append(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED, 2);
append(p_target);
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 9eee0b57f3..ab0fe5c37d 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -109,7 +109,9 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
+ const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->path);
+ const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->name);
+ if (is_inner_by_path || is_inner_by_name) {
// Local class.
List<StringName> names;
while (class_type->outer) {
@@ -486,6 +488,9 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(p_expression);
GDScriptDataType type = _gdtype_from_datatype(call->get_datatype());
GDScriptCodeGenerator::Address result = codegen.add_temporary(type);
+ GDScriptCodeGenerator::Address nil = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::NIL);
+
+ GDScriptCodeGenerator::Address return_addr = p_root ? nil : result;
Vector<GDScriptCodeGenerator::Address> arguments;
for (int i = 0; i < call->arguments.size(); i++) {
@@ -536,13 +541,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (within_await) {
gen->write_call_async(result, self, call->function_name, arguments);
} else {
- gen->write_call(result, self, call->function_name, arguments);
+ gen->write_call(return_addr, self, call->function_name, arguments);
}
} else {
if (within_await) {
gen->write_call_self_async(result, call->function_name, arguments);
} else {
- gen->write_call_self(result, call->function_name, arguments);
+ gen->write_call_self(return_addr, call->function_name, arguments);
}
}
} else if (callee->type == GDScriptParser::Node::SUBSCRIPT) {
@@ -577,12 +582,12 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
gen->write_call_method_bind(result, base, method, arguments);
}
} else {
- gen->write_call(result, base, call->function_name, arguments);
+ gen->write_call(return_addr, base, call->function_name, arguments);
}
} else if (base.type.has_type && base.type.kind == GDScriptDataType::BUILTIN) {
gen->write_call_builtin_type(result, base, base.type.builtin_type, call->function_name, arguments);
} else {
- gen->write_call(result, base, call->function_name, arguments);
+ gen->write_call(return_addr, base, call->function_name, arguments);
}
if (base.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
@@ -2087,77 +2092,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
Error error = OK;
- CodeGen codegen;
- codegen.generator = memnew(GDScriptByteCodeGenerator);
-
- codegen.class_node = p_class;
- codegen.script = p_script;
- StringName func_name;
+ GDScriptParser::FunctionNode *function;
if (p_is_setter) {
- func_name = "@" + p_variable->identifier->name + "_setter";
+ function = p_variable->setter;
} else {
- func_name = "@" + p_variable->identifier->name + "_getter";
- }
-
- codegen.function_name = func_name;
-
- GDScriptDataType return_type;
- if (p_is_setter) {
- return_type.has_type = true;
- return_type.kind = GDScriptDataType::BUILTIN;
- return_type.builtin_type = Variant::NIL;
- } else {
- return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script);
- }
-
- codegen.generator->write_start(p_script, func_name, false, Multiplayer::RPCConfig(), return_type);
-
- if (p_is_setter) {
- uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype()));
- codegen.parameters[p_variable->setter_parameter->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, _gdtype_from_datatype(p_variable->get_datatype()));
- }
-
- error = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter);
- if (error) {
- memdelete(codegen.generator);
- return error;
- }
-
- GDScriptFunction *gd_function = codegen.generator->write_end();
-
- p_script->member_functions[func_name] = gd_function;
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- String signature;
- //path
- if (p_script->get_path() != String()) {
- signature += p_script->get_path();
- }
- //loc
- signature += "::" + itos(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-
- //function and class
-
- if (p_class->identifier) {
- signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
- } else {
- signature += "::" + String(func_name);
- }
-
- codegen.generator->set_signature(signature);
+ function = p_variable->getter;
}
-#endif
- codegen.generator->set_initial_line(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line;
-#endif
- memdelete(codegen.generator);
+ _parse_function(error, p_script, p_class, function);
- return OK;
+ return error;
}
Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index e49bf518a2..71d2699c2e 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1089,6 +1089,15 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
kwa++;
}
+ List<StringName> utility_func_names;
+ Variant::get_utility_function_list(&utility_func_names);
+
+ for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ option.insert_text += "(";
+ r_result.insert(option.display, option);
+ }
+
OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
if (!E.value().is_singleton) {
@@ -2325,7 +2334,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptCompletionIdentifier connect_base;
- if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ if (Variant::has_utility_function(call->function_name)) {
+ MethodInfo info = Variant::get_utility_function_info(call->function_name);
+ r_arghint = _make_arguments_hint(info, p_argidx);
+ return;
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_arghint = _make_arguments_hint(info, p_argidx);
return;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index ef3059e6aa..8cb25e2c03 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -947,7 +947,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var
void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)");
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) {
p_variable->setter_parameter = parse_identifier();
@@ -955,9 +955,32 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*");
consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*");
- p_variable->setter = parse_suite("setter definition");
- break;
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_setter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ ParameterNode *parameter = alloc_node<ParameterNode>();
+ parameter->identifier = p_variable->setter_parameter;
+
+ if (parameter->identifier != nullptr) {
+ function->parameters_indices[parameter->identifier->name] = 0;
+ function->parameters.push_back(parameter);
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ body->add_local(parameter, function);
+
+ function->body = parse_suite("setter declaration", body);
+ p_variable->setter = function;
+ }
+ current_function = previous_function;
+ break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "set")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -972,11 +995,25 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
void GDScriptParser::parse_property_getter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)");
- p_variable->getter = parse_suite("getter definition");
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_getter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ function->body = parse_suite("getter declaration", body);
+
+ p_variable->getter = function;
+ current_function = previous_function;
break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "get")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -3423,7 +3460,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String enum_hint_string;
for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
- enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ enum_hint_string += E->key().operator String().capitalize().xml_escape();
enum_hint_string += ":";
enum_hint_string += String::num_int64(E->get()).xml_escape();
@@ -3490,9 +3527,9 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod
} else if (mode == "authority") {
rpc_config.rpc_mode = Multiplayer::RPC_MODE_AUTHORITY;
} else if (mode == "call_local") {
- rpc_config.sync = true;
+ rpc_config.call_local = true;
} else if (mode == "call_remote") {
- rpc_config.sync = false;
+ rpc_config.call_local = false;
} else if (mode == "reliable") {
rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
} else if (mode == "unreliable") {
@@ -4437,7 +4474,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
if (p_variable->property == VariableNode::PROP_INLINE) {
push_line(":");
increase_indent();
- print_suite(p_variable->getter);
+ print_suite(p_variable->getter->body);
decrease_indent();
} else {
push_line(" =");
@@ -4457,7 +4494,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
}
push_line("):");
increase_indent();
- print_suite(p_variable->setter);
+ print_suite(p_variable->setter->body);
decrease_indent();
} else {
push_line(" =");
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 593fb0cc5e..af9b973ada 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1109,12 +1109,12 @@ public:
PropertyStyle property = PROP_NONE;
union {
- SuiteNode *setter = nullptr;
+ FunctionNode *setter = nullptr;
IdentifierNode *setter_pointer;
};
IdentifierNode *setter_parameter = nullptr;
union {
- SuiteNode *getter = nullptr;
+ FunctionNode *getter = nullptr;
IdentifierNode *getter_pointer;
};
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index c89cf2f25c..40f03979c6 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1719,6 +1719,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define OPCODE_CALL_PTR(m_type) \
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
CHECK_SPACE(3 + instr_arg_count); \
+ ip += instr_arg_count; \
int argc = _code_ptr[ip + 1]; \
GET_INSTRUCTION_ARG(base, argc); \
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
@@ -2097,8 +2098,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
if (result.get_type() != Variant::SIGNAL) {
+ // Not async, return immediately using the target from OPCODE_AWAIT_RESUME.
+ GET_VARIANT_PTR(target, 3);
+ *target = result;
ip += 4; // Skip OPCODE_AWAIT_RESUME and its data.
- // The stack pointer should be the same, so we don't need to set a return value.
is_signal = false;
} else {
sig = result;
@@ -3312,7 +3315,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
// debugger break did not happen
- _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), false, ERR_HANDLER_SCRIPT);
}
#endif
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 730e554476..f4c0c4d9bb 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -165,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
case ClassNode::Member::VARIABLE: {
lsp::DocumentSymbol symbol;
symbol.name = m.variable->identifier->name;
- symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;
+ symbol.kind = m.variable->property == VariableNode::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;
symbol.deprecated = false;
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column);
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index 85a44a8cc1..f1413f0133 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -50,10 +50,8 @@ class GDScriptLanguageServer : public EditorPlugin {
private:
void _notification(int p_what);
- void _iteration();
public:
- Error parse_script_file(const String &p_path);
GDScriptLanguageServer();
void start();
void stop();
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 50c1f68440..d2e71efee7 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -334,7 +334,7 @@ void GDScriptTest::print_handler(void *p_this, const String &p_message, bool p_e
result->output += p_message + "\n";
}
-void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type) {
+void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, bool p_editor_notify, ErrorHandlerType p_type) {
ErrorHandlerData *data = (ErrorHandlerData *)p_this;
GDScriptTest *self = data->self;
TestResult *result = data->result;
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
index 9b2d14a371..98c57dc97c 100644
--- a/modules/gdscript/tests/gdscript_test_runner.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -87,7 +87,7 @@ private:
public:
static void print_handler(void *p_this, const String &p_message, bool p_error);
- static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type);
+ static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, bool p_editor_notify, ErrorHandlerType p_type);
TestResult run_test();
bool generate_output();
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd
new file mode 100644
index 0000000000..f1be6aaa0c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd
@@ -0,0 +1,11 @@
+var _prop : int
+
+# Getter function has wrong return type.
+var prop : String:
+ get = get_prop
+
+func get_prop():
+ return _prop
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out
new file mode 100644
index 0000000000..29eec51ef2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Function with return type "int" cannot be used as getter for a property of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd
new file mode 100644
index 0000000000..dd190157a1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd
@@ -0,0 +1,11 @@
+var _prop : int
+
+# Setter function has wrong argument type.
+var prop : String:
+ set = set_prop
+
+func set_prop(value : int):
+ _prop = value
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out
new file mode 100644
index 0000000000..7a25280d55
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Function with argument type "int" cannot be used as setter for a property of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd
new file mode 100644
index 0000000000..7f2b29222a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd
@@ -0,0 +1,9 @@
+var _prop : int
+
+# Inline getter returns int instead of String.
+var prop : String:
+ get:
+ return _prop
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out
new file mode 100644
index 0000000000..e0adef1bf8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot return value of type "int" because the function return type is "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd
new file mode 100644
index 0000000000..0ce239dbbd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd
@@ -0,0 +1,9 @@
+var _prop : int
+
+# Inline setter assigns String to int.
+var prop : String:
+ set(value):
+ _prop = value
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out
new file mode 100644
index 0000000000..bbadf1ce27
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a value of type "String" to a target of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd
new file mode 100644
index 0000000000..3bbee5f5f7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd
@@ -0,0 +1,8 @@
+var with_setter := 0:
+ set(val):
+ var x: String = val
+ with_setter = val
+
+func test():
+ with_setter = 1
+ print(with_setter)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out
new file mode 100644
index 0000000000..9eb2a42ccd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Value of type "int" cannot be assigned to a variable of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd
new file mode 100644
index 0000000000..30e7deb05a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.gd
@@ -0,0 +1,19 @@
+class A:
+ var x = 3
+
+class B:
+ var x = 4
+
+class C:
+ var x = 5
+
+class Test:
+ var a = A.new()
+ var b: B = B.new()
+ var c := C.new()
+
+func test():
+ var test_instance := Test.new()
+ prints(test_instance.a.x)
+ prints(test_instance.b.x)
+ prints(test_instance.c.x)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out
new file mode 100644
index 0000000000..a078e62cc7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_from_parent.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+3
+4
+5
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd
new file mode 100644
index 0000000000..1706087f82
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd
@@ -0,0 +1,16 @@
+var _prop = 1
+var prop:
+ get = get_prop, set = set_prop
+
+func get_prop():
+ return _prop
+
+func set_prop(value):
+ _prop = value
+
+func test():
+ print(prop)
+
+ prop = 2
+
+ print(prop)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.out b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out
new file mode 100644
index 0000000000..f1253ca57e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+1
+2
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd
new file mode 100644
index 0000000000..23eb011b23
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd
@@ -0,0 +1,46 @@
+# Untyped inline property
+var prop1:
+ get:
+ return prop1
+ set(value):
+ prop1 = value
+
+# Typed inline property
+var prop2 : int:
+ get:
+ return prop2
+ set(value):
+ prop2 = value
+
+# Typed inline property with default value
+var prop3 : int = 1:
+ get:
+ return prop3
+ set(value):
+ prop3 = value
+
+# Typed inline property with backing variable
+var _prop4 : int = 2
+var prop4: int:
+ get:
+ return _prop4
+ set(value):
+ _prop4 = value
+
+func test():
+ print(prop1)
+ print(prop2)
+ print(prop3)
+ print(prop4)
+
+ print()
+
+ prop1 = 1
+ prop2 = 2
+ prop3 = 3
+ prop4 = 4
+
+ print(prop1)
+ print(prop2)
+ print(prop3)
+ print(prop4)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.out b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
new file mode 100644
index 0000000000..5482592e90
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+null
+0
+1
+2
+
+1
+2
+3
+4
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.gd
new file mode 100644
index 0000000000..55c40cb971
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.gd
@@ -0,0 +1,6 @@
+# https://github.com/godotengine/godot/issues/53640
+
+func test():
+ var arr := [0]
+ arr[0] = 1
+ print(arr[0])
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.out b/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.out
new file mode 100644
index 0000000000..a7f1357bb2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_inferred_access_isnt_constant.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+1
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd
new file mode 100644
index 0000000000..9502f6e196
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd
@@ -0,0 +1,10 @@
+class Inner:
+ var prop = "Inner"
+
+
+var array: Array[Inner] = [Inner.new()]
+
+
+func test():
+ var element: Inner = array[0]
+ print(element.prop)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out
new file mode 100644
index 0000000000..8f250d2632
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+Inner
diff --git a/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd
new file mode 100644
index 0000000000..18174eae67
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.gd
@@ -0,0 +1,32 @@
+# https://github.com/godotengine/godot/issues/48121
+
+func test():
+ var x := []
+ var y := []
+ x.push_back(y)
+ print("TEST ARRAY ADD TO SELF: " + str(len(y)))
+ x.clear()
+
+ x = Array()
+ y = Array()
+ x.push_back(y)
+ print("TEST ARRAY ADD TO SELF: " + str(len(y)))
+ x.clear()
+
+ x = Array().duplicate()
+ y = Array().duplicate()
+ x.push_back(y)
+ print("TEST ARRAY ADD TO SELF: " + str(len(y)))
+ x.clear()
+
+ x = [].duplicate()
+ y = [].duplicate()
+ x.push_back(y)
+ print("TEST ARRAY ADD TO SELF: " + str(len(y)))
+ x.clear()
+
+ x = Array()
+ y = Array()
+ x.push_back(y)
+ print("TEST ARRAY ADD TO SELF: " + str(len(y)))
+ x.clear()
diff --git a/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out
new file mode 100644
index 0000000000..f6b7d3cc39
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/arrays_arent_shared.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+TEST ARRAY ADD TO SELF: 0
+TEST ARRAY ADD TO SELF: 0
+TEST ARRAY ADD TO SELF: 0
+TEST ARRAY ADD TO SELF: 0
+TEST ARRAY ADD TO SELF: 0
diff --git a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd
new file mode 100644
index 0000000000..9da61ab184
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.gd
@@ -0,0 +1,8 @@
+# https://github.com/godotengine/godot/issues/50894
+
+func test():
+ print(await not_coroutine())
+
+
+func not_coroutine():
+ return "awaited"
diff --git a/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out
new file mode 100644
index 0000000000..c2ac488e9b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/await_without_coroutine.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+>> WARNING
+>> Line: 4
+>> REDUNDANT_AWAIT
+>> "await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.
+awaited
diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd
new file mode 100644
index 0000000000..d5a5f8de64
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.gd
@@ -0,0 +1,19 @@
+# https://github.com/godotengine/godot/issues/48121
+
+func test():
+ var x := Dictionary()
+ var y := Dictionary()
+ y[0]=1
+ y[1]=1
+ y[2]=1
+ print("TEST OTHER DICTIONARY: " + str(len(x)))
+ x.clear()
+
+ x = Dictionary().duplicate()
+ y = Dictionary().duplicate()
+ y[0]=1
+ y[1]=1
+ y[2]=1
+ print("TEST OTHER DICTIONARY: " + str(len(x)))
+ x.clear()
+ return
diff --git a/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out
new file mode 100644
index 0000000000..0bf49f5934
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/dictionaries_arent_shared.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+TEST OTHER DICTIONARY: 0
+TEST OTHER DICTIONARY: 0
diff --git a/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd b/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd
new file mode 100644
index 0000000000..c9b5f8481e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd
@@ -0,0 +1,4 @@
+func test():
+ var dict = {}
+ dict.test = 1
+ print(dict.test)
diff --git a/modules/gdscript/tests/scripts/runtime/features/lua_assign.out b/modules/gdscript/tests/scripts/runtime/features/lua_assign.out
new file mode 100644
index 0000000000..a7f1357bb2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lua_assign.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+1
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
new file mode 100644
index 0000000000..fead2df854
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -0,0 +1,42 @@
+func test():
+ print(true, false)
+ print(-1, 0, 1)
+ print(-1.25, 0.25, 1.25)
+ print("hello world")
+
+ print(Vector2(0.25, 0.25))
+ print(Vector2i(0, 0))
+
+ print(Rect2(0.25, 0.25, 0.5, 0.5))
+ print(Rect2i(0, 0, 0, 0))
+
+ print(Vector3(0.25, 0.25, 0.25))
+ print(Vector3i(0, 0, 0))
+
+ print(Transform2D.IDENTITY)
+ print(Plane(1, 2, 3, 4))
+ print(Quaternion(1, 2, 3, 4))
+ print(AABB(Vector3.ZERO, Vector3.ONE))
+ print(Basis.from_euler(Vector3(0, 0, 0)))
+ print(Transform3D.IDENTITY)
+
+ print(Color(1, 2, 3, 4))
+ print(StringName("hello"))
+ print(NodePath("hello/world"))
+ var node := Node.new()
+ print(RID(node))
+ print(node.get_name)
+ print(node.property_list_changed)
+ node.free()
+ print({"hello":123})
+ print(["hello", 123])
+
+ print(PackedByteArray([-1, 0, 1]))
+ print(PackedInt32Array([-1, 0, 1]))
+ print(PackedInt64Array([-1, 0, 1]))
+ print(PackedFloat32Array([-1, 0, 1]))
+ print(PackedFloat64Array([-1, 0, 1]))
+ print(PackedStringArray(["hello", "world"]))
+ print(PackedVector2Array([Vector2.ONE, Vector2.ZERO]))
+ print(PackedVector3Array([Vector3.ONE, Vector3.ZERO]))
+ print(PackedColorArray([Color.RED, Color.BLUE, Color.GREEN]))
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
new file mode 100644
index 0000000000..7670fc0128
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -0,0 +1,34 @@
+GDTEST_OK
+truefalse
+-101
+-1.250.251.25
+hello world
+(0.25, 0.25)
+(0, 0)
+[P: (0.25, 0.25), S: (0.5, 0.5)]
+[P: (0, 0), S: (0, 0)]
+(0.25, 0.25, 0.25)
+(0, 0, 0)
+[X: (1, 0), Y: (0, 1), O: (0, 0)]
+[N: (1, 2, 3), D: 4]
+(1, 2, 3, 4)
+[P: (0, 0, 0), S: (1, 1, 1)]
+[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1)]
+[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1), O: (0, 0, 0)]
+(1, 2, 3, 4)
+hello
+hello/world
+RID(0)
+Node::get_name
+Node::[signal]property_list_changed
+{hello:123}
+[hello, 123]
+[255, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[hello, world]
+[(1, 1), (0, 0)]
+[(1, 1, 1), (0, 0, 0)]
+[(1, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1)]
diff --git a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
deleted file mode 100644
index c85fce7b9d..0000000000
--- a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterGLTF" inherits="EditorSceneImporter" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
-</class>
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index 25875e7396..1a172877a0 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -38,16 +38,16 @@
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
-uint32_t EditorSceneImporterGLTF::get_import_flags() const {
+uint32_t EditorSceneFormatImporterGLTF::get_import_flags() const {
return ImportFlags::IMPORT_SCENE | ImportFlags::IMPORT_ANIMATION;
}
-void EditorSceneImporterGLTF::get_extensions(List<String> *r_extensions) const {
+void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) const {
r_extensions->push_back("gltf");
r_extensions->push_back("glb");
}
-Node *EditorSceneImporterGLTF::import_scene(const String &p_path,
+Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path,
uint32_t p_flags, int p_bake_fps,
List<String> *r_missing_deps,
Error *r_err) {
@@ -56,7 +56,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path,
return doc->import_scene_gltf(p_path, p_flags, p_bake_fps, Ref<GLTFState>(), r_missing_deps, r_err);
}
-Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
+Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path,
uint32_t p_flags,
int p_bake_fps) {
return Ref<Animation>();
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index 90663612a1..28963adc28 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -41,8 +41,8 @@
class Animation;
-class EditorSceneImporterGLTF : public EditorSceneImporter {
- GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
+class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter {
+ GDCLASS(EditorSceneFormatImporterGLTF, EditorSceneFormatImporter);
public:
virtual uint32_t get_import_flags() const override;
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index ba98592600..3a8cab7e7e 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -120,26 +120,26 @@ Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &
return Error::FAILED;
}
- /* STEP 7 SERIALIZE IMAGES */
- err = _serialize_images(state, p_path);
+ /* STEP 7 SERIALIZE ANIMATIONS */
+ err = _serialize_animations(state);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 8 SERIALIZE TEXTURES */
- err = _serialize_textures(state);
+ /* STEP 8 SERIALIZE ACCESSORS */
+ err = _encode_accessors(state);
if (err != OK) {
return Error::FAILED;
}
- // /* STEP 9 SERIALIZE ANIMATIONS */
- err = _serialize_animations(state);
+ /* STEP 9 SERIALIZE IMAGES */
+ err = _serialize_images(state, p_path);
if (err != OK) {
return Error::FAILED;
}
- /* STEP 10 SERIALIZE ACCESSORS */
- err = _encode_accessors(state);
+ /* STEP 10 SERIALIZE TEXTURES */
+ err = _serialize_textures(state);
if (err != OK) {
return Error::FAILED;
}
@@ -247,7 +247,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
JSON json;
err = json.parse(text);
if (err != OK) {
- _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT);
return err;
}
state->json = json.get_data();
@@ -282,7 +282,7 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) {
JSON json;
err = json.parse(text);
if (err != OK) {
- _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), false, ERR_HANDLER_SCRIPT);
return err;
}
@@ -4319,6 +4319,9 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
skeleton->add_bone(node->get_name());
skeleton->set_bone_rest(bone_index, node->xform);
+ skeleton->set_bone_pose_position(bone_index, node->position);
+ skeleton->set_bone_pose_rotation(bone_index, node->rotation.normalized());
+ skeleton->set_bone_pose_scale(bone_index, node->scale);
if (node->parent >= 0 && state->nodes[node->parent]->skeleton == skel_i) {
const int bone_parent = skeleton->find_bone(state->nodes[node->parent]->get_name());
@@ -4366,6 +4369,10 @@ Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) {
json_skin["name"] = gltf_skin->get_name();
json_skins.push_back(json_skin);
}
+ if (!state->skins.size()) {
+ return OK;
+ }
+
state->json["skins"] = json_skins;
return OK;
}
@@ -5470,7 +5477,7 @@ void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFS
// Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node
// names to be unique regardless of whether or not they are used as joints.
joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i)));
- Transform3D xform = skeleton->get_bone_rest(bone_i) * skeleton->get_bone_pose(bone_i);
+ Transform3D xform = skeleton->get_bone_pose(bone_i);
joint_node->scale = xform.basis.get_scale();
joint_node->rotation = xform.basis.get_rotation_quaternion();
joint_node->position = xform.origin;
@@ -5681,7 +5688,7 @@ void GLTFDocument::_generate_skeleton_bone_node(Ref<GLTFState> state, Node *scen
}
template <class T>
-struct EditorSceneImporterGLTFInterpolate {
+struct EditorSceneFormatImporterGLTFInterpolate {
T lerp(const T &a, const T &b, float c) const {
return a + (b - a) * c;
}
@@ -5707,7 +5714,7 @@ struct EditorSceneImporterGLTFInterpolate {
// thank you for existing, partial specialization
template <>
-struct EditorSceneImporterGLTFInterpolate<Quaternion> {
+struct EditorSceneFormatImporterGLTFInterpolate<Quaternion> {
Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const {
ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized.");
ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized.");
@@ -5733,7 +5740,7 @@ struct EditorSceneImporterGLTFInterpolate<Quaternion> {
template <class T>
T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) {
ERR_FAIL_COND_V(!p_values.size(), T());
- if (p_times.size() != p_values.size()) {
+ if (p_times.size() != (p_values.size() / (p_interp == GLTFAnimation::INTERP_CUBIC_SPLINE ? 3 : 1))) {
ERR_PRINT_ONCE("The interpolated values are not corresponding to its times.");
return p_values[0];
}
@@ -5746,7 +5753,7 @@ T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T>
idx++;
}
- EditorSceneImporterGLTFInterpolate<T> interp;
+ EditorSceneFormatImporterGLTFInterpolate<T> interp;
switch (p_interp) {
case GLTFAnimation::INTERP_LINEAR: {
@@ -5868,9 +5875,67 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0;
if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) {
//make transform track
- int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_TRANSFORM3D);
- animation->track_set_path(track_idx, transform_node_path);
+ int base_idx = animation->get_track_count();
+ int position_idx = -1;
+ int rotation_idx = -1;
+ int scale_idx = -1;
+
+ if (track.position_track.values.size()) {
+ Vector3 base_pos = state->nodes[track_i.key]->position;
+ bool not_default = false; //discard the track if all it contains is default values
+ for (int i = 0; i < track.position_track.times.size(); i++) {
+ Vector3 value = track.position_track.values[track.position_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
+ if (!value.is_equal_approx(base_pos)) {
+ not_default = true;
+ break;
+ }
+ }
+ if (not_default) {
+ position_idx = base_idx;
+ animation->add_track(Animation::TYPE_POSITION_3D);
+ animation->track_set_path(position_idx, transform_node_path);
+ animation->track_set_imported(position_idx, true); //helps merging later
+
+ base_idx++;
+ }
+ }
+ if (track.rotation_track.values.size()) {
+ Quaternion base_rot = state->nodes[track_i.key]->rotation.normalized();
+ bool not_default = false; //discard the track if all it contains is default values
+ for (int i = 0; i < track.rotation_track.times.size(); i++) {
+ Quaternion value = track.rotation_track.values[track.rotation_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i].normalized();
+ if (!value.is_equal_approx(base_rot)) {
+ not_default = true;
+ break;
+ }
+ }
+ if (not_default) {
+ rotation_idx = base_idx;
+ animation->add_track(Animation::TYPE_ROTATION_3D);
+ animation->track_set_path(rotation_idx, transform_node_path);
+ animation->track_set_imported(rotation_idx, true); //helps merging later
+ base_idx++;
+ }
+ }
+ if (track.scale_track.values.size()) {
+ Vector3 base_scale = state->nodes[track_i.key]->scale;
+ bool not_default = false; //discard the track if all it contains is default values
+ for (int i = 0; i < track.scale_track.times.size(); i++) {
+ Vector3 value = track.scale_track.values[track.scale_track.interpolation == GLTFAnimation::INTERP_CUBIC_SPLINE ? (1 + i * 3) : i];
+ if (!value.is_equal_approx(base_scale)) {
+ not_default = true;
+ break;
+ }
+ }
+ if (not_default) {
+ scale_idx = base_idx;
+ animation->add_track(Animation::TYPE_SCALE_3D);
+ animation->track_set_path(scale_idx, transform_node_path);
+ animation->track_set_imported(scale_idx, true); //helps merging later
+ base_idx++;
+ }
+ }
+
//first determine animation length
const double increment = 1.0 / bake_fps;
@@ -5880,15 +5945,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Quaternion base_rot;
Vector3 base_scale = Vector3(1, 1, 1);
- if (!track.rotation_track.values.size()) {
+ if (rotation_idx == -1) {
base_rot = state->nodes[track_i.key]->rotation.normalized();
}
- if (!track.position_track.values.size()) {
+ if (position_idx == -1) {
base_pos = state->nodes[track_i.key]->position;
}
- if (!track.scale_track.values.size()) {
+ if (scale_idx == -1) {
base_scale = state->nodes[track_i.key]->scale;
}
@@ -5898,35 +5963,21 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Quaternion rot = base_rot;
Vector3 scale = base_scale;
- if (track.position_track.times.size()) {
+ if (position_idx >= 0) {
pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation);
+ animation->position_track_insert_key(position_idx, time, pos);
}
- if (track.rotation_track.times.size()) {
+ if (rotation_idx >= 0) {
rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation);
+ animation->rotation_track_insert_key(rotation_idx, time, rot);
}
- if (track.scale_track.times.size()) {
+ if (scale_idx >= 0) {
scale = _interpolate_track<Vector3>(track.scale_track.times, track.scale_track.values, time, track.scale_track.interpolation);
+ animation->scale_track_insert_key(scale_idx, time, scale);
}
- if (gltf_node->skeleton >= 0) {
- Transform3D xform;
- xform.basis.set_quaternion_scale(rot, scale);
- xform.origin = pos;
-
- const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton;
- const int bone_idx = skeleton->find_bone(gltf_node->get_name());
- xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform;
-
- rot = xform.basis.get_rotation_quaternion();
- rot.normalize();
- scale = xform.basis.get_scale();
- pos = xform.origin;
- }
-
- animation->transform_track_insert_key(track_idx, time, pos, rot, scale);
-
if (last) {
break;
}
@@ -5944,12 +5995,11 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
ERR_CONTINUE(mesh.is_null());
ERR_CONTINUE(mesh->get_mesh().is_null());
ERR_CONTINUE(mesh->get_mesh()->get_mesh().is_null());
- const String prop = "blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i);
- const String blend_path = String(node_path) + ":" + prop;
+ const String blend_path = String(node_path) + ":" + String(mesh->get_mesh()->get_blend_shape_name(i));
const int track_idx = animation->get_track_count();
- animation->add_track(Animation::TYPE_VALUE);
+ animation->add_track(Animation::TYPE_BLEND_SHAPE);
animation->track_set_path(track_idx, blend_path);
// Only LINEAR and STEP (NEAREST) can be supported out of the box by Godot's Animation,
@@ -5960,7 +6010,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (int j = 0; j < track.weight_tracks[i].times.size(); j++) {
const float t = track.weight_tracks[i].times[j];
const float attribs = track.weight_tracks[i].values[j];
- animation->track_insert_key(track_idx, t, attribs);
+ animation->blend_shape_track_insert_key(track_idx, t, attribs);
}
} else {
// CATMULLROMSPLINE or CUBIC_SPLINE have to be baked, apologies.
@@ -5968,7 +6018,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
double time = 0.0;
bool last = false;
while (true) {
- _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
+ float blend = _interpolate_track<float>(track.weight_tracks[i].times, track.weight_tracks[i].values, time, gltf_interp);
+ animation->blend_shape_track_insert_key(track_idx, time, blend);
if (last) {
break;
}
@@ -6042,7 +6093,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
} else {
if (skin.is_null()) {
// Note that gltf_skin_key should remain null, so these can share a reference.
- skin = skeleton->register_skin(nullptr)->get_skin();
+ skin = skeleton->create_skin_from_rest_transforms();
}
gltf_skin.instantiate();
gltf_skin->godot_skin = skin;
@@ -6145,7 +6196,7 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
}
}
-GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) {
+GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, int32_t p_track_i, GLTFNodeIndex p_node_i) {
Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i);
GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
@@ -6164,33 +6215,35 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
for (int32_t key_i = 0; key_i < key_count; key_i++) {
times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i);
}
- if (track_type == Animation::TYPE_TRANSFORM3D) {
- p_track.position_track.times = times;
- p_track.position_track.interpolation = gltf_interpolation;
- p_track.rotation_track.times = times;
- p_track.rotation_track.interpolation = gltf_interpolation;
+ if (track_type == Animation::TYPE_SCALE_3D) {
p_track.scale_track.times = times;
p_track.scale_track.interpolation = gltf_interpolation;
-
p_track.scale_track.values.resize(key_count);
- p_track.scale_track.interpolation = gltf_interpolation;
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
+ Vector3 scale;
+ Error err = p_animation->scale_track_get_key(p_track_i, key_i, &scale);
+ ERR_CONTINUE(err != OK);
+ p_track.scale_track.values.write[key_i] = scale;
+ }
+ } else if (track_type == Animation::TYPE_POSITION_3D) {
+ p_track.position_track.times = times;
p_track.position_track.values.resize(key_count);
p_track.position_track.interpolation = gltf_interpolation;
- p_track.rotation_track.values.resize(key_count);
- p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
Vector3 position;
+ Error err = p_animation->position_track_get_key(p_track_i, key_i, &position);
+ ERR_CONTINUE(err != OK);
+ p_track.position_track.values.write[key_i] = position;
+ }
+ } else if (track_type == Animation::TYPE_ROTATION_3D) {
+ p_track.rotation_track.times = times;
+ p_track.rotation_track.interpolation = gltf_interpolation;
+ p_track.rotation_track.values.resize(key_count);
+ for (int32_t key_i = 0; key_i < key_count; key_i++) {
Quaternion rotation;
- Vector3 scale;
- Error err = p_animation->transform_track_get_key(p_track_i, key_i, &position, &rotation, &scale);
+ Error err = p_animation->rotation_track_get_key(p_track_i, key_i, &rotation);
ERR_CONTINUE(err != OK);
- Transform3D xform;
- xform.basis.set_quaternion_scale(rotation, scale);
- xform.origin = position;
- xform = p_bone_rest * xform;
- p_track.position_track.values.write[key_i] = xform.get_origin();
- p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion();
- p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
+ p_track.rotation_track.values.write[key_i] = rotation;
}
} else if (path.find(":transform") != -1) {
p_track.position_track.times = times;
@@ -6282,13 +6335,10 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
Vector3 bezier_track = p_track.scale_track.values[key_i];
if (path.find("/scale:x") != -1) {
bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.x = p_bone_rest.affine_inverse().basis.get_scale().x * bezier_track.x;
} else if (path.find("/scale:y") != -1) {
bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.y = p_bone_rest.affine_inverse().basis.get_scale().y * bezier_track.y;
} else if (path.find("/scale:z") != -1) {
bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.z = p_bone_rest.affine_inverse().basis.get_scale().z * bezier_track.z;
}
p_track.scale_track.values.write[key_i] = bezier_track;
}
@@ -6311,19 +6361,15 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
Vector3 bezier_track = p_track.position_track.values[key_i];
if (path.find("/position:x") != -1) {
bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.x = p_bone_rest.affine_inverse().origin.x * bezier_track.x;
} else if (path.find("/position:y") != -1) {
bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.y = p_bone_rest.affine_inverse().origin.y * bezier_track.y;
} else if (path.find("/position:z") != -1) {
bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
- bezier_track.z = p_bone_rest.affine_inverse().origin.z * bezier_track.z;
}
p_track.position_track.values.write[key_i] = bezier_track;
}
}
}
-
return p_track;
}
@@ -6350,7 +6396,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (position_track_i) {
track = position_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6366,7 +6412,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (rotation_degree_track_i) {
track = rotation_degree_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6382,7 +6428,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (scale_track_i) {
track = scale_track_i->get();
}
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
+ track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
}
}
@@ -6393,7 +6439,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : state->scene_nodes) {
if (transform_track_i.value == node) {
GLTFAnimation::Track track;
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i.key);
+ track = _convert_animation_track(state, track, animation, track_i, transform_track_i.key);
gltf_animation->get_tracks().insert(transform_track_i.key, track);
}
}
@@ -6417,8 +6463,8 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (!tracks.has(mesh_index)) {
for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) {
String shape_name = mesh->get_blend_shape_name(shape_i);
- NodePath shape_path = String(path) + ":blend_shapes/" + shape_name;
- int32_t shape_track_i = animation->find_track(shape_path);
+ NodePath shape_path = String(path) + ":" + shape_name;
+ int32_t shape_track_i = animation->find_track(shape_path, Animation::TYPE_BLEND_SHAPE);
if (shape_track_i == -1) {
GLTFAnimation::Channel<float> weight;
weight.interpolation = GLTFAnimation::INTERP_LINEAR;
@@ -6470,7 +6516,6 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i];
int32_t bone = skeleton->find_bone(suffix);
ERR_CONTINUE(bone == -1);
- Transform3D xform = skeleton->get_bone_rest(bone);
if (!skeleton_gltf->godot_bone_node.has(bone)) {
continue;
}
@@ -6480,27 +6525,24 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
if (property_track_i) {
track = property_track_i->get();
}
- track = _convert_animation_track(state, track, animation, xform, track_i, node_i);
+ track = _convert_animation_track(state, track, animation, track_i, node_i);
gltf_animation->get_tracks()[node_i] = track;
}
}
} else if (String(orig_track_path).find(":") == -1) {
ERR_CONTINUE(!ap->get_parent());
- for (int32_t node_i = 0; node_i < ap->get_parent()->get_child_count(); node_i++) {
- const Node *child = ap->get_parent()->get_child(node_i);
- const Node *node = child->get_node_or_null(orig_track_path);
- for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) {
- if (scene_node_i.value == node) {
- GLTFNodeIndex node_index = scene_node_i.key;
- Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_index);
- GLTFAnimation::Track track;
- if (node_track_i) {
- track = node_track_i->get();
- }
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
- gltf_animation->get_tracks().insert(node_index, track);
- break;
+ Node *godot_node = ap->get_parent()->get_node_or_null(orig_track_path);
+ for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) {
+ if (scene_node_i.value == godot_node) {
+ GLTFNodeIndex node_i = scene_node_i.key;
+ Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_i);
+ GLTFAnimation::Track track;
+ if (node_track_i) {
+ track = node_track_i->get();
}
+ track = _convert_animation_track(state, track, animation, track_i, node_i);
+ gltf_animation->get_tracks()[node_i] = track;
+ break;
}
}
}
@@ -6718,33 +6760,36 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
const uint32_t magic = 0x46546C67; // GLTF
const int32_t header_size = 12;
const int32_t chunk_header_size = 8;
-
- for (int32_t pad_i = 0; pad_i < (chunk_header_size + json.utf8().length()) % 4; pad_i++) {
- json += " ";
- }
CharString cs = json.utf8();
- const uint32_t text_chunk_length = cs.length();
-
+ const uint32_t text_data_length = cs.length();
+ const uint32_t text_chunk_length = ((text_data_length + 3) & (~3));
const uint32_t text_chunk_type = 0x4E4F534A; //JSON
- int32_t binary_data_length = 0;
+
+ uint32_t binary_data_length = 0;
if (state->buffers.size()) {
binary_data_length = state->buffers[0].size();
}
- const int32_t binary_chunk_length = binary_data_length;
- const int32_t binary_chunk_type = 0x004E4942; //BIN
+ const uint32_t binary_chunk_length = ((binary_data_length + 3) & (~3));
+ const uint32_t binary_chunk_type = 0x004E4942; //BIN
f->create(FileAccess::ACCESS_RESOURCES);
f->store_32(magic);
f->store_32(state->major_version); // version
- f->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_data_length); // length
+ f->store_32(header_size + chunk_header_size + text_chunk_length + chunk_header_size + binary_chunk_length); // length
f->store_32(text_chunk_length);
f->store_32(text_chunk_type);
f->store_buffer((uint8_t *)&cs[0], cs.length());
+ for (uint32_t pad_i = text_data_length; pad_i < text_chunk_length; pad_i++) {
+ f->store_8(' ');
+ }
if (binary_chunk_length) {
f->store_32(binary_chunk_length);
f->store_32(binary_chunk_type);
f->store_buffer(state->buffers[0].ptr(), binary_data_length);
}
+ for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) {
+ f->store_8(0);
+ }
f->close();
} else {
@@ -6795,7 +6840,7 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in
r_state.instantiate();
}
r_state->use_named_skin_binds =
- p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+ p_flags & EditorSceneFormatImporter::IMPORT_USE_NAMED_SKIN_BINDS;
Ref<GLTFDocument> gltf_document;
gltf_document.instantiate();
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 7317c6a9a3..f2f0b439a5 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -269,8 +269,6 @@ private:
Error _reparent_non_joint_skeleton_subtrees(
Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton,
const Vector<GLTFNodeIndex> &non_joints);
- Error _reparent_to_fake_joint(Ref<GLTFState> state, Ref<GLTFSkeleton> skeleton,
- const GLTFNodeIndex node_index);
Error _determine_skeleton_roots(Ref<GLTFState> state,
const GLTFSkeletonIndex skel_i);
Error _create_skeletons(Ref<GLTFState> state);
@@ -357,7 +355,7 @@ private:
String interpolation_to_string(const GLTFAnimation::Interpolation p_interp);
GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state,
GLTFAnimation::Track p_track,
- Ref<Animation> p_animation, Transform3D p_bone_rest,
+ Ref<Animation> p_animation,
int32_t p_track_i,
GLTFNodeIndex p_node_i);
Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path);
diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
index 78a98dfa3e..56c8f5ca27 100644
--- a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "gltf_document_extension_convert_importer_mesh.h"
+#include "core/error/error_macros.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/importer_mesh.h"
@@ -38,6 +39,8 @@ void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
}
Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) {
+ ERR_FAIL_NULL_V(p_document, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
List<Node *> queue;
queue.push_back(p_node);
List<Node *> delete_queue;
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 0aceb838f7..5a60c2d328 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -52,7 +52,7 @@
#ifndef _3D_DISABLED
#ifdef TOOLS_ENABLED
static void _editor_init() {
- Ref<EditorSceneImporterGLTF> import_gltf;
+ Ref<EditorSceneFormatImporterGLTF> import_gltf;
import_gltf.instantiate();
ResourceImporterScene::get_singleton()->add_importer(import_gltf);
}
@@ -64,7 +64,7 @@ void register_gltf_types() {
#ifdef TOOLS_ENABLED
ClassDB::APIType prev_api = ClassDB::get_current_api();
ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(EditorSceneImporterGLTF);
+ GDREGISTER_CLASS(EditorSceneFormatImporterGLTF);
GDREGISTER_CLASS(GLTFMesh);
EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
ClassDB::set_current_api(prev_api);
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 9d6a399eff..32a31aa764 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -65,7 +65,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
Vector<uint8_t> imgdata;
- imgdata.resize(height * width * sizeof(uint32_t));
+ imgdata.resize(height * width * (int)sizeof(uint32_t));
{
uint8_t *w = imgdata.ptrw();
@@ -75,7 +75,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
if (width < 8 || width >= 32768) {
// Read flat data
- f->get_buffer(ptr, width * height * 4);
+ f->get_buffer(ptr, (uint64_t)width * height * 4);
} else {
// Read RLE-encoded data
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index ba4ef3be8d..37e969db4d 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -611,6 +611,61 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int
}
}
+LightmapperRD::BakeError LightmapperRD::_dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices) {
+ Vector<RD::Uniform> uniforms;
+ {
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = 0;
+ u.ids.push_back(dest_light_tex);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.binding = 1;
+ u.ids.push_back(source_light_tex);
+ uniforms.push_back(u);
+ }
+ }
+
+ RID compute_shader_dilate = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("dilate"));
+ ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
+ RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
+
+ RID dilate_uniform_set = rd->uniform_set_create(uniforms, compute_shader_dilate, 1);
+
+ RD::ComputeListID compute_list = rd->compute_list_begin();
+ rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_dilate_pipeline);
+ rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0);
+ rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1);
+ push_constant.region_ofs[0] = 0;
+ push_constant.region_ofs[1] = 0;
+ Vector3i group_size((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); //restore group size
+
+ for (int i = 0; i < atlas_slices; i++) {
+ push_constant.atlas_slice = i;
+ rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
+ rd->compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z);
+ //no barrier, let them run all together
+ }
+ rd->compute_list_end();
+ rd->free(compute_shader_dilate);
+
+#ifdef DEBUG_TEXTURES
+ for (int i = 0; i < atlas_slices; i++) {
+ Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
+ Ref<Image> img;
+ img.instantiate();
+ img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+ img->convert(Image::FORMAT_RGBA8);
+ img->save_png("res://5_dilated_" + itos(i) + ".png");
+ }
+#endif
+ return BAKE_OK;
+}
+
LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function, void *p_bake_userdata) {
if (p_step_function) {
p_step_function(0.0, TTR("Begin Bake"), p_bake_userdata, true);
@@ -943,11 +998,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary);
- // Dilate
- RID compute_shader_dilate = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("dilate"));
- ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
- RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
-
// Light probes
RID compute_shader_light_probes = rd->shader_create_from_spirv(compute_shader->get_spirv_stages("light_probes"));
ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
@@ -959,7 +1009,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->free(compute_shader_unocclude); \
rd->free(compute_shader_primary); \
rd->free(compute_shader_secondary); \
- rd->free(compute_shader_dilate); \
rd->free(compute_shader_light_probes);
PushConstant push_constant;
@@ -1270,7 +1319,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
push_constant.environment_xform[3] = 0.0f;
}
- /* LIGHPROBES */
+ /* LIGHTPROBES */
RID light_probe_buffer;
@@ -1377,6 +1426,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
#endif
+ {
+ SWAP(light_accum_tex, light_accum_tex2);
+ BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
+ if (unlikely(error != BAKE_OK)) {
+ return error;
+ }
+ }
+
/* DENOISE */
if (p_use_denoiser) {
@@ -1409,58 +1466,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
}
}
- }
-#ifdef DEBUG_TEXTURES
-
- for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
- Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
- Ref<Image> img;
- img.instantiate();
- img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
- }
-#endif
-
- /* DILATE LIGHTMAP */
- {
- SWAP(light_accum_tex, light_accum_tex2);
-
- Vector<RD::Uniform> uniforms;
{
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 0;
- u.ids.push_back(light_accum_tex);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1;
- u.ids.push_back(light_accum_tex2);
- uniforms.push_back(u);
+ SWAP(light_accum_tex, light_accum_tex2);
+ BakeError error = _dilate(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, light_accum_tex, atlas_size, atlas_slices * (p_bake_sh ? 4 : 1));
+ if (unlikely(error != BAKE_OK)) {
+ return error;
}
}
-
- RID dilate_uniform_set = rd->uniform_set_create(uniforms, compute_shader_dilate, 1);
-
- RD::ComputeListID compute_list = rd->compute_list_begin();
- rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_dilate_pipeline);
- rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0);
- rd->compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1);
- push_constant.region_ofs[0] = 0;
- push_constant.region_ofs[1] = 0;
- group_size = Vector3i((atlas_size.x - 1) / 8 + 1, (atlas_size.y - 1) / 8 + 1, 1); //restore group size
-
- for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) {
- push_constant.atlas_slice = i;
- rd->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
- rd->compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z);
- //no barrier, let them run all together
- }
- rd->compute_list_end();
}
#ifdef DEBUG_TEXTURES
@@ -1470,8 +1483,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instantiate();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://5_dilated_" + itos(i) + ".png");
+ img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
}
#endif
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index a6a3740051..e1657b2069 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -36,6 +36,7 @@
#include "scene/resources/mesh.h"
#include "servers/rendering/rendering_device.h"
+class RDShaderFile;
class LightmapperRD : public Lightmapper {
GDCLASS(LightmapperRD, Lightmapper)
@@ -231,6 +232,8 @@ class LightmapperRD : public Lightmapper {
void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
+ BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
+
public:
virtual void add_mesh(const MeshData &p_mesh) override;
virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) override;
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index 22172d50e4..58523dc1f8 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -81,3 +81,7 @@ layout(set = 0, binding = 8) uniform texture2DArray albedo_tex;
layout(set = 0, binding = 9) uniform texture2DArray emission_tex;
layout(set = 0, binding = 10) uniform sampler linear_sampler;
+
+// Fragment action constants
+const uint FA_NONE = 0;
+const uint FA_SMOOTHEN_POSITION = 1;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 25b334c5eb..158cd960c4 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -94,13 +94,14 @@ params;
//check it, but also return distance and barycentric coords (for uv lookup)
bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) {
+ const float EPSILON = 0.00001;
const vec3 e0 = p1 - p0;
const vec3 e1 = p0 - p2;
vec3 triangle_normal = cross(e1, e0);
float n_dot_dir = dot(triangle_normal, dir);
- if (abs(n_dot_dir) < 0.01) {
+ if (abs(n_dot_dir) < EPSILON) {
return false;
}
@@ -148,7 +149,7 @@ uint trace_ray(vec3 p_from, vec3 p_to
ivec3 icell = ivec3(from_cell);
ivec3 iendcell = ivec3(to_cell);
vec3 dir_cell = normalize(rel_cell);
- vec3 delta = abs(1.0 / dir_cell); //vec3(length(rel_cell)) / rel_cell);
+ vec3 delta = min(abs(1.0 / dir_cell), params.grid_size); // use params.grid_size as max to prevent infinity values
ivec3 step = ivec3(sign(rel_cell));
vec3 side = (sign(rel_cell) * (vec3(icell) - from_cell) + (sign(rel_cell) * 0.5) + 0.5) * delta;
@@ -420,20 +421,22 @@ void main() {
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
active_rays += 1.0;
- } else if (trace_result == RAY_MISS && params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
- // Did not hit a triangle, reach out for the sky
- vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
+ } else if (trace_result == RAY_MISS) {
+ if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
+ // Did not hit a triangle, reach out for the sky
+ vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
- vec2 st = vec2(
- atan(sky_dir.x, sky_dir.z),
- acos(sky_dir.y));
+ vec2 st = vec2(
+ atan(sky_dir.x, sky_dir.z),
+ acos(sky_dir.y));
- if (st.x < 0.0)
- st.x += PI * 2.0;
+ if (st.x < 0.0)
+ st.x += PI * 2.0;
- st /= vec2(PI * 2.0, PI);
+ st /= vec2(PI * 2.0, PI);
- light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
+ light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
+ }
active_rays += 1.0;
}
diff --git a/modules/lightmapper_rd/lm_raster.glsl b/modules/lightmapper_rd/lm_raster.glsl
index 55ca193cc1..a86968a4f3 100644
--- a/modules/lightmapper_rd/lm_raster.glsl
+++ b/modules/lightmapper_rd/lm_raster.glsl
@@ -12,6 +12,7 @@ layout(location = 2) out vec2 uv_interp;
layout(location = 3) out vec3 barycentric;
layout(location = 4) flat out uvec3 vertex_indices;
layout(location = 5) flat out vec3 face_normal;
+layout(location = 6) flat out uint fragment_action;
layout(push_constant, binding = 0, std430) uniform Params {
vec2 atlas_size;
@@ -49,6 +50,14 @@ void main() {
face_normal = -normalize(cross((vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.y].position), (vertices.data[vertex_indices.x].position - vertices.data[vertex_indices.z].position)));
+ {
+ const float FLAT_THRESHOLD = 0.99;
+ const vec3 norm_a = vec3(vertices.data[vertex_indices.x].normal_xy, vertices.data[vertex_indices.x].normal_z);
+ const vec3 norm_b = vec3(vertices.data[vertex_indices.y].normal_xy, vertices.data[vertex_indices.y].normal_z);
+ const vec3 norm_c = vec3(vertices.data[vertex_indices.z].normal_xy, vertices.data[vertex_indices.z].normal_z);
+ fragment_action = (dot(norm_a, norm_b) < FLAT_THRESHOLD || dot(norm_a, norm_c) < FLAT_THRESHOLD || dot(norm_b, norm_c) < FLAT_THRESHOLD) ? FA_SMOOTHEN_POSITION : FA_NONE;
+ }
+
gl_Position = vec4((uv_interp + params.uv_offset) * 2.0 - 1.0, 0.0001, 1.0);
}
@@ -78,6 +87,7 @@ layout(location = 2) in vec2 uv_interp;
layout(location = 3) in vec3 barycentric;
layout(location = 4) in flat uvec3 vertex_indices;
layout(location = 5) in flat vec3 face_normal;
+layout(location = 6) in flat uint fragment_action;
layout(location = 0) out vec4 position;
layout(location = 1) out vec4 normal;
@@ -86,7 +96,7 @@ layout(location = 2) out vec4 unocclude;
void main() {
vec3 vertex_pos = vertex_interp;
- {
+ if (fragment_action == FA_SMOOTHEN_POSITION) {
// smooth out vertex position by interpolating its projection in the 3 normal planes (normal plane is created by vertex pos and normal)
// because we don't want to interpolate inwards, normals found pointing inwards are pushed out.
vec3 pos_a = vertices.data[vertex_indices.x].position;
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.h b/modules/mbedtls/packet_peer_mbed_dtls.h
index 6554c74a21..92e6ab88c4 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.h
+++ b/modules/mbedtls/packet_peer_mbed_dtls.h
@@ -59,8 +59,6 @@ protected:
Ref<SSLContextMbedTLS> ssl_ctx;
mbedtls_timing_delay_context timer;
- static void _bind_methods();
-
Error _do_handshake();
int _set_cookie();
diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h
index 1b55a54a10..5692dec1b6 100644
--- a/modules/mbedtls/ssl_context_mbedtls.h
+++ b/modules/mbedtls/ssl_context_mbedtls.h
@@ -67,8 +67,6 @@ class SSLContextMbedTLS : public RefCounted {
protected:
bool inited = false;
- static PackedByteArray _read_file(String p_path);
-
public:
static void print_mbedtls_error(int p_ret);
diff --git a/modules/mbedtls/stream_peer_mbedtls.h b/modules/mbedtls/stream_peer_mbedtls.h
index b89d7fb238..407479e3cc 100644
--- a/modules/mbedtls/stream_peer_mbedtls.h
+++ b/modules/mbedtls/stream_peer_mbedtls.h
@@ -50,8 +50,6 @@ private:
protected:
Ref<SSLContextMbedTLS> ssl_ctx;
- static void _bind_methods();
-
Error _do_handshake();
public:
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index 7b52ef178a..17ce051b67 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -112,7 +112,7 @@ void AudioStreamPlaybackMP3::seek(float p_time) {
}
frames_mixed = uint32_t(mp3_stream->sample_rate * p_time);
- mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels);
+ mp3dec_ex_seek(mp3d, (uint64_t)frames_mixed * mp3_stream->channels);
}
AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() {
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 04ba82ef51..18a77c8b8d 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -37,5 +37,6 @@
<member name="oversample" type="float" setter="set_oversample" getter="get_oversample" default="1.5">
The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance.
</member>
+ <member name="xr_play_area_mode" type="int" setter="set_play_area_mode" getter="get_play_area_mode" override="true" enum="XRInterface.PlayAreaMode" default="1" />
</members>
</class>
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index fc1a118e4f..ba7353ace2 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -126,6 +126,8 @@ void MobileVRInterface::set_position_from_sensors() {
// 9dof is a misleading marketing term coming from 3 accelerometer axis + 3 gyro axis + 3 magnetometer axis = 9 axis
// but in reality this only offers 3 dof (yaw, pitch, roll) orientation
+ Basis orientation;
+
uint64_t ticks = OS::get_singleton()->get_ticks_usec();
uint64_t ticks_elapsed = ticks - last_ticks;
float delta_time = (double)ticks_elapsed / 1000000.0;
@@ -207,8 +209,8 @@ void MobileVRInterface::set_position_from_sensors() {
};
};
- // JIC
- orientation.orthonormalize();
+ // and copy to our head transform
+ head_transform.basis = orientation.orthonormalized();
last_ticks = ticks;
};
@@ -318,7 +320,7 @@ bool MobileVRInterface::initialize() {
ERR_FAIL_NULL_V(xr_server, false);
if (!initialized) {
- // reset our sensor data and orientation
+ // reset our sensor data
mag_count = 0;
has_gyro = false;
sensor_first = true;
@@ -326,9 +328,15 @@ bool MobileVRInterface::initialize() {
mag_next_max = Vector3(-10000, -10000, -10000);
mag_current_min = Vector3(0, 0, 0);
mag_current_max = Vector3(0, 0, 0);
+ head_transform.basis = Basis();
+ head_transform.origin = Vector3(0.0, eye_height, 0.0);
- // reset our orientation
- orientation = Basis();
+ // we must create a tracker for our head
+ head.instantiate();
+ head->set_tracker_type(XRServer::TRACKER_HEAD);
+ head->set_tracker_name("head");
+ head->set_tracker_desc("Players head");
+ xr_server->add_tracker(head);
// make this our primary interface
xr_server->set_primary_interface(this);
@@ -343,16 +351,38 @@ bool MobileVRInterface::initialize() {
void MobileVRInterface::uninitialize() {
if (initialized) {
+ // do any cleanup here...
XRServer *xr_server = XRServer::get_singleton();
- if (xr_server != nullptr && xr_server->get_primary_interface() == this) {
- // no longer our primary interface
- xr_server->set_primary_interface(nullptr);
+ if (xr_server != nullptr) {
+ if (head.is_valid()) {
+ xr_server->remove_tracker(head);
+
+ head.unref();
+ }
+
+ if (xr_server->get_primary_interface() == this) {
+ // no longer our primary interface
+ xr_server->set_primary_interface(nullptr);
+ }
}
initialized = false;
};
};
+bool MobileVRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ // This interface has no positional tracking so fix this to 3DOF
+ return p_mode == XR_PLAY_AREA_3DOF;
+}
+
+XRInterface::PlayAreaMode MobileVRInterface::get_play_area_mode() const {
+ return XR_PLAY_AREA_3DOF;
+}
+
+bool MobileVRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ return p_mode == XR_PLAY_AREA_3DOF;
+}
+
Size2 MobileVRInterface::get_render_target_size() {
_THREAD_SAFE_METHOD_
@@ -377,11 +407,10 @@ Transform3D MobileVRInterface::get_camera_transform() {
float world_scale = xr_server->get_world_scale();
// just scale our origin point of our transform
- Transform3D hmd_transform;
- hmd_transform.basis = orientation;
- hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
+ Transform3D _head_transform = head_transform;
+ _head_transform.origin *= world_scale;
- transform_for_eye = (xr_server->get_reference_frame()) * hmd_transform;
+ transform_for_eye = (xr_server->get_reference_frame()) * _head_transform;
}
return transform_for_eye;
@@ -409,11 +438,10 @@ Transform3D MobileVRInterface::get_transform_for_view(uint32_t p_view, const Tra
};
// just scale our origin point of our transform
- Transform3D hmd_transform;
- hmd_transform.basis = orientation;
- hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0);
+ Transform3D _head_transform = head_transform;
+ _head_transform.origin *= world_scale;
- transform_for_eye = p_cam_transform * (xr_server->get_reference_frame()) * hmd_transform * transform_for_eye;
+ transform_for_eye = p_cam_transform * (xr_server->get_reference_frame()) * _head_transform * transform_for_eye;
} else {
// huh? well just return what we got....
transform_for_eye = p_cam_transform;
@@ -476,7 +504,16 @@ void MobileVRInterface::process() {
_THREAD_SAFE_METHOD_
if (initialized) {
+ // update our head transform orientation
set_position_from_sensors();
+
+ // update our head transform position (should be constant)
+ head_transform.origin = Vector3(0.0, eye_height, 0.0);
+
+ if (head.is_valid()) {
+ // Set our head position, note in real space, reference frame and world scale is applied later
+ head->set_pose("default", head_transform, Vector3(), Vector3());
+ }
};
};
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index a843e1188b..b5bf966247 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -53,7 +53,6 @@ class MobileVRInterface : public XRInterface {
private:
bool initialized = false;
XRInterface::TrackingStatus tracking_state;
- Basis orientation;
// Just set some defaults for these. At some point we need to look at adding a lookup table for common device + headset combos and/or support reading cardboard QR codes
double eye_height = 1.85;
@@ -68,6 +67,10 @@ private:
double k2 = 0.215;
double aspect = 1.0;
+ // at a minimum we need a tracker for our head
+ Ref<XRPositionalTracker> head;
+ Transform3D head_transform;
+
/*
logic for processing our sensor data, this was originally in our positional tracker logic but I think
that doesn't make sense in hindsight. It only makes marginally more sense to park it here for now,
@@ -140,6 +143,10 @@ public:
virtual bool initialize() override;
virtual void uninitialize() override;
+ virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
+ virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
+ virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
+
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 3b94949470..95c959235c 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -49,6 +49,7 @@ if env_mono["tools"] and env_mono["mono_glue"] and env_mono["build_cil"]:
env_mono.add_source_files(env.modules_sources, "*.cpp")
env_mono.add_source_files(env.modules_sources, "glue/*.cpp")
+env_mono.add_source_files(env.modules_sources, "glue/mono_glue.gen.cpp")
env_mono.add_source_files(env.modules_sources, "mono_gd/*.cpp")
env_mono.add_source_files(env.modules_sources, "utils/*.cpp")
@@ -57,6 +58,8 @@ env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.cpp")
if env["platform"] in ["osx", "iphone"]:
env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.mm")
env_mono.add_source_files(env.modules_sources, "mono_gd/support/*.m")
+elif env["platform"] == "android":
+ env_mono.add_source_files(env.modules_sources, "mono_gd/android_mono_config.gen.cpp")
if env["tools"]:
env_mono.add_source_files(env.modules_sources, "editor/*.cpp")
diff --git a/modules/mono/build_scripts/mono_reg_utils.py b/modules/mono/build_scripts/mono_reg_utils.py
index 0ec7e2f433..93a66ebf6f 100644
--- a/modules/mono/build_scripts/mono_reg_utils.py
+++ b/modules/mono/build_scripts/mono_reg_utils.py
@@ -2,7 +2,6 @@ import os
import platform
if os.name == "nt":
- import sys
import winreg
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 4c851a2989..df02d9a309 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -2,7 +2,7 @@ supported_platforms = ["windows", "osx", "linuxbsd", "server", "android", "haiku
def can_build(env, platform):
- return True
+ return not env["arch"].startswith("rv")
def configure(env):
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 247eee4280..531f600c3f 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -1660,7 +1660,7 @@ bool CSharpInstance::set(const StringName &p_name, const Variant &p_value) {
GDMonoProperty *property = top->get_property(p_name);
if (property) {
- property->set_value(mono_object, GDMonoMarshal::variant_to_mono_object(p_value, property->get_type()));
+ property->set_value_from_variant(mono_object, p_value);
return true;
}
@@ -1813,8 +1813,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
}
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) {
- p_properties->push_back(E.value);
+ for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) {
+ p_properties->push_front(E.value());
}
// Call _get_property_list
@@ -1839,10 +1839,9 @@ void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
for (int i = 0, size = array.size(); i < size; i++) {
p_properties->push_back(PropertyInfo::from_dict(array.get(i)));
}
- return;
}
- break;
+ return;
}
top = top->get_parent_class();
@@ -1865,8 +1864,9 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *
}
void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
- if (!script->is_valid() || !script->script_class)
+ if (!script->is_valid() || !script->script_class) {
return;
+ }
GD_MONO_SCOPE_THREAD_ATTACH;
@@ -3499,9 +3499,9 @@ Ref<Script> CSharpScript::get_base_script() const {
return Ref<Script>();
}
-void CSharpScript::get_script_property_list(List<PropertyInfo> *p_list) const {
- for (const KeyValue<StringName, PropertyInfo> &E : member_info) {
- p_list->push_back(E.value);
+void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
+ for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) {
+ r_list->push_front(E.value());
}
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index afc17f694a..c998d9c1e4 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -154,7 +154,7 @@ private:
Set<StringName> exported_members_names;
#endif
- Map<StringName, PropertyInfo> member_info;
+ OrderedHashMap<StringName, PropertyInfo> member_info;
void _clear();
@@ -215,7 +215,7 @@ public:
void get_script_signal_list(List<MethodInfo> *r_signals) const override;
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
- void get_script_property_list(List<PropertyInfo> *p_list) const override;
+ void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
void get_members(Set<StringName> *p_members) override;
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
index 1d7bfaf0a4..bc09e1ebf9 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
@@ -121,15 +121,20 @@ namespace GodotTools.IdeMessaging
this.messageHandler = messageHandler;
this.logger = logger;
- // TODO: Need to fetch the project data dir name from ProjectSettings instead of defaulting to ".godot"
string projectMetadataDir = Path.Combine(godotProjectDir, ".godot", "mono", "metadata");
+ // FileSystemWatcher requires an existing directory
+ if (!Directory.Exists(projectMetadataDir)) {
+ // Check if the non hidden version exists
+ string nonHiddenProjectMetadataDir = Path.Combine(godotProjectDir, "godot", "mono", "metadata");
+ if (Directory.Exists(nonHiddenProjectMetadataDir)) {
+ projectMetadataDir = nonHiddenProjectMetadataDir;
+ } else {
+ Directory.CreateDirectory(projectMetadataDir);
+ }
+ }
MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
- // FileSystemWatcher requires an existing directory
- if (!Directory.Exists(projectMetadataDir))
- Directory.CreateDirectory(projectMetadataDir);
-
fsWatcher = new FileSystemWatcher(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
}
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index c9789bf270..1904634132 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -139,49 +139,65 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_type.type_class->get_mono_type());
+ MonoClass *elem_class = mono_class_get_element_class(p_type.type_class->get_mono_ptr());
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+ if (elem_class == CACHED_CLASS_RAW(MonoObject)) {
return Variant::ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+ if (elem_class == CACHED_CLASS_RAW(uint8_t)) {
return Variant::PACKED_BYTE_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+ if (elem_class == CACHED_CLASS_RAW(int32_t)) {
return Variant::PACKED_INT32_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(int64_t)) {
+ if (elem_class == CACHED_CLASS_RAW(int64_t)) {
return Variant::PACKED_INT64_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(float)) {
+ if (elem_class == CACHED_CLASS_RAW(float)) {
return Variant::PACKED_FLOAT32_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(double)) {
+ if (elem_class == CACHED_CLASS_RAW(double)) {
return Variant::PACKED_FLOAT64_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+ if (elem_class == CACHED_CLASS_RAW(String)) {
return Variant::PACKED_STRING_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+ if (elem_class == CACHED_CLASS_RAW(Vector2)) {
return Variant::PACKED_VECTOR2_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+ if (elem_class == CACHED_CLASS_RAW(Vector3)) {
return Variant::PACKED_VECTOR3_ARRAY;
}
- if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+ if (elem_class == CACHED_CLASS_RAW(Color)) {
return Variant::PACKED_COLOR_ARRAY;
}
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
+ if (elem_class == CACHED_CLASS_RAW(StringName)) {
+ return Variant::ARRAY;
+ }
+
+ if (elem_class == CACHED_CLASS_RAW(NodePath)) {
+ return Variant::ARRAY;
+ }
+
+ if (elem_class == CACHED_CLASS_RAW(RID)) {
+ return Variant::ARRAY;
+ }
+
+ if (mono_class_is_enum(elem_class)) {
+ return Variant::ARRAY;
+ }
+
+ GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(elem_class);
if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
return Variant::ARRAY;
}
@@ -266,6 +282,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_
if (GDMonoUtils::Marshal::type_is_generic_icollection(reftype) || GDMonoUtils::Marshal::type_is_generic_ienumerable(reftype)) {
return Variant::ARRAY;
}
+
+ // GodotObject
+ GDMonoClass *type_class = p_type.type_class;
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
+ return Variant::OBJECT;
+ }
} break;
default: {
@@ -284,9 +306,8 @@ bool try_get_array_element_type(const ManagedType &p_array_type, ManagedType &r_
switch (p_array_type.type_encoding) {
case MONO_TYPE_ARRAY:
case MONO_TYPE_SZARRAY: {
- MonoArrayType *array_type = mono_type_get_array_type(p_array_type.type_class->get_mono_type());
- GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
- r_elem_type = ManagedType::from_class(array_type_class);
+ MonoClass *elem_class = mono_class_get_element_class(p_array_type.type_class->get_mono_ptr());
+ r_elem_type = ManagedType::from_class(elem_class);
return true;
} break;
case MONO_TYPE_GENERICINST: {
@@ -361,6 +382,18 @@ MonoArray *variant_to_mono_array(const Variant &p_var, GDMonoClass *p_type_class
return PackedColorArray_to_mono_array(p_var.operator PackedColorArray());
}
+ if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
+ return Array_to_mono_array(p_var.operator Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
+ return Array_to_mono_array(p_var.operator Array());
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
+ return Array_to_mono_array(p_var.operator Array());
+ }
+
if (mono_class_is_assignable_from(CACHED_CLASS(GodotObject)->get_mono_ptr(), array_type->eklass)) {
return Array_to_mono_array(p_var.operator ::Array(), array_type->eklass);
}
@@ -450,6 +483,11 @@ MonoObject *variant_to_mono_object_of_genericinst(const Variant &p_var, GDMonoCl
return GDMonoUtils::create_managed_from(p_var.operator Array(), godot_array_class);
}
+ // GodotObject
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(p_type_class)) {
+ return GDMonoUtils::unmanaged_get_managed(p_var.operator Object *());
+ }
+
ERR_FAIL_V_MSG(nullptr, "Attempted to convert Variant to unsupported generic type: '" +
p_type_class->get_full_name() + "'.");
}
@@ -1118,6 +1156,18 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
return mono_array_to_PackedColorArray((MonoArray *)p_obj);
}
+ if (array_type->eklass == CACHED_CLASS_RAW(StringName)) {
+ return mono_array_to_Array((MonoArray *)p_obj);
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(NodePath)) {
+ return mono_array_to_Array((MonoArray *)p_obj);
+ }
+
+ if (array_type->eklass == CACHED_CLASS_RAW(RID)) {
+ return mono_array_to_Array((MonoArray *)p_obj);
+ }
+
GDMonoClass *array_type_class = GDMono::get_singleton()->get_class(array_type->eklass);
if (CACHED_CLASS(GodotObject)->is_assignable_from(array_type_class)) {
return mono_array_to_Array((MonoArray *)p_obj);
@@ -1206,6 +1256,17 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type
GDMonoUtils::Marshal::array_get_element_type(reftype, &elem_reftype);
return system_generic_list_to_Array_variant(p_obj, p_type.type_class, elem_reftype);
}
+
+ // GodotObject
+ GDMonoClass *type_class = p_type.type_class;
+ if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) {
+ Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj));
+ if (ptr != nullptr) {
+ RefCounted *rc = Object::cast_to<RefCounted>(ptr);
+ return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr);
+ }
+ return Variant();
+ }
} break;
}
@@ -1315,7 +1376,6 @@ Dictionary system_generic_dict_to_Dictionary(MonoObject *p_obj, [[maybe_unused]]
MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_class, MonoReflectionType *p_elem_reftype) {
MonoType *elem_type = mono_reflection_type_get_type(p_elem_reftype);
- MonoClass *elem_class = mono_class_from_mono_type(elem_type);
String ctor_desc = ":.ctor(System.Collections.Generic.IEnumerable`1<" + GDMonoUtils::get_type_desc(elem_type) + ">)";
GDMonoMethod *ctor = p_class->get_method_with_desc(ctor_desc, true);
@@ -1324,7 +1384,10 @@ MonoObject *Array_to_system_generic_list(const Array &p_array, GDMonoClass *p_cl
MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
ERR_FAIL_NULL_V(mono_object, nullptr);
- void *ctor_args[1] = { Array_to_mono_array(p_array, elem_class) };
+ GDMonoClass *godot_array_class = GDMonoUtils::Marshal::make_generic_array_type(p_elem_reftype);
+ MonoObject *godot_array = GDMonoUtils::create_managed_from(p_array, godot_array_class);
+
+ void *ctor_args[1] = { godot_array };
MonoException *exc = nullptr;
ctor->invoke_raw(mono_object, ctor_args, &exc);
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index 5391b7775e..5c7cf29e88 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -65,6 +65,8 @@ GDMonoProperty::GDMonoProperty(MonoProperty *p_mono_property, GDMonoClass *p_own
type.type_class = GDMono::get_singleton()->get_class(param_type_class);
}
+ param_buffer_size = GDMonoMarshal::variant_get_managed_unboxed_size(type);
+
attrs_fetched = false;
attributes = nullptr;
}
@@ -147,24 +149,20 @@ bool GDMonoProperty::has_setter() {
return mono_property_get_set_method(mono_property) != nullptr;
}
-void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
- MonoMethod *prop_method = mono_property_get_set_method(mono_property);
- void *params[1] = { p_value };
- MonoException *exc = nullptr;
- GDMonoUtils::runtime_invoke(prop_method, p_object, params, &exc);
- if (exc) {
- if (r_exc) {
- *r_exc = exc;
- } else {
- GDMonoUtils::set_pending_exception(exc);
- }
- }
-}
+void GDMonoProperty::set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc) {
+ uint8_t *buffer = (uint8_t *)alloca(param_buffer_size);
+ unsigned int offset = 0;
-void GDMonoProperty::set_value(MonoObject *p_object, void **p_params, MonoException **r_exc) {
- MonoException *exc = nullptr;
- GDMonoUtils::property_set_value(mono_property, p_object, p_params, &exc);
+ void *params[1] = {
+ GDMonoMarshal::variant_to_managed_unboxed(p_value, type, buffer, offset)
+ };
+
+#ifdef DEBUG_ENABLED
+ CRASH_COND(offset != param_buffer_size);
+#endif
+ MonoException *exc = nullptr;
+ GDMonoUtils::property_set_value(mono_property, p_object, params, &exc);
if (exc) {
if (r_exc) {
*r_exc = exc;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index af7a2c02e5..9bb1caa759 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -45,6 +45,8 @@ class GDMonoProperty : public IMonoClassMember {
bool attrs_fetched;
MonoCustomAttrInfo *attributes;
+ unsigned int param_buffer_size;
+
public:
virtual GDMonoClass *get_enclosing_class() const final { return owner; }
@@ -64,8 +66,7 @@ public:
_FORCE_INLINE_ ManagedType get_type() const { return type; }
- void set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc = nullptr);
- void set_value(MonoObject *p_object, void **p_params, MonoException **r_exc = nullptr);
+ void set_value_from_variant(MonoObject *p_object, const Variant &p_value, MonoException **r_exc = nullptr);
MonoObject *get_value(MonoObject *p_object, MonoException **r_exc = nullptr);
bool get_bool_value(MonoObject *p_object);
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 13939bd014..09aa9ad948 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -450,7 +450,7 @@ void debug_send_unhandled_exception_error(MonoException *p_exc) {
int line = si.size() ? si[0].line : __LINE__;
String error_msg = "Unhandled exception";
- EngineDebugger::get_script_debugger()->send_error(func, file, line, error_msg, exc_msg, ERR_HANDLER_ERROR, si);
+ EngineDebugger::get_script_debugger()->send_error(func, file, line, error_msg, exc_msg, true, ERR_HANDLER_ERROR, si);
#endif
}
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index bb6bc578a4..8fd3a13e1f 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -489,7 +489,7 @@ NavigationMeshGenerator::~NavigationMeshGenerator() {
}
void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) {
- ERR_FAIL_COND(!p_nav_mesh.is_valid());
+ ERR_FAIL_COND_MSG(!p_nav_mesh.is_valid(), "Invalid navigation mesh.");
#ifdef TOOLS_ENABLED
EditorProgress *ep(nullptr);
diff --git a/modules/ogg/SCsub b/modules/ogg/SCsub
index e415d92498..f15525648f 100644
--- a/modules/ogg/SCsub
+++ b/modules/ogg/SCsub
@@ -3,9 +3,6 @@
Import("env")
Import("env_modules")
-# Only kept to build the thirdparty library used by the theora and webm
-# modules.
-
env_ogg = env_modules.Clone()
# Thirdparty source files
diff --git a/modules/opus/SCsub b/modules/opus/SCsub
deleted file mode 100644
index 1437cd86df..0000000000
--- a/modules/opus/SCsub
+++ /dev/null
@@ -1,252 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-# Only kept to build the thirdparty library used by the webm module.
-# AudioStreamOpus was dropped in 3.0 due to incompatibility with the new audio
-# engine. If you want to port it, fetch it from the Git history.
-
-env_opus = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-# Thirdparty source files
-if env["builtin_opus"]:
- thirdparty_dir = "#thirdparty/opus/"
-
- thirdparty_sources = [
- # Sync with opus_sources.mk
- "opus.c",
- "opus_decoder.c",
- "opus_encoder.c",
- "opus_multistream.c",
- "opus_multistream_encoder.c",
- "opus_multistream_decoder.c",
- "repacketizer.c",
- "analysis.c",
- "mlp.c",
- "mlp_data.c",
- # Sync with libopusfile Makefile.am
- "info.c",
- "internal.c",
- "opusfile.c",
- "stream.c",
- # Sync with celt_sources.mk
- "celt/bands.c",
- "celt/celt.c",
- "celt/celt_encoder.c",
- "celt/celt_decoder.c",
- "celt/cwrs.c",
- "celt/entcode.c",
- "celt/entdec.c",
- "celt/entenc.c",
- "celt/kiss_fft.c",
- "celt/laplace.c",
- "celt/mathops.c",
- "celt/mdct.c",
- "celt/modes.c",
- "celt/pitch.c",
- "celt/celt_lpc.c",
- "celt/quant_bands.c",
- "celt/rate.c",
- "celt/vq.c",
- # "celt/arm/arm_celt_map.c",
- # "celt/arm/armcpu.c",
- # "celt/arm/celt_ne10_fft.c",
- # "celt/arm/celt_ne10_mdct.c",
- # "celt/arm/celt_neon_intr.c",
- # Sync with silk_sources.mk
- "silk/CNG.c",
- "silk/code_signs.c",
- "silk/init_decoder.c",
- "silk/decode_core.c",
- "silk/decode_frame.c",
- "silk/decode_parameters.c",
- "silk/decode_indices.c",
- "silk/decode_pulses.c",
- "silk/decoder_set_fs.c",
- "silk/dec_API.c",
- "silk/enc_API.c",
- "silk/encode_indices.c",
- "silk/encode_pulses.c",
- "silk/gain_quant.c",
- "silk/interpolate.c",
- "silk/LP_variable_cutoff.c",
- "silk/NLSF_decode.c",
- "silk/NSQ.c",
- "silk/NSQ_del_dec.c",
- "silk/PLC.c",
- "silk/shell_coder.c",
- "silk/tables_gain.c",
- "silk/tables_LTP.c",
- "silk/tables_NLSF_CB_NB_MB.c",
- "silk/tables_NLSF_CB_WB.c",
- "silk/tables_other.c",
- "silk/tables_pitch_lag.c",
- "silk/tables_pulses_per_block.c",
- "silk/VAD.c",
- "silk/control_audio_bandwidth.c",
- "silk/quant_LTP_gains.c",
- "silk/VQ_WMat_EC.c",
- "silk/HP_variable_cutoff.c",
- "silk/NLSF_encode.c",
- "silk/NLSF_VQ.c",
- "silk/NLSF_unpack.c",
- "silk/NLSF_del_dec_quant.c",
- "silk/process_NLSFs.c",
- "silk/stereo_LR_to_MS.c",
- "silk/stereo_MS_to_LR.c",
- "silk/check_control_input.c",
- "silk/control_SNR.c",
- "silk/init_encoder.c",
- "silk/control_codec.c",
- "silk/A2NLSF.c",
- "silk/ana_filt_bank_1.c",
- "silk/biquad_alt.c",
- "silk/bwexpander_32.c",
- "silk/bwexpander.c",
- "silk/debug.c",
- "silk/decode_pitch.c",
- "silk/inner_prod_aligned.c",
- "silk/lin2log.c",
- "silk/log2lin.c",
- "silk/LPC_analysis_filter.c",
- "silk/LPC_inv_pred_gain.c",
- "silk/table_LSF_cos.c",
- "silk/NLSF2A.c",
- "silk/NLSF_stabilize.c",
- "silk/NLSF_VQ_weights_laroia.c",
- "silk/pitch_est_tables.c",
- "silk/resampler.c",
- "silk/resampler_down2_3.c",
- "silk/resampler_down2.c",
- "silk/resampler_private_AR2.c",
- "silk/resampler_private_down_FIR.c",
- "silk/resampler_private_IIR_FIR.c",
- "silk/resampler_private_up2_HQ.c",
- "silk/resampler_rom.c",
- "silk/sigm_Q15.c",
- "silk/sort.c",
- "silk/sum_sqr_shift.c",
- "silk/stereo_decode_pred.c",
- "silk/stereo_encode_pred.c",
- "silk/stereo_find_predictor.c",
- "silk/stereo_quant_pred.c",
- ]
-
- opus_sources_silk = []
-
- if env["platform"] in ["android", "iphone", "javascript"]:
- env_opus.Append(CPPDEFINES=["FIXED_POINT"])
- opus_sources_silk = [
- "silk/fixed/LTP_analysis_filter_FIX.c",
- "silk/fixed/LTP_scale_ctrl_FIX.c",
- "silk/fixed/corrMatrix_FIX.c",
- "silk/fixed/encode_frame_FIX.c",
- "silk/fixed/find_LPC_FIX.c",
- "silk/fixed/find_LTP_FIX.c",
- "silk/fixed/find_pitch_lags_FIX.c",
- "silk/fixed/find_pred_coefs_FIX.c",
- "silk/fixed/noise_shape_analysis_FIX.c",
- "silk/fixed/prefilter_FIX.c",
- "silk/fixed/process_gains_FIX.c",
- "silk/fixed/regularize_correlations_FIX.c",
- "silk/fixed/residual_energy16_FIX.c",
- "silk/fixed/residual_energy_FIX.c",
- "silk/fixed/solve_LS_FIX.c",
- "silk/fixed/warped_autocorrelation_FIX.c",
- "silk/fixed/apply_sine_window_FIX.c",
- "silk/fixed/autocorr_FIX.c",
- "silk/fixed/burg_modified_FIX.c",
- "silk/fixed/k2a_FIX.c",
- "silk/fixed/k2a_Q16_FIX.c",
- "silk/fixed/pitch_analysis_core_FIX.c",
- "silk/fixed/vector_ops_FIX.c",
- "silk/fixed/schur64_FIX.c",
- "silk/fixed/schur_FIX.c",
- ]
- else:
- opus_sources_silk = [
- "silk/float/apply_sine_window_FLP.c",
- "silk/float/corrMatrix_FLP.c",
- "silk/float/encode_frame_FLP.c",
- "silk/float/find_LPC_FLP.c",
- "silk/float/find_LTP_FLP.c",
- "silk/float/find_pitch_lags_FLP.c",
- "silk/float/find_pred_coefs_FLP.c",
- "silk/float/LPC_analysis_filter_FLP.c",
- "silk/float/LTP_analysis_filter_FLP.c",
- "silk/float/LTP_scale_ctrl_FLP.c",
- "silk/float/noise_shape_analysis_FLP.c",
- "silk/float/prefilter_FLP.c",
- "silk/float/process_gains_FLP.c",
- "silk/float/regularize_correlations_FLP.c",
- "silk/float/residual_energy_FLP.c",
- "silk/float/solve_LS_FLP.c",
- "silk/float/warped_autocorrelation_FLP.c",
- "silk/float/wrappers_FLP.c",
- "silk/float/autocorrelation_FLP.c",
- "silk/float/burg_modified_FLP.c",
- "silk/float/bwexpander_FLP.c",
- "silk/float/energy_FLP.c",
- "silk/float/inner_product_FLP.c",
- "silk/float/k2a_FLP.c",
- "silk/float/levinsondurbin_FLP.c",
- "silk/float/LPC_inv_pred_gain_FLP.c",
- "silk/float/pitch_analysis_core_FLP.c",
- "silk/float/scale_copy_vector_FLP.c",
- "silk/float/scale_vector_FLP.c",
- "silk/float/schur_FLP.c",
- "silk/float/sort_FLP.c",
- ]
-
- thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources + opus_sources_silk]
-
- # also requires libogg
- if env["builtin_libogg"]:
- env_opus.Prepend(CPPPATH=["#thirdparty/libogg"])
-
- env_opus.Append(CPPDEFINES=["HAVE_CONFIG_H"])
-
- thirdparty_include_paths = [
- "",
- "celt",
- "opus",
- "silk",
- "silk/fixed",
- "silk/float",
- ]
- env_opus.Prepend(CPPPATH=[thirdparty_dir + "/" + dir for dir in thirdparty_include_paths])
-
- if env["platform"] == "android":
- if "android_arch" in env and env["android_arch"] == "armv7":
- env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
- elif "android_arch" in env and env["android_arch"] == "arm64v8":
- env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
- elif env["platform"] == "iphone":
- if "arch" in env and env["arch"] == "arm":
- env_opus.Append(CPPDEFINES=["OPUS_ARM_OPT"])
- elif "arch" in env and env["arch"] == "arm64":
- env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
- elif env["platform"] == "osx":
- if "arch" in env and env["arch"] == "arm64":
- env_opus.Append(CPPDEFINES=["OPUS_ARM64_OPT"])
-
- env_thirdparty = env_opus.Clone()
- env_thirdparty.disable_warnings()
- env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
- env.modules_sources += thirdparty_obj
-
-
-# Godot source files
-
-module_obj = []
-
-env_opus.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/opus/config.py b/modules/opus/config.py
deleted file mode 100644
index 9ff7b2dece..0000000000
--- a/modules/opus/config.py
+++ /dev/null
@@ -1,6 +0,0 @@
-def can_build(env, platform):
- return env.module_check_dependencies("opus", ["ogg"])
-
-
-def configure(env):
- pass
diff --git a/modules/opus/register_types.cpp b/modules/opus/register_types.cpp
deleted file mode 100644
index 02874a9a4b..0000000000
--- a/modules/opus/register_types.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-#include "register_types.h"
-
-// Dummy module as libvorbis is needed by other modules (theora ...)
-
-void register_opus_types() {}
-
-void unregister_opus_types() {}
diff --git a/modules/opus/register_types.h b/modules/opus/register_types.h
deleted file mode 100644
index af889cf809..0000000000
--- a/modules/opus/register_types.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 OPUS_REGISTER_TYPES_H
-#define OPUS_REGISTER_TYPES_H
-
-void register_opus_types();
-void unregister_opus_types();
-
-#endif // OPUS_REGISTER_TYPES_H
diff --git a/modules/raycast/config.py b/modules/raycast/config.py
index 5de36c5322..2f8bacd4ae 100644
--- a/modules/raycast/config.py
+++ b/modules/raycast/config.py
@@ -1,5 +1,7 @@
def can_build(env, platform):
# Depends on Embree library, which only supports x86_64 and aarch64.
+ if env["arch"].startswith("rv"):
+ return False
if platform == "android":
return env["android_arch"] in ["arm64v8", "x86_64"]
diff --git a/modules/regex/config.py b/modules/regex/config.py
index df9f44cb95..1248a8374d 100644
--- a/modules/regex/config.py
+++ b/modules/regex/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return True
+ return not env["arch"].startswith("rv")
def configure(env):
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 7cd4db6f67..d6a96282f3 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -7,7 +7,6 @@ env_text_server_adv = env_modules.Clone()
def make_icu_data(target, source, env):
- import os
dst = target[0].srcnode().abspath
@@ -24,7 +23,6 @@ def make_icu_data(target, source, env):
f = open(source[0].srcnode().abspath, "rb")
buf = f.read()
- import os.path
g.write('extern "C" U_EXPORT const size_t U_ICUDATA_SIZE = ' + str(len(buf)) + ";\n")
g.write('extern "C" U_EXPORT const unsigned char U_ICUDATA_ENTRY_POINT[] = {\n')
@@ -272,6 +270,7 @@ if env["builtin_icu"]:
"common/dictionarydata.cpp",
"common/dtintrv.cpp",
"common/edits.cpp",
+ "common/emojiprops.cpp",
"common/errorcode.cpp",
"common/filteredbrk.cpp",
"common/filterednormalizer2.cpp",
@@ -293,6 +292,7 @@ if env["builtin_icu"]:
"common/locresdata.cpp",
"common/locutil.cpp",
"common/lsr.cpp",
+ "common/lstmbe.cpp",
"common/messagepattern.cpp",
"common/normalizer2.cpp",
"common/normalizer2impl.cpp",
@@ -450,7 +450,7 @@ if env["builtin_icu"]:
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
- icu_data_name = "icudt69l.dat"
+ icu_data_name = "icudt70l.dat"
if env_icu["tools"]:
env_icu.Depends("#thirdparty/icu4c/icudata.gen.h", "#thirdparty/icu4c/" + icu_data_name)
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index f5d159040f..776134b598 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -46,13 +46,13 @@
#endif
/*************************************************************************/
-/* hb_bmp_font_t HarfBuzz Bitmap font interface */
+/* bmp_font_t HarfBuzz Bitmap font interface */
/*************************************************************************/
hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;
-TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
- hb_bmp_font_t *bm_font = memnew(hb_bmp_font_t);
+TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ bmp_font_t *bm_font = memnew(bmp_font_t);
if (!bm_font) {
return nullptr;
@@ -64,13 +64,13 @@ TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextS
return bm_font;
}
-void TextServerAdvanced::_hb_bmp_font_destroy(void *p_data) {
- hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(p_data);
+void TextServerAdvanced::_bmp_font_destroy(void *p_data) {
+ bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data);
memdelete(bm_font);
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -89,8 +89,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *
return true;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -103,8 +103,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font,
return bm_font->face->glyph_map[p_glyph].advance.x * 64;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -117,8 +117,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font,
return -bm_font->face->glyph_map[p_glyph].advance.y * 64;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -131,8 +131,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font,
return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -148,8 +148,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void
return true;
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -167,8 +167,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *
return true;
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -181,40 +181,40 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void
return true;
}
-void TextServerAdvanced::hb_bmp_create_font_funcs() {
+void TextServerAdvanced::_bmp_create_font_funcs() {
if (funcs == nullptr) {
funcs = hb_font_funcs_create();
- hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
- hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr);
- hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr);
+ hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_make_immutable(funcs);
}
}
-void TextServerAdvanced::hb_bmp_free_font_funcs() {
+void TextServerAdvanced::_bmp_free_font_funcs() {
if (funcs != nullptr) {
hb_font_funcs_destroy(funcs);
funcs = nullptr;
}
}
-void TextServerAdvanced::_hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
- hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_unref), _hb_bmp_font_destroy);
+void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);
}
-hb_font_t *TextServerAdvanced::hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
+hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
hb_font_t *font;
hb_face_t *face = hb_face_create(nullptr, 0);
font = hb_font_create(face);
hb_face_destroy(face);
- _hb_bmp_font_set_funcs(font, p_face, false);
+ _bmp_font_set_funcs(font, p_face, false);
return font;
}
@@ -442,9 +442,7 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const {
}
}
-static Map<StringName, int32_t> feature_sets;
-
-static void _insert_feature_sets() {
+void TextServerAdvanced::_insert_feature_sets() {
// Registered OpenType feature tags.
feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't'));
feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f'));
@@ -740,6 +738,10 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
continue;
}
+ if (ct.offsets.size() < ct.texture_w) {
+ continue;
+ }
+
ret.y = 0x7FFFFFFF;
ret.x = 0;
@@ -956,7 +958,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
edgeColoringSimple(shape, 3.0); // Max. angle.
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
- //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
DistancePixelConversion distancePixelConversion(p_pixel_range);
msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
@@ -986,10 +987,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));
- //wr[ofs + 0] = 100;
- //wr[ofs + 1] = 100;
- //wr[ofs + 2] = 100;
- //wr[ofs + 3] = 100;
}
}
}
@@ -1054,13 +1051,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
- //wr[ofs + 1] = 100;
break;
case FT_PIXEL_MODE_BGRA: {
int ofs_color = i * bitmap.pitch + (j << 2);
@@ -1215,13 +1211,14 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d
}
_FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced *p_font_data, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_size.x <= 0, false);
if (p_font_data->cache.has(p_size)) {
return true;
}
FontDataForSizeAdvanced *fd = memnew(FontDataForSizeAdvanced);
fd->size = p_size;
- if (p_font_data->data_ptr) {
+ if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
@@ -1594,7 +1591,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
#endif
} else {
// Init bitmap font.
- fd->hb_handle = hb_bmp_font_create(fd, nullptr);
+ fd->hb_handle = _bmp_font_create(fd, nullptr);
}
p_font_data->cache[p_size] = fd;
return true;
@@ -2123,6 +2120,7 @@ void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ ERR_FAIL_COND(p_texture_index < 0);
if (p_texture_index >= fd->cache[size]->textures.size()) {
fd->cache[size]->textures.resize(p_texture_index + 1);
}
@@ -2480,6 +2478,8 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
+ ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
+ ERR_FAIL_COND_V_MSG((p_variation_selector >= 0xd800 && p_variation_selector <= 0xdfff) || (p_variation_selector > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_variation_selector, 16) + ".");
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
@@ -2503,6 +2503,7 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha
bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
+ ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -2555,6 +2556,8 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
+ ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");
+ ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
@@ -3161,7 +3164,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -3189,7 +3192,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -3351,7 +3354,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -3379,7 +3382,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -4485,7 +4488,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -4513,7 +4516,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -4679,76 +4682,186 @@ float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) cons
return sd->uthk;
}
-struct num_system_data {
- Set<String> lang;
- String digits;
- String percent_sign;
- String exp;
-};
+void TextServerAdvanced::_insert_num_systems_lang() {
+ // Eastern Arabic numerals.
+ {
+ NumSystemData ar;
+ ar.lang.insert(StringName("ar")); // Arabic
+ ar.lang.insert(StringName("ar_AE"));
+ ar.lang.insert(StringName("ar_BH"));
+ ar.lang.insert(StringName("ar_DJ"));
+ ar.lang.insert(StringName("ar_EG"));
+ ar.lang.insert(StringName("ar_ER"));
+ ar.lang.insert(StringName("ar_IL"));
+ ar.lang.insert(StringName("ar_IQ"));
+ ar.lang.insert(StringName("ar_JO"));
+ ar.lang.insert(StringName("ar_KM"));
+ ar.lang.insert(StringName("ar_KW"));
+ ar.lang.insert(StringName("ar_LB"));
+ ar.lang.insert(StringName("ar_MR"));
+ ar.lang.insert(StringName("ar_OM"));
+ ar.lang.insert(StringName("ar_PS"));
+ ar.lang.insert(StringName("ar_QA"));
+ ar.lang.insert(StringName("ar_SA"));
+ ar.lang.insert(StringName("ar_SD"));
+ ar.lang.insert(StringName("ar_SO"));
+ ar.lang.insert(StringName("ar_SS"));
+ ar.lang.insert(StringName("ar_SY"));
+ ar.lang.insert(StringName("ar_TD"));
+ ar.lang.insert(StringName("ar_YE"));
+ ar.lang.insert(StringName("ckb")); // Central Kurdish
+ ar.lang.insert(StringName("ckb_IQ"));
+ ar.lang.insert(StringName("ckb_IR"));
+ ar.lang.insert(StringName("sd")); // Sindhi
+ ar.lang.insert(StringName("sd_PK"));
+ ar.lang.insert(StringName("sd_Arab"));
+ ar.lang.insert(StringName("sd_Arab_PK"));
+ ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";
+ ar.percent_sign = U"٪";
+ ar.exp = U"اس";
+ num_systems.push_back(ar);
+ }
+
+ // Persian and Urdu numerals.
+ {
+ NumSystemData pr;
+ pr.lang.insert(StringName("fa")); // Persian
+ pr.lang.insert(StringName("fa_AF"));
+ pr.lang.insert(StringName("fa_IR"));
+ pr.lang.insert(StringName("ks")); // Kashmiri
+ pr.lang.insert(StringName("ks_IN"));
+ pr.lang.insert(StringName("ks_Arab"));
+ pr.lang.insert(StringName("ks_Arab_IN"));
+ pr.lang.insert(StringName("lrc")); // Northern Luri
+ pr.lang.insert(StringName("lrc_IQ"));
+ pr.lang.insert(StringName("lrc_IR"));
+ pr.lang.insert(StringName("mzn")); // Mazanderani
+ pr.lang.insert(StringName("mzn_IR"));
+ pr.lang.insert(StringName("pa_PK")); // Panjabi
+ pr.lang.insert(StringName("pa_Arab"));
+ pr.lang.insert(StringName("pa_Arab_PK"));
+ pr.lang.insert(StringName("ps")); // Pushto
+ pr.lang.insert(StringName("ps_AF"));
+ pr.lang.insert(StringName("ps_PK"));
+ pr.lang.insert(StringName("ur_IN")); // Urdu
+ pr.lang.insert(StringName("uz_AF")); // Uzbek
+ pr.lang.insert(StringName("uz_Arab"));
+ pr.lang.insert(StringName("uz_Arab_AF"));
+ pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";
+ pr.percent_sign = U"٪";
+ pr.exp = U"اس";
+ num_systems.push_back(pr);
+ }
+
+ // Bengali numerals.
+ {
+ NumSystemData bn;
+ bn.lang.insert(StringName("as")); // Assamese
+ bn.lang.insert(StringName("as_IN"));
+ bn.lang.insert(StringName("bn")); // Bengali
+ bn.lang.insert(StringName("bn_BD"));
+ bn.lang.insert(StringName("bn_IN"));
+ bn.lang.insert(StringName("mni")); // Manipuri
+ bn.lang.insert(StringName("mni_IN"));
+ bn.lang.insert(StringName("mni_Beng"));
+ bn.lang.insert(StringName("mni_Beng_IN"));
+ bn.digits = U"০১২৩৪৫৬৭৮৯.";
+ bn.percent_sign = U"%";
+ bn.exp = U"e";
+ num_systems.push_back(bn);
+ }
+
+ // Devanagari numerals.
+ {
+ NumSystemData mr;
+ mr.lang.insert(StringName("mr")); // Marathi
+ mr.lang.insert(StringName("mr_IN"));
+ mr.lang.insert(StringName("ne")); // Nepali
+ mr.lang.insert(StringName("ne_IN"));
+ mr.lang.insert(StringName("ne_NP"));
+ mr.lang.insert(StringName("sa")); // Sanskrit
+ mr.lang.insert(StringName("sa_IN"));
+ mr.digits = U"०१२३४५६७८९.";
+ mr.percent_sign = U"%";
+ mr.exp = U"e";
+ num_systems.push_back(mr);
+ }
+
+ // Dzongkha numerals.
+ {
+ NumSystemData dz;
+ dz.lang.insert(StringName("dz")); // Dzongkha
+ dz.lang.insert(StringName("dz_BT"));
+ dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";
+ dz.percent_sign = U"%";
+ dz.exp = U"e";
+ num_systems.push_back(dz);
+ }
-static num_system_data num_systems[]{
- { Set<String>(), U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" },
- { Set<String>(), U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" },
- { Set<String>(), U"০১২৩৪৫৬৭৮৯.", U"%", U"e" },
- { Set<String>(), U"०१२३४५६७८९.", U"%", U"e" },
- { Set<String>(), U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" },
- { Set<String>(), U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" },
- { Set<String>(), U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" },
- { Set<String>(), String(), String(), String() },
-};
+ // Santali numerals.
+ {
+ NumSystemData sat;
+ sat.lang.insert(StringName("sat")); // Santali
+ sat.lang.insert(StringName("sat_IN"));
+ sat.lang.insert(StringName("sat_Olck"));
+ sat.lang.insert(StringName("sat_Olck_IN"));
+ sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";
+ sat.percent_sign = U"%";
+ sat.exp = U"e";
+ num_systems.push_back(sat);
+ }
+
+ // Burmese numerals.
+ {
+ NumSystemData my;
+ my.lang.insert(StringName("my")); // Burmese
+ my.lang.insert(StringName("my_MM"));
+ my.digits = U"၀၁၂၃၄၅၆၇၈၉.";
+ my.percent_sign = U"%";
+ my.exp = U"e";
+ num_systems.push_back(my);
+ }
-static void _insert_num_systems_lang() {
- num_systems[0].lang.insert(StringName("ar"));
- num_systems[0].lang.insert(StringName("ar_AR"));
- num_systems[0].lang.insert(StringName("ar_BH"));
- num_systems[0].lang.insert(StringName("ar_DJ"));
- num_systems[0].lang.insert(StringName("ar_EG"));
- num_systems[0].lang.insert(StringName("ar_ER"));
- num_systems[0].lang.insert(StringName("ar_IL"));
- num_systems[0].lang.insert(StringName("ar_IQ"));
- num_systems[0].lang.insert(StringName("ar_JO"));
- num_systems[0].lang.insert(StringName("ar_KM"));
- num_systems[0].lang.insert(StringName("ar_KW"));
- num_systems[0].lang.insert(StringName("ar_LB"));
- num_systems[0].lang.insert(StringName("ar_MR"));
- num_systems[0].lang.insert(StringName("ar_OM"));
- num_systems[0].lang.insert(StringName("ar_PS"));
- num_systems[0].lang.insert(StringName("ar_QA"));
- num_systems[0].lang.insert(StringName("ar_SA"));
- num_systems[0].lang.insert(StringName("ar_SD"));
- num_systems[0].lang.insert(StringName("ar_SO"));
- num_systems[0].lang.insert(StringName("ar_SS"));
- num_systems[0].lang.insert(StringName("ar_SY"));
- num_systems[0].lang.insert(StringName("ar_TD"));
- num_systems[0].lang.insert(StringName("ar_YE"));
-
- num_systems[1].lang.insert(StringName("fa"));
- num_systems[1].lang.insert(StringName("ks"));
- num_systems[1].lang.insert(StringName("pa_Arab"));
- num_systems[1].lang.insert(StringName("ug"));
- num_systems[1].lang.insert(StringName("ur_IN"));
- num_systems[1].lang.insert(StringName("ur"));
- num_systems[1].lang.insert(StringName("uz_Arab"));
-
- num_systems[2].lang.insert(StringName("as"));
- num_systems[2].lang.insert(StringName("bn"));
- num_systems[2].lang.insert(StringName("mni"));
-
- num_systems[3].lang.insert(StringName("mr"));
- num_systems[3].lang.insert(StringName("ne"));
-
- num_systems[4].lang.insert(StringName("dz"));
-
- num_systems[5].lang.insert(StringName("sat"));
-
- num_systems[6].lang.insert(StringName("my"));
+ // Chakma numerals.
+ {
+ NumSystemData ccp;
+ ccp.lang.insert(StringName("ccp")); // Chakma
+ ccp.lang.insert(StringName("ccp_BD"));
+ ccp.lang.insert(StringName("ccp_IN"));
+ ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";
+ ccp.percent_sign = U"%";
+ ccp.exp = U"e";
+ num_systems.push_back(ccp);
+ }
+
+ // Adlam numerals.
+ {
+ NumSystemData ff;
+ ff.lang.insert(StringName("ff")); // Fulah
+ ff.lang.insert(StringName("ff_Adlm_BF"));
+ ff.lang.insert(StringName("ff_Adlm_CM"));
+ ff.lang.insert(StringName("ff_Adlm_GH"));
+ ff.lang.insert(StringName("ff_Adlm_GM"));
+ ff.lang.insert(StringName("ff_Adlm_GN"));
+ ff.lang.insert(StringName("ff_Adlm_GW"));
+ ff.lang.insert(StringName("ff_Adlm_LR"));
+ ff.lang.insert(StringName("ff_Adlm_MR"));
+ ff.lang.insert(StringName("ff_Adlm_NE"));
+ ff.lang.insert(StringName("ff_Adlm_NG"));
+ ff.lang.insert(StringName("ff_Adlm_SL"));
+ ff.lang.insert(StringName("ff_Adlm_SN"));
+ ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";
+ ff.percent_sign = U"%";
+ ff.exp = U"e";
+ num_systems.push_back(ff);
+ }
}
String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const {
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
@@ -4773,7 +4886,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
@@ -4800,7 +4913,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
String TextServerAdvanced::percent_sign(const String &p_language) const {
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].percent_sign == String()) {
return "%";
@@ -4811,14 +4924,47 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
+String TextServerAdvanced::strip_diacritics(const String &p_string) const {
+ UErrorCode err = U_ZERO_ERROR;
+
+ // Get NFKD normalizer singleton.
+ const UNormalizer2 *unorm = unorm2_getNFKDInstance(&err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));
+
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ // Normalize.
+ Char16String normalized;
+ err = U_ZERO_ERROR;
+ int32_t len = unorm2_normalize(unorm, utf16.ptr(), -1, nullptr, 0, &err);
+ ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, TextServer::strip_diacritics(p_string), u_errorName(err));
+ normalized.resize(len);
+ err = U_ZERO_ERROR;
+ unorm2_normalize(unorm, utf16.ptr(), -1, normalized.ptrw(), len, &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), TextServer::strip_diacritics(p_string), u_errorName(err));
+
+ // Convert back to UTF-32.
+ String normalized_string = String::utf16(normalized.ptr(), len);
+
+ // Strip combining characters.
+ String result;
+ for (int i = 0; i < normalized_string.length(); i++) {
+ if (u_getCombiningClass(normalized_string[i]) == 0) {
+ result += normalized_string[i];
+ }
+ }
+ return result;
+}
+
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
- hb_bmp_create_font_funcs();
+ _bmp_create_font_funcs();
}
TextServerAdvanced::~TextServerAdvanced() {
- hb_bmp_free_font_funcs();
+ _bmp_free_font_funcs();
if (library != nullptr) {
FT_Done_FreeType(library);
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 1feeada76d..15f3a7f1a9 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -50,6 +50,7 @@
#include <unicode/udata.h>
#include <unicode/uiter.h>
#include <unicode/uloc.h>
+#include <unicode/unorm2.h>
#include <unicode/uscript.h>
#include <unicode/ustring.h>
#include <unicode/utypes.h>
@@ -79,6 +80,19 @@ class TextServerAdvanced : public TextServer {
static String interface_name;
static uint32_t interface_features;
+ struct NumSystemData {
+ Set<StringName> lang;
+ String digits;
+ String percent_sign;
+ String exp;
+ };
+
+ Vector<NumSystemData> num_systems;
+ Map<StringName, int32_t> feature_sets;
+
+ void _insert_num_systems_lang();
+ void _insert_feature_sets();
+
// ICU support data.
uint8_t *icu_data = nullptr;
@@ -258,24 +272,24 @@ class TextServerAdvanced : public TextServer {
static hb_font_funcs_t *funcs;
- struct hb_bmp_font_t {
+ struct bmp_font_t {
TextServerAdvanced::FontDataForSizeAdvanced *face = nullptr;
bool unref = false; /* Whether to destroy bm_face when done. */
};
- static hb_bmp_font_t *_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
- static void _hb_bmp_font_destroy(void *p_data);
- static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
- static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data);
- static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data);
- static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data);
- static void hb_bmp_create_font_funcs();
- static void hb_bmp_free_font_funcs();
- static void _hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
- static hb_font_t *hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
+ static bmp_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static void _bmp_font_destroy(void *p_data);
+ static hb_bool_t _bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
+ static hb_bool_t _bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data);
+ static hb_bool_t _bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data);
+ static hb_bool_t _bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data);
+ static void _bmp_create_font_funcs();
+ static void _bmp_free_font_funcs();
+ static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
protected:
static void _bind_methods(){};
@@ -488,6 +502,8 @@ public:
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
+ virtual String strip_diacritics(const String &p_string) const override;
+
TextServerAdvanced();
~TextServerAdvanced();
};
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 3d868d7be3..f598eb80ea 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -111,22 +111,14 @@ bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const {
return false; // No RTL support.
}
-#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF)))
-
-struct FeatureInfo {
- int32_t tag;
- String name;
-};
-
-static FeatureInfo feature_set[] = {
- // Registered OpenType variation tags.
- { OT_TAG('i', 't', 'a', 'l'), "italic" },
- { OT_TAG('o', 'p', 's', 'z'), "optical_size" },
- { OT_TAG('s', 'l', 'n', 't'), "slant" },
- { OT_TAG('w', 'd', 't', 'h'), "width" },
- { OT_TAG('w', 'g', 'h', 't'), "weight" },
- { 0, String() },
-};
+void TextServerFallback::_insert_feature_sets() {
+ // Registered OpenType variation tag.
+ feature_sets.insert("italic", OT_TAG('i', 't', 'a', 'l'));
+ feature_sets.insert("optical_size", OT_TAG('o', 'p', 's', 'z'));
+ feature_sets.insert("slant", OT_TAG('s', 'l', 'n', 't'));
+ feature_sets.insert("width", OT_TAG('w', 'd', 't', 'h'));
+ feature_sets.insert("weight", OT_TAG('w', 'g', 'h', 't'));
+}
_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
char tag[4];
@@ -150,10 +142,8 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
}
int32_t TextServerFallback::name_to_tag(const String &p_name) const {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].name == p_name) {
- return feature_set[i].tag;
- }
+ if (feature_sets.has(p_name)) {
+ return feature_sets[p_name];
}
// No readable name, use tag string.
@@ -168,9 +158,9 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
}
String TextServerFallback::tag_to_name(int32_t p_tag) const {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].tag == p_tag) {
- return feature_set[i].name;
+ for (const KeyValue<StringName, int32_t> &E : feature_sets) {
+ if (E.value == p_tag) {
+ return E.key;
}
}
@@ -205,6 +195,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
continue;
}
+ if (ct.offsets.size() < ct.texture_w) {
+ continue;
+ }
+
ret.y = 0x7FFFFFFF;
ret.x = 0;
@@ -421,7 +415,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
edgeColoringSimple(shape, 3.0); // Max. angle.
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
- //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
DistancePixelConversion distancePixelConversion(p_pixel_range);
msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
@@ -515,11 +508,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
break;
case FT_PIXEL_MODE_BGRA: {
@@ -677,13 +670,14 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d
}
_FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback *p_font_data, const Vector2i &p_size) const {
+ ERR_FAIL_COND_V(p_size.x <= 0, false);
if (p_font_data->cache.has(p_size)) {
return true;
}
FontDataForSizeFallback *fd = memnew(FontDataForSizeFallback);
fd->size = p_size;
- if (p_font_data->data_ptr) {
+ if (p_font_data->data_ptr && (p_font_data->data_size > 0)) {
// Init dynamic font.
#ifdef MODULE_FREETYPE_ENABLED
int error = 0;
@@ -1304,6 +1298,7 @@ void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+ ERR_FAIL_COND(p_texture_index < 0);
if (p_texture_index >= fd->cache[size]->textures.size()) {
fd->cache[size]->textures.resize(p_texture_index + 1);
}
@@ -1661,12 +1656,14 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
}
int32_t TextServerFallback::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
+ ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), 0, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
return (int32_t)p_char;
}
bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
+ ERR_FAIL_COND_V_MSG((p_char >= 0xd800 && p_char <= 0xdfff) || (p_char > 0x10ffff), false, "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_char, 16) + ".");
MutexLock lock(fd->mutex);
if (fd->cache.is_empty()) {
@@ -1719,6 +1716,8 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
+ ERR_FAIL_COND_MSG((p_start >= 0xd800 && p_start <= 0xdfff) || (p_start > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_start, 16) + ".");
+ ERR_FAIL_COND_MSG((p_end >= 0xd800 && p_end <= 0xdfff) || (p_end > 0x10ffff), "Unicode parsing error: Invalid unicode codepoint " + String::num_int64(p_end, 16) + ".");
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
@@ -2269,7 +2268,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -2297,7 +2296,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -2420,7 +2419,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -2448,7 +2447,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -2960,7 +2959,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.y);
@@ -2988,7 +2987,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
full_ascent = MAX(full_ascent, -E.value.rect.position.x);
@@ -3148,7 +3147,9 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons
return sd->uthk;
}
-TextServerFallback::TextServerFallback(){};
+TextServerFallback::TextServerFallback() {
+ _insert_feature_sets();
+};
TextServerFallback::~TextServerFallback() {
if (library != nullptr) {
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 992ce5018f..fb7de8f443 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -54,6 +54,8 @@
#include FT_BBOX_H
#endif
+#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF)))
+
class TextServerFallback : public TextServer {
GDCLASS(TextServerFallback, TextServer);
_THREAD_SAFE_CLASS_
@@ -61,6 +63,10 @@ class TextServerFallback : public TextServer {
static String interface_name;
static uint32_t interface_features;
+ Map<StringName, int32_t> feature_sets;
+
+ void _insert_feature_sets();
+
// Font cache data.
#ifdef MODULE_FREETYPE_ENABLED
diff --git a/modules/theora/config.py b/modules/theora/config.py
index b063ed51f9..7f354a8fda 100644
--- a/modules/theora/config.py
+++ b/modules/theora/config.py
@@ -1,4 +1,6 @@
def can_build(env, platform):
+ if env["arch"].startswith("rv"):
+ return False
return env.module_check_dependencies("theora", ["ogg", "vorbis"])
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index 2dfcd27dff..725f87b046 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -4,7 +4,7 @@
[VideoStream] resource for Ogg Theora videos.
</brief_description>
<description>
- [VideoStream] resource handling the [url=https://www.theora.org/]Ogg Theora[/url] video format with [code].ogv[/code] extension. The Theora codec is less efficient than [VideoStreamWebm]'s VP8 and VP9, but it requires less CPU resources to decode. The Theora codec is decoded on the CPU.
+ [VideoStream] resource handling the [url=https://www.theora.org/]Ogg Theora[/url] video format with [code].ogv[/code] extension. The Theora codec is decoded on the CPU.
[b]Note:[/b] While Ogg Theora videos can also have an [code].ogg[/code] extension, you will have to rename the extension to [code].ogv[/code] to use those videos within Godot.
</description>
<tutorials>
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 2f6faec8ec..ef434f107e 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -108,7 +108,7 @@ void VideoStreamPlaybackTheora::video_write() {
Ref<Image> img = memnew(Image(size.x, size.y, 0, Image::FORMAT_RGBA8, frame_data)); //zero copy image creation
- texture->update(img); //zero copy send to visual server
+ texture->update(img); //zero copy send to rendering server
frames_pending = 1;
}
@@ -603,7 +603,7 @@ float VideoStreamPlaybackTheora::get_playback_position() const {
};
void VideoStreamPlaybackTheora::seek(float p_time) {
- WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
+ WARN_PRINT_ONCE("Seeking in Theora videos is not implemented yet (it's only supported for GDNative-provided video streams).");
}
void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback, void *p_userdata) {
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 54d310e636..8f4e807295 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -1688,7 +1688,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
// debugger break did not happen
if (!VisualScriptLanguage::singleton->debug_break(error_str, false)) {
- _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, error_str.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, error_str.utf8().get_data(), false, ERR_HANDLER_SCRIPT);
}
//}
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 8cb701ea20..d73b8d3ca0 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -4262,8 +4262,6 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);
-
- ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &VisualScriptEditor::add_syntax_highlighter);
}
VisualScriptEditor::VisualScriptEditor() {
diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h
index bf2d8e9683..78881f0a53 100644
--- a/modules/visual_script/visual_script_nodes.h
+++ b/modules/visual_script/visual_script_nodes.h
@@ -90,12 +90,6 @@ public:
void set_stack_size(int p_size);
int get_stack_size() const;
- void set_return_type_enabled(bool p_returns);
- bool is_return_type_enabled() const;
-
- void set_return_type(Variant::Type p_type);
- Variant::Type get_return_type() const;
-
void set_rpc_mode(Multiplayer::RPCMode p_mode);
Multiplayer::RPCMode get_rpc_mode() const;
diff --git a/modules/webm/SCsub b/modules/webm/SCsub
deleted file mode 100644
index 44e80e2870..0000000000
--- a/modules/webm/SCsub
+++ /dev/null
@@ -1,48 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_webm = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-thirdparty_dir = "#thirdparty/libsimplewebm/"
-thirdparty_sources = [
- "libwebm/mkvparser/mkvparser.cc",
- "OpusVorbisDecoder.cpp",
- "VPXDecoder.cpp",
- "WebMDemuxer.cpp",
-]
-thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
-
-env_webm.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "libwebm/"])
-
-# also requires libogg, libvorbis and libopus
-if env["builtin_libogg"]:
- env_webm.Prepend(CPPPATH=["#thirdparty/libogg"])
-if env["builtin_libvorbis"]:
- env_webm.Prepend(CPPPATH=["#thirdparty/libvorbis"])
-if env["builtin_opus"]:
- env_webm.Prepend(CPPPATH=["#thirdparty/opus"])
-
-if env["builtin_libvpx"]:
- env_webm.Prepend(CPPPATH=["#thirdparty/libvpx"])
- SConscript("libvpx/SCsub")
-
-env_thirdparty = env_webm.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-# Godot source files
-
-module_obj = []
-
-env_webm.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/webm/config.py b/modules/webm/config.py
deleted file mode 100644
index 99f8ace114..0000000000
--- a/modules/webm/config.py
+++ /dev/null
@@ -1,19 +0,0 @@
-def can_build(env, platform):
- if platform in ["iphone"]:
- return False
-
- return env.module_check_dependencies("webm", ["ogg", "opus", "vorbis"])
-
-
-def configure(env):
- pass
-
-
-def get_doc_classes():
- return [
- "VideoStreamWebm",
- ]
-
-
-def get_doc_path():
- return "doc_classes"
diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml
deleted file mode 100644
index e04d02d6ab..0000000000
--- a/modules/webm/doc_classes/VideoStreamWebm.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="VideoStreamWebm" inherits="VideoStream" version="4.0">
- <brief_description>
- [VideoStream] resource for WebM videos.
- </brief_description>
- <description>
- [VideoStream] resource handling the [url=https://www.webmproject.org/]WebM[/url] video format with [code].webm[/code] extension. Both the VP8 and VP9 codecs are supported. The VP8 and VP9 codecs are more efficient than [VideoStreamTheora], but they require more CPU resources to decode (especially VP9). Both the VP8 and VP9 codecs are decoded on the CPU.
- [b]Note:[/b] Alpha channel (also known as transparency) is not supported. The video will always appear to have a black background, even if it originally contains an alpha channel.
- [b]Note:[/b] There are known bugs and performance issues with WebM video playback in Godot. If you run into problems, try using the Ogg Theora format instead: [VideoStreamTheora]
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_file">
- <return type="String" />
- <description>
- Returns the WebM video file handled by this [VideoStreamWebm].
- </description>
- </method>
- <method name="set_file">
- <return type="void" />
- <argument index="0" name="file" type="String" />
- <description>
- Sets the WebM video file that this [VideoStreamWebm] resource handles. The [code]file[/code] name should have the [code].webm[/code] extension.
- </description>
- </method>
- </methods>
-</class>
diff --git a/modules/webm/libvpx/SCsub b/modules/webm/libvpx/SCsub
deleted file mode 100644
index 4334cf732b..0000000000
--- a/modules/webm/libvpx/SCsub
+++ /dev/null
@@ -1,382 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-# Thirdparty sources
-
-libvpx_dir = "#thirdparty/libvpx/"
-
-libvpx_sources = [
- "vp8/vp8_dx_iface.c",
- "vp8/common/generic/systemdependent.c",
- "vp8/common/alloccommon.c",
- "vp8/common/blockd.c",
- "vp8/common/copy_c.c",
- "vp8/common/debugmodes.c",
- "vp8/common/dequantize.c",
- "vp8/common/entropy.c",
- "vp8/common/entropymode.c",
- "vp8/common/entropymv.c",
- "vp8/common/extend.c",
- "vp8/common/filter.c",
- "vp8/common/findnearmv.c",
- "vp8/common/idct_blk.c",
- "vp8/common/idctllm.c",
- "vp8/common/loopfilter_filters.c",
- "vp8/common/mbpitch.c",
- "vp8/common/modecont.c",
- "vp8/common/quant_common.c",
- "vp8/common/reconinter.c",
- "vp8/common/reconintra.c",
- "vp8/common/reconintra4x4.c",
- "vp8/common/rtcd.c",
- "vp8/common/setupintrarecon.c",
- "vp8/common/swapyv12buffer.c",
- "vp8/common/treecoder.c",
- "vp8/common/vp8_loopfilter.c",
- "vp8/decoder/dboolhuff.c",
- "vp8/decoder/decodeframe.c",
- "vp8/decoder/decodemv.c",
- "vp8/decoder/detokenize.c",
- "vp8/decoder/onyxd_if.c",
- "vp9/vp9_dx_iface.c",
- "vp9/common/vp9_alloccommon.c",
- "vp9/common/vp9_blockd.c",
- "vp9/common/vp9_common_data.c",
- "vp9/common/vp9_debugmodes.c",
- "vp9/common/vp9_entropy.c",
- "vp9/common/vp9_entropymode.c",
- "vp9/common/vp9_entropymv.c",
- "vp9/common/vp9_filter.c",
- "vp9/common/vp9_frame_buffers.c",
- "vp9/common/vp9_idct.c",
- "vp9/common/vp9_loopfilter.c",
- "vp9/common/vp9_mvref_common.c",
- "vp9/common/vp9_pred_common.c",
- "vp9/common/vp9_quant_common.c",
- "vp9/common/vp9_reconinter.c",
- "vp9/common/vp9_reconintra.c",
- "vp9/common/vp9_rtcd.c",
- "vp9/common/vp9_scale.c",
- "vp9/common/vp9_scan.c",
- "vp9/common/vp9_seg_common.c",
- "vp9/common/vp9_thread_common.c",
- "vp9/common/vp9_tile_common.c",
- "vp9/decoder/vp9_decodeframe.c",
- "vp9/decoder/vp9_decodemv.c",
- "vp9/decoder/vp9_decoder.c",
- "vp9/decoder/vp9_detokenize.c",
- "vp9/decoder/vp9_dsubexp.c",
- "vp9/decoder/vp9_dthread.c",
- "vpx/src/vpx_codec.c",
- "vpx/src/vpx_decoder.c",
- "vpx/src/vpx_image.c",
- "vpx/src/vpx_psnr.c",
- "vpx_dsp/bitreader.c",
- "vpx_dsp/bitreader_buffer.c",
- "vpx_dsp/intrapred.c",
- "vpx_dsp/inv_txfm.c",
- "vpx_dsp/loopfilter.c",
- "vpx_dsp/prob.c",
- "vpx_dsp/vpx_convolve.c",
- "vpx_dsp/vpx_dsp_rtcd.c",
- "vpx_mem/vpx_mem.c",
- "vpx_scale/vpx_scale_rtcd.c",
- "vpx_scale/generic/yv12config.c",
- "vpx_scale/generic/yv12extend.c",
- "vpx_util/vpx_thread.c",
-]
-
-libvpx_sources_mt = [
- "vp8/decoder/threading.c",
-]
-
-libvpx_sources_intrin_x86 = [
- "vp8/common/x86/filter_x86.c",
- "vp8/common/x86/loopfilter_x86.c",
- "vp8/common/x86/vp8_asm_stubs.c",
- "vpx_dsp/x86/vpx_asm_stubs.c",
-]
-libvpx_sources_intrin_x86_mmx = [
- "vp8/common/x86/idct_blk_mmx.c",
-]
-libvpx_sources_intrin_x86_sse2 = [
- "vp8/common/x86/idct_blk_sse2.c",
- "vp9/common/x86/vp9_idct_intrin_sse2.c",
- "vpx_dsp/x86/inv_txfm_sse2.c",
- "vpx_dsp/x86/loopfilter_sse2.c",
-]
-libvpx_sources_intrin_x86_ssse3 = [
- "vpx_dsp/x86/vpx_subpixel_8t_intrin_ssse3.c",
-]
-libvpx_sources_intrin_x86_avx2 = [
- "vpx_dsp/x86/loopfilter_avx2.c",
- "vpx_dsp/x86/vpx_subpixel_8t_intrin_avx2.c",
-]
-libvpx_sources_x86asm = [
- "vp8/common/x86/copy_sse2.asm",
- "vp8/common/x86/copy_sse3.asm",
- "vp8/common/x86/dequantize_mmx.asm",
- "vp8/common/x86/idctllm_mmx.asm",
- "vp8/common/x86/idctllm_sse2.asm",
- "vp8/common/x86/iwalsh_mmx.asm",
- "vp8/common/x86/iwalsh_sse2.asm",
- "vp8/common/x86/loopfilter_sse2.asm",
- "vp8/common/x86/recon_mmx.asm",
- "vp8/common/x86/recon_sse2.asm",
- "vp8/common/x86/subpixel_mmx.asm",
- "vp8/common/x86/subpixel_sse2.asm",
- "vp8/common/x86/subpixel_ssse3.asm",
- "vp8/common/x86/vp8_loopfilter_mmx.asm",
- "vpx_dsp/x86/intrapred_sse2.asm",
- "vpx_dsp/x86/intrapred_ssse3.asm",
- "vpx_dsp/x86/inv_wht_sse2.asm",
- "vpx_dsp/x86/vpx_convolve_copy_sse2.asm",
- "vpx_dsp/x86/vpx_subpixel_8t_sse2.asm",
- "vpx_dsp/x86/vpx_subpixel_8t_ssse3.asm",
- "vpx_dsp/x86/vpx_subpixel_bilinear_sse2.asm",
- "vpx_dsp/x86/vpx_subpixel_bilinear_ssse3.asm",
- "vpx_ports/emms.asm",
-]
-libvpx_sources_x86_64asm = [
- "vp8/common/x86/loopfilter_block_sse2_x86_64.asm",
- "vpx_dsp/x86/inv_txfm_ssse3_x86_64.asm",
-]
-
-libvpx_sources_arm = [
- "vpx_ports/arm_cpudetect.c",
- "vp8/common/arm/loopfilter_arm.c",
-]
-libvpx_sources_arm_neon = [
- "vp8/common/arm/neon/bilinearpredict_neon.c",
- "vp8/common/arm/neon/copymem_neon.c",
- "vp8/common/arm/neon/dc_only_idct_add_neon.c",
- "vp8/common/arm/neon/dequant_idct_neon.c",
- "vp8/common/arm/neon/dequantizeb_neon.c",
- "vp8/common/arm/neon/idct_blk_neon.c",
- "vp8/common/arm/neon/idct_dequant_0_2x_neon.c",
- "vp8/common/arm/neon/idct_dequant_full_2x_neon.c",
- "vp8/common/arm/neon/iwalsh_neon.c",
- "vp8/common/arm/neon/loopfiltersimplehorizontaledge_neon.c",
- "vp8/common/arm/neon/loopfiltersimpleverticaledge_neon.c",
- "vp8/common/arm/neon/mbloopfilter_neon.c",
- "vp8/common/arm/neon/shortidct4x4llm_neon.c",
- "vp8/common/arm/neon/sixtappredict_neon.c",
- "vp8/common/arm/neon/vp8_loopfilter_neon.c",
- "vp9/common/arm/neon/vp9_iht4x4_add_neon.c",
- "vp9/common/arm/neon/vp9_iht8x8_add_neon.c",
- "vpx_dsp/arm/idct16x16_1_add_neon.c",
- "vpx_dsp/arm/idct16x16_add_neon.c",
- "vpx_dsp/arm/idct16x16_neon.c",
- "vpx_dsp/arm/idct32x32_1_add_neon.c",
- "vpx_dsp/arm/idct32x32_add_neon.c",
- "vpx_dsp/arm/idct4x4_1_add_neon.c",
- "vpx_dsp/arm/idct4x4_add_neon.c",
- "vpx_dsp/arm/idct8x8_1_add_neon.c",
- "vpx_dsp/arm/idct8x8_add_neon.c",
- "vpx_dsp/arm/intrapred_neon.c",
- "vpx_dsp/arm/loopfilter_16_neon.c",
- "vpx_dsp/arm/loopfilter_4_neon.c",
- "vpx_dsp/arm/loopfilter_8_neon.c",
- "vpx_dsp/arm/loopfilter_neon.c",
- "vpx_dsp/arm/vpx_convolve8_avg_neon.c",
- "vpx_dsp/arm/vpx_convolve8_neon.c",
- "vpx_dsp/arm/vpx_convolve_avg_neon.c",
- "vpx_dsp/arm/vpx_convolve_copy_neon.c",
- "vpx_dsp/arm/vpx_convolve_neon.c",
-]
-libvpx_sources_arm_neon_gas = [
- "vpx_dsp/arm/gas/intrapred_neon_asm.s",
- "vpx_dsp/arm/gas/loopfilter_mb_neon.s",
- "vpx_dsp/arm/gas/save_reg_neon.s",
-]
-libvpx_sources_arm_neon_armasm_ms = [
- "vpx_dsp/arm/armasm_ms/intrapred_neon_asm.asm",
- "vpx_dsp/arm/armasm_ms/loopfilter_mb_neon.asm",
- "vpx_dsp/arm/armasm_ms/save_reg_neon.asm",
-]
-libvpx_sources_arm_neon_gas_apple = [
- "vpx_dsp/arm/gas_apple/intrapred_neon_asm.s",
- "vpx_dsp/arm/gas_apple/loopfilter_mb_neon.s",
- "vpx_dsp/arm/gas_apple/save_reg_neon.s",
-]
-
-libvpx_sources = [libvpx_dir + file for file in libvpx_sources]
-libvpx_sources_mt = [libvpx_dir + file for file in libvpx_sources_mt]
-libvpx_sources_intrin_x86 = [libvpx_dir + file for file in libvpx_sources_intrin_x86]
-libvpx_sources_intrin_x86_mmx = [libvpx_dir + file for file in libvpx_sources_intrin_x86_mmx]
-libvpx_sources_intrin_x86_sse2 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_sse2]
-libvpx_sources_intrin_x86_ssse3 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_ssse3]
-libvpx_sources_intrin_x86_avx2 = [libvpx_dir + file for file in libvpx_sources_intrin_x86_avx2]
-libvpx_sources_x86asm = [libvpx_dir + file for file in libvpx_sources_x86asm]
-libvpx_sources_x86_64asm = [libvpx_dir + file for file in libvpx_sources_x86_64asm]
-libvpx_sources_arm = [libvpx_dir + file for file in libvpx_sources_arm]
-libvpx_sources_arm_neon = [libvpx_dir + file for file in libvpx_sources_arm_neon]
-libvpx_sources_arm_neon_gas = [libvpx_dir + file for file in libvpx_sources_arm_neon_gas]
-libvpx_sources_arm_neon_armasm_ms = [libvpx_dir + file for file in libvpx_sources_arm_neon_armasm_ms]
-libvpx_sources_arm_neon_gas_apple = [libvpx_dir + file for file in libvpx_sources_arm_neon_gas_apple]
-
-
-env_libvpx = env_modules.Clone()
-env_libvpx.disable_warnings()
-env_libvpx.Prepend(CPPPATH=[libvpx_dir])
-
-webm_multithread = env["platform"] != "javascript"
-
-cpu_bits = env["bits"]
-webm_cpu_x86 = False
-webm_cpu_arm = False
-if env["platform"] == "uwp":
- if "arm" in env["PROGSUFFIX"]:
- webm_cpu_arm = True
- else:
- webm_cpu_x86 = True
-else:
- import platform
-
- is_x11_or_server_arm = env["platform"] == "linuxbsd" and (
- platform.machine().startswith("arm") or platform.machine().startswith("aarch")
- )
- is_macos_x86 = env["platform"] == "osx" and ("arch" in env and (env["arch"] != "arm64"))
- is_ios_x86 = env["platform"] == "iphone" and ("arch" in env and env["arch"].startswith("x86"))
- is_android_x86 = env["platform"] == "android" and env["android_arch"].startswith("x86")
- if is_android_x86:
- cpu_bits = "32" if env["android_arch"] == "x86" else "64"
- webm_cpu_x86 = (
- not is_x11_or_server_arm
- and (cpu_bits == "32" or cpu_bits == "64")
- and (
- env["platform"] == "windows"
- or env["platform"] == "linuxbsd"
- or env["platform"] == "haiku"
- or is_macos_x86
- or is_android_x86
- or is_ios_x86
- )
- )
- webm_cpu_arm = (
- is_x11_or_server_arm
- or (not is_macos_x86 and env["platform"] == "osx")
- or (not is_ios_x86 and env["platform"] == "iphone")
- or (not is_android_x86 and env["platform"] == "android")
- )
-
-if webm_cpu_x86:
- import subprocess
- import os
-
- yasm_paths = [
- "yasm",
- "../../../yasm",
- ]
-
- yasm_found = False
-
- devnull = open(os.devnull)
- for yasm_path in yasm_paths:
- try:
- yasm_found = True
- subprocess.Popen([yasm_path, "--version"], stdout=devnull, stderr=devnull).communicate()
- except Exception:
- yasm_found = False
- if yasm_found:
- break
-
- if not yasm_found:
- webm_cpu_x86 = False
- print("YASM is necessary for WebM SIMD optimizations.")
-
-webm_simd_optimizations = False
-
-if webm_cpu_x86:
- if env["platform"] == "windows" or env["platform"] == "uwp":
- env_libvpx["ASFORMAT"] = "win"
- elif env["platform"] == "osx" or env["platform"] == "iphone":
- env_libvpx["ASFORMAT"] = "macho"
- else:
- env_libvpx["ASFORMAT"] = "elf"
- env_libvpx["ASFORMAT"] += cpu_bits
-
- env_libvpx["AS"] = "yasm"
- env_libvpx["ASFLAGS"] = "-I" + libvpx_dir[1:] + " -f $ASFORMAT -D $ASCPU"
- env_libvpx["ASCOM"] = "$AS $ASFLAGS -o $TARGET $SOURCES"
-
- if cpu_bits == "32":
- env_libvpx["ASCPU"] = "X86_32"
- elif cpu_bits == "64":
- env_libvpx["ASCPU"] = "X86_64"
-
- env_libvpx.Append(CPPDEFINES=["WEBM_X86ASM"])
-
- webm_simd_optimizations = True
-
-if webm_cpu_arm:
- if env["platform"] == "iphone":
- env_libvpx["ASFLAGS"] = "-arch armv7"
- elif env["platform"] == "android" and env["android_arch"] == "armv7" or env["platform"] == "linuxbsd":
- env_libvpx["ASFLAGS"] = "-mfpu=neon"
- elif env["platform"] == "uwp":
- env_libvpx["AS"] = "armasm"
- env_libvpx["ASFLAGS"] = ""
- env_libvpx["ASCOM"] = "$AS $ASFLAGS -o $TARGET $SOURCES"
-
- env_libvpx.Append(CPPDEFINES=["WEBM_ARMASM"])
-
- webm_simd_optimizations = True
-
-if webm_simd_optimizations == False:
- print("WebM SIMD optimizations are disabled. Check if your CPU architecture, CPU bits or platform are supported!")
-
-env_libvpx.add_source_files(env.modules_sources, libvpx_sources)
-
-if webm_multithread:
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_mt)
-
-if webm_cpu_x86:
- is_clang_or_gcc = (
- ("gcc" in os.path.basename(env["CC"])) or ("clang" in os.path.basename(env["CC"])) or ("osxcross" in env)
- )
-
- env_libvpx_mmx = env_libvpx.Clone()
- if cpu_bits == "32" and is_clang_or_gcc:
- env_libvpx_mmx.Append(CCFLAGS=["-mmmx"])
- env_libvpx_mmx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_mmx)
-
- env_libvpx_sse2 = env_libvpx.Clone()
- if cpu_bits == "32" and is_clang_or_gcc:
- env_libvpx_sse2.Append(CCFLAGS=["-msse2"])
- env_libvpx_sse2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_sse2)
-
- env_libvpx_ssse3 = env_libvpx.Clone()
- if is_clang_or_gcc:
- env_libvpx_ssse3.Append(CCFLAGS=["-mssse3"])
- env_libvpx_ssse3.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_ssse3)
-
- env_libvpx_avx2 = env_libvpx.Clone()
- if is_clang_or_gcc:
- env_libvpx_avx2.Append(CCFLAGS=["-mavx2"])
- env_libvpx_avx2.add_source_files(env.modules_sources, libvpx_sources_intrin_x86_avx2)
-
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_intrin_x86)
-
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86asm)
- if cpu_bits == "64":
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_x86_64asm)
-elif webm_cpu_arm:
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm)
- if env["platform"] == "android":
- env_libvpx.Prepend(CPPPATH=[libvpx_dir + "third_party/android"])
- env_libvpx.add_source_files(env.modules_sources, [libvpx_dir + "third_party/android/cpu-features.c"])
-
- env_libvpx_neon = env_libvpx.Clone()
- env_libvpx_neon.add_source_files(env.modules_sources, libvpx_sources_arm_neon)
-
- if env["platform"] == "uwp":
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_armasm_ms)
- elif env["platform"] == "iphone":
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas_apple)
- elif (is_x11_or_server_arm and cpu_bits == "32") or (
- env["platform"] == "android" and not env["android_arch"] == "arm64v8"
- ):
- env_libvpx.add_source_files(env.modules_sources, libvpx_sources_arm_neon_gas)
diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp
deleted file mode 100644
index 8f690a6892..0000000000
--- a/modules/webm/register_types.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "video_stream_webm.h"
-
-static Ref<ResourceFormatLoaderWebm> resource_loader_webm;
-
-void register_webm_types() {
- resource_loader_webm.instantiate();
- ResourceLoader::add_resource_format_loader(resource_loader_webm, true);
-
- GDREGISTER_CLASS(VideoStreamWebm);
-}
-
-void unregister_webm_types() {
- ResourceLoader::remove_resource_format_loader(resource_loader_webm);
- resource_loader_webm.unref();
-}
diff --git a/modules/webm/register_types.h b/modules/webm/register_types.h
deleted file mode 100644
index d090fe745b..0000000000
--- a/modules/webm/register_types.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 WEBM_REGISTER_TYPES_H
-#define WEBM_REGISTER_TYPES_H
-
-void register_webm_types();
-void unregister_webm_types();
-
-#endif // WEBM_REGISTER_TYPES_H
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
deleted file mode 100644
index 12e0f5bd25..0000000000
--- a/modules/webm/video_stream_webm.cpp
+++ /dev/null
@@ -1,469 +0,0 @@
-/*************************************************************************/
-/* video_stream_webm.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 "video_stream_webm.h"
-
-#include "core/config/project_settings.h"
-#include "core/io/file_access.h"
-#include "core/os/os.h"
-#include "servers/audio_server.h"
-
-#include "thirdparty/misc/yuv2rgb.h"
-
-// libsimplewebm
-#include <OpusVorbisDecoder.hpp>
-#include <VPXDecoder.hpp>
-
-// libvpx
-#include <vpx/vpx_image.h>
-
-// libwebm
-#include <mkvparser/mkvparser.h>
-
-class MkvReader : public mkvparser::IMkvReader {
-public:
- MkvReader(const String &p_file) {
- file = FileAccess::open(p_file, FileAccess::READ);
-
- ERR_FAIL_COND_MSG(!file, "Failed loading resource: '" + p_file + "'.");
- }
- ~MkvReader() {
- if (file) {
- memdelete(file);
- }
- }
-
- virtual int Read(long long pos, long len, unsigned char *buf) {
- if (file) {
- if (file->get_position() != (uint64_t)pos) {
- file->seek(pos);
- }
- if (file->get_buffer(buf, len) == (uint64_t)len) {
- return 0;
- }
- }
- return -1;
- }
-
- virtual int Length(long long *total, long long *available) {
- if (file) {
- const uint64_t len = file->get_length();
- if (total) {
- *total = len;
- }
- if (available) {
- *available = len;
- }
- return 0;
- }
- return -1;
- }
-
-private:
- FileAccess *file;
-};
-
-/**/
-
-VideoStreamPlaybackWebm::VideoStreamPlaybackWebm() :
-
- texture(memnew(ImageTexture)) {}
-VideoStreamPlaybackWebm::~VideoStreamPlaybackWebm() {
- delete_pointers();
-}
-
-bool VideoStreamPlaybackWebm::open_file(const String &p_file) {
- file_name = p_file;
- webm = memnew(WebMDemuxer(new MkvReader(file_name), 0, audio_track));
- if (webm->isOpen()) {
- video = memnew(VPXDecoder(*webm, OS::get_singleton()->get_processor_count()));
- if (video->isOpen()) {
- audio = memnew(OpusVorbisDecoder(*webm));
- if (audio->isOpen()) {
- audio_frame = memnew(WebMFrame);
- pcm = (float *)memalloc(sizeof(float) * audio->getBufferSamples() * webm->getChannels());
- } else {
- memdelete(audio);
- audio = nullptr;
- }
-
- frame_data.resize((webm->getWidth() * webm->getHeight()) << 2);
- Ref<Image> img;
- img.instantiate();
- img->create(webm->getWidth(), webm->getHeight(), false, Image::FORMAT_RGBA8);
- texture->create_from_image(img);
-
- return true;
- }
- memdelete(video);
- video = nullptr;
- }
- memdelete(webm);
- webm = nullptr;
- return false;
-}
-
-void VideoStreamPlaybackWebm::stop() {
- if (playing) {
- delete_pointers();
-
- pcm = nullptr;
-
- audio_frame = nullptr;
- video_frames = nullptr;
-
- video = nullptr;
- audio = nullptr;
-
- open_file(file_name); //Should not fail here...
-
- video_frames_capacity = video_frames_pos = 0;
- num_decoded_samples = 0;
- samples_offset = -1;
- video_frame_delay = video_pos = 0.0;
- }
- time = 0.0;
- playing = false;
-}
-
-void VideoStreamPlaybackWebm::play() {
- stop();
-
- delay_compensation = ProjectSettings::get_singleton()->get("audio/video/video_delay_compensation_ms");
- delay_compensation /= 1000.0;
-
- playing = true;
-}
-
-bool VideoStreamPlaybackWebm::is_playing() const {
- return playing;
-}
-
-void VideoStreamPlaybackWebm::set_paused(bool p_paused) {
- paused = p_paused;
-}
-
-bool VideoStreamPlaybackWebm::is_paused() const {
- return paused;
-}
-
-void VideoStreamPlaybackWebm::set_loop(bool p_enable) {
- //Empty
-}
-
-bool VideoStreamPlaybackWebm::has_loop() const {
- return false;
-}
-
-float VideoStreamPlaybackWebm::get_length() const {
- if (webm) {
- return webm->getLength();
- }
- return 0.0f;
-}
-
-float VideoStreamPlaybackWebm::get_playback_position() const {
- return video_pos;
-}
-
-void VideoStreamPlaybackWebm::seek(float p_time) {
- WARN_PRINT_ONCE("Seeking in Theora and WebM videos is not implemented yet (it's only supported for GDNative-provided video streams).");
-}
-
-void VideoStreamPlaybackWebm::set_audio_track(int p_idx) {
- audio_track = p_idx;
-}
-
-Ref<Texture2D> VideoStreamPlaybackWebm::get_texture() const {
- return texture;
-}
-
-void VideoStreamPlaybackWebm::update(float p_delta) {
- if ((!playing || paused) || !video) {
- return;
- }
-
- time += p_delta;
-
- if (time < video_pos) {
- return;
- }
-
- bool audio_buffer_full = false;
-
- if (samples_offset > -1) {
- //Mix remaining samples
- const int to_read = num_decoded_samples - samples_offset;
- const int mixed = mix_callback(mix_udata, pcm + samples_offset * webm->getChannels(), to_read);
- if (mixed != to_read) {
- samples_offset += mixed;
- audio_buffer_full = true;
- } else {
- samples_offset = -1;
- }
- }
-
- const bool hasAudio = (audio && mix_callback);
- while ((hasAudio && !audio_buffer_full && !has_enough_video_frames()) ||
- (!hasAudio && video_frames_pos == 0)) {
- if (hasAudio && !audio_buffer_full && audio_frame->isValid() &&
- audio->getPCMF(*audio_frame, pcm, num_decoded_samples) && num_decoded_samples > 0) {
- const int mixed = mix_callback(mix_udata, pcm, num_decoded_samples);
-
- if (mixed != num_decoded_samples) {
- samples_offset = mixed;
- audio_buffer_full = true;
- }
- }
-
- WebMFrame *video_frame;
- if (video_frames_pos >= video_frames_capacity) {
- WebMFrame **video_frames_new = (WebMFrame **)memrealloc(video_frames, ++video_frames_capacity * sizeof(void *));
- ERR_FAIL_COND(!video_frames_new); //Out of memory
- (video_frames = video_frames_new)[video_frames_capacity - 1] = memnew(WebMFrame);
- }
- video_frame = video_frames[video_frames_pos];
-
- if (!webm->readFrame(video_frame, audio_frame)) { //This will invalidate frames
- break; //Can't demux, EOS?
- }
-
- if (video_frame->isValid()) {
- ++video_frames_pos;
- }
- };
-
- bool video_frame_done = false;
- while (video_frames_pos > 0 && !video_frame_done) {
- WebMFrame *video_frame = video_frames[0];
-
- // It seems VPXDecoder::decode has to be executed even though we might skip this frame
- if (video->decode(*video_frame)) {
- VPXDecoder::IMAGE_ERROR err;
- VPXDecoder::Image image;
-
- if (should_process(*video_frame)) {
- if ((err = video->getImage(image)) != VPXDecoder::NO_FRAME) {
- if (err == VPXDecoder::NO_ERROR && image.w == webm->getWidth() && image.h == webm->getHeight()) {
- uint8_t *w = frame_data.ptrw();
- bool converted = false;
-
- if (image.chromaShiftW == 0 && image.chromaShiftH == 0 && image.cs == VPX_CS_SRGB) {
- uint8_t *wp = w;
- unsigned char *rRow = image.planes[2];
- unsigned char *gRow = image.planes[0];
- unsigned char *bRow = image.planes[1];
- for (int i = 0; i < image.h; i++) {
- for (int j = 0; j < image.w; j++) {
- *wp++ = rRow[j];
- *wp++ = gRow[j];
- *wp++ = bRow[j];
- *wp++ = 255;
- }
- rRow += image.linesize[2];
- gRow += image.linesize[0];
- bRow += image.linesize[1];
- }
- converted = true;
- } else if (image.chromaShiftW == 1 && image.chromaShiftH == 1) {
- yuv420_2_rgb8888(w, image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
- //libyuv::I420ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 1 && image.chromaShiftH == 0) {
- yuv422_2_rgb8888(w, image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
- //libyuv::I422ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 0 && image.chromaShiftH == 0) {
- yuv444_2_rgb8888(w, image.planes[0], image.planes[1], image.planes[2], image.w, image.h, image.linesize[0], image.linesize[1], image.w << 2);
- //libyuv::I444ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2], image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- converted = true;
- } else if (image.chromaShiftW == 2 && image.chromaShiftH == 0) {
- //libyuv::I411ToARGB(image.planes[0], image.linesize[0], image.planes[2], image.linesize[2] image.planes[1], image.linesize[1], w.ptr(), image.w << 2, image.w, image.h);
- //converted = true;
- }
-
- if (converted) {
- Ref<Image> img = memnew(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data));
- texture->update(img); //Zero copy send to visual server
- video_frame_done = true;
- }
- }
- }
- }
- }
-
- video_pos = video_frame->time;
- memmove(video_frames, video_frames + 1, (--video_frames_pos) * sizeof(void *));
- video_frames[video_frames_pos] = video_frame;
- }
-
- if (video_frames_pos == 0 && webm->isEOS()) {
- stop();
- }
-}
-
-void VideoStreamPlaybackWebm::set_mix_callback(VideoStreamPlayback::AudioMixCallback p_callback, void *p_userdata) {
- mix_callback = p_callback;
- mix_udata = p_userdata;
-}
-
-int VideoStreamPlaybackWebm::get_channels() const {
- if (audio) {
- return webm->getChannels();
- }
- return 0;
-}
-
-int VideoStreamPlaybackWebm::get_mix_rate() const {
- if (audio) {
- return webm->getSampleRate();
- }
- return 0;
-}
-
-inline bool VideoStreamPlaybackWebm::has_enough_video_frames() const {
- if (video_frames_pos > 0) {
- // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to
- // systematically return 0. Now that it gives a proper latency, it broke this
- // code where the delay compensation likely never really worked.
- //const double audio_delay = AudioServer::get_singleton()->get_output_latency();
- const double video_time = video_frames[video_frames_pos - 1]->time;
- return video_time >= time + /* audio_delay + */ delay_compensation;
- }
- return false;
-}
-
-bool VideoStreamPlaybackWebm::should_process(WebMFrame &video_frame) {
- // FIXME: AudioServer output latency was fixed in af9bb0e, previously it used to
- // systematically return 0. Now that it gives a proper latency, it broke this
- // code where the delay compensation likely never really worked.
- //const double audio_delay = AudioServer::get_singleton()->get_output_latency();
- return video_frame.time >= time + /* audio_delay + */ delay_compensation;
-}
-
-void VideoStreamPlaybackWebm::delete_pointers() {
- if (pcm) {
- memfree(pcm);
- }
-
- if (audio_frame) {
- memdelete(audio_frame);
- }
- if (video_frames) {
- for (int i = 0; i < video_frames_capacity; ++i) {
- memdelete(video_frames[i]);
- }
- memfree(video_frames);
- }
-
- if (video) {
- memdelete(video);
- }
- if (audio) {
- memdelete(audio);
- }
-
- if (webm) {
- memdelete(webm);
- }
-}
-
-/**/
-
-VideoStreamWebm::VideoStreamWebm() {}
-
-Ref<VideoStreamPlayback> VideoStreamWebm::instance_playback() {
- Ref<VideoStreamPlaybackWebm> pb = memnew(VideoStreamPlaybackWebm);
- pb->set_audio_track(audio_track);
- if (pb->open_file(file)) {
- return pb;
- }
- return nullptr;
-}
-
-void VideoStreamWebm::set_file(const String &p_file) {
- file = p_file;
-}
-
-String VideoStreamWebm::get_file() {
- return file;
-}
-
-void VideoStreamWebm::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_file", "file"), &VideoStreamWebm::set_file);
- ClassDB::bind_method(D_METHOD("get_file"), &VideoStreamWebm::get_file);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "file", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_file", "get_file");
-}
-
-void VideoStreamWebm::set_audio_track(int p_track) {
- audio_track = p_track;
-}
-
-////////////
-
-RES ResourceFormatLoaderWebm::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
- if (r_error) {
- *r_error = ERR_CANT_OPEN;
- }
- return RES();
- }
-
- VideoStreamWebm *stream = memnew(VideoStreamWebm);
- stream->set_file(p_path);
-
- Ref<VideoStreamWebm> webm_stream = Ref<VideoStreamWebm>(stream);
-
- if (r_error) {
- *r_error = OK;
- }
-
- f->close();
- memdelete(f);
- return webm_stream;
-}
-
-void ResourceFormatLoaderWebm::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("webm");
-}
-
-bool ResourceFormatLoaderWebm::handles_type(const String &p_type) const {
- return ClassDB::is_parent_class(p_type, "VideoStream");
-}
-
-String ResourceFormatLoaderWebm::get_resource_type(const String &p_path) const {
- String el = p_path.get_extension().to_lower();
- if (el == "webm") {
- return "VideoStreamWebm";
- }
- return "";
-}
diff --git a/modules/webm/video_stream_webm.h b/modules/webm/video_stream_webm.h
deleted file mode 100644
index 60e02ab38b..0000000000
--- a/modules/webm/video_stream_webm.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*************************************************************************/
-/* video_stream_webm.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 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 VIDEO_STREAM_WEBM_H
-#define VIDEO_STREAM_WEBM_H
-
-#include "core/io/resource_loader.h"
-#include "scene/resources/video_stream.h"
-
-class WebMFrame;
-class WebMDemuxer;
-class VPXDecoder;
-class OpusVorbisDecoder;
-
-class VideoStreamPlaybackWebm : public VideoStreamPlayback {
- GDCLASS(VideoStreamPlaybackWebm, VideoStreamPlayback);
-
- String file_name;
- int audio_track = 0;
-
- WebMDemuxer *webm = nullptr;
- VPXDecoder *video = nullptr;
- OpusVorbisDecoder *audio = nullptr;
-
- WebMFrame **video_frames = nullptr, *audio_frame = nullptr;
- int video_frames_pos = 0, video_frames_capacity = 0;
-
- int num_decoded_samples = 0, samples_offset = -1;
- AudioMixCallback mix_callback = nullptr;
- void *mix_udata = nullptr;
-
- bool playing = false, paused = false;
- double delay_compensation = 0.0;
- double time = 0.0, video_frame_delay = 0.0, video_pos = 0.0;
-
- Vector<uint8_t> frame_data;
- Ref<ImageTexture> texture;
-
- float *pcm = nullptr;
-
-public:
- VideoStreamPlaybackWebm();
- ~VideoStreamPlaybackWebm();
-
- bool open_file(const String &p_file);
-
- virtual void stop() override;
- virtual void play() override;
-
- virtual bool is_playing() const override;
-
- virtual void set_paused(bool p_paused) override;
- virtual bool is_paused() const override;
-
- virtual void set_loop(bool p_enable) override;
- virtual bool has_loop() const override;
-
- virtual float get_length() const override;
-
- virtual float get_playback_position() const override;
- virtual void seek(float p_time) override;
-
- virtual void set_audio_track(int p_idx) override;
-
- virtual Ref<Texture2D> get_texture() const override;
- virtual void update(float p_delta) override;
-
- virtual void set_mix_callback(AudioMixCallback p_callback, void *p_userdata) override;
- virtual int get_channels() const override;
- virtual int get_mix_rate() const override;
-
-private:
- inline bool has_enough_video_frames() const;
- bool should_process(WebMFrame &video_frame);
-
- void delete_pointers();
-};
-
-/**/
-
-class VideoStreamWebm : public VideoStream {
- GDCLASS(VideoStreamWebm, VideoStream);
-
- String file;
- int audio_track = 0;
-
-protected:
- static void _bind_methods();
-
-public:
- VideoStreamWebm();
-
- virtual Ref<VideoStreamPlayback> instance_playback() override;
-
- virtual void set_file(const String &p_file);
- String get_file();
- virtual void set_audio_track(int p_track) override;
-};
-
-class ResourceFormatLoaderWebm : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String &p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-};
-
-#endif // VIDEO_STREAM_WEBM_H
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index f7a8944745..bf35c91c7f 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -129,7 +129,7 @@ void WebSocketClient::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
ClassDB::bind_method(D_METHOD("get_trusted_ssl_certificate"), &WebSocketClient::get_trusted_ssl_certificate);
- ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate"), &WebSocketClient::set_trusted_ssl_certificate);
+ ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate", "cert"), &WebSocketClient::set_trusted_ssl_certificate);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_trusted_ssl_certificate", "get_trusted_ssl_certificate");
diff --git a/modules/websocket/websocket_macros.h b/modules/websocket/websocket_macros.h
index d04909c97d..2ca60a3b61 100644
--- a/modules/websocket/websocket_macros.h
+++ b/modules/websocket/websocket_macros.h
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WEBSOCKETMACTOS_H
-#define WEBSOCKETMACTOS_H
+#ifndef WEBSOCKET_MACROS_H
+#define WEBSOCKET_MACROS_H
// Defaults per peer buffers, 1024 packets with a shared 65536 bytes payload.
#define DEF_PKT_SHIFT 10
@@ -65,4 +65,4 @@ public:\
protected:\
/* clang-format on */
-#endif // WEBSOCKETMACTOS_H
+#endif // WEBSOCKET_MACROS_H
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index fb838109f3..e7f90fdeba 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -50,19 +50,19 @@ void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_bind_ip"), &WebSocketServer::get_bind_ip);
- ClassDB::bind_method(D_METHOD("set_bind_ip"), &WebSocketServer::set_bind_ip);
+ ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &WebSocketServer::set_bind_ip);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bind_ip"), "set_bind_ip", "get_bind_ip");
ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key);
- ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key);
+ ClassDB::bind_method(D_METHOD("set_private_key", "key"), &WebSocketServer::set_private_key);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", PROPERTY_USAGE_NONE), "set_private_key", "get_private_key");
ClassDB::bind_method(D_METHOD("get_ssl_certificate"), &WebSocketServer::get_ssl_certificate);
- ClassDB::bind_method(D_METHOD("set_ssl_certificate"), &WebSocketServer::set_ssl_certificate);
+ ClassDB::bind_method(D_METHOD("set_ssl_certificate", "cert"), &WebSocketServer::set_ssl_certificate);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ssl_certificate", "get_ssl_certificate");
ClassDB::bind_method(D_METHOD("get_ca_chain"), &WebSocketServer::get_ca_chain);
- ClassDB::bind_method(D_METHOD("set_ca_chain"), &WebSocketServer::set_ca_chain);
+ ClassDB::bind_method(D_METHOD("set_ca_chain", "ca_chain"), &WebSocketServer::set_ca_chain);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ca_chain", "get_ca_chain");
ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout);
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 93c8bd9604..508b5a12a1 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -53,7 +53,7 @@ private:
Ref<StreamPeer> connection;
bool use_ssl = false;
- int time = 0;
+ uint64_t time = 0;
uint8_t req_buf[WSL_MAX_HEADER_SIZE] = {};
int req_pos = 0;
String key;
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index 16d671c9e9..6e224a8242 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -87,7 +87,7 @@
There are several ways to handle "controller" input:
- Using [XRController3D] nodes and their [signal XRController3D.button_pressed] and [signal XRController3D.button_released] signals. This is how controllers are typically handled in AR/VR apps in Godot, however, this will only work with advanced VR controllers like the Oculus Touch or Index controllers, for example. The buttons codes are defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
- Using [method Node._unhandled_input] and [InputEventJoypadButton] or [InputEventJoypadMotion]. This works the same as normal joypads, except the [member InputEvent.device] starts at 100, so the left controller is 100 and the right controller is 101, and the button codes are also defined by [url=https://immersive-web.github.io/webxr-gamepads-module/#xr-standard-gamepad-mapping]Section 3.3 of the WebXR Gamepads Module[/url].
- - Using the [signal select], [signal squeeze] and related signals. This method will work for both advanced VR controllers, and non-traditional "controllers" like a tap on the screen, a spoken voice command or a button press on the device itself. The [code]controller_id[/code] passed to these signals is the same id as used in [member XRController3D.controller_id].
+ - Using the [signal select], [signal squeeze] and related signals. This method will work for both advanced VR controllers, and non-traditional "controllers" like a tap on the screen, a spoken voice command or a button press on the device itself.
You can use one or all of these methods to allow your game or app to support a wider or narrower set of devices and input methods, or to allow more advanced interactions with more advanced devices.
</description>
<tutorials>
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 10c17aa672..2676b3cf80 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -163,9 +163,14 @@ String WebXRInterfaceJS::get_reference_space_type() const {
Ref<XRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const {
XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, nullptr);
+ ERR_FAIL_NULL_V(xr_server, Ref<XRPositionalTracker>());
- return xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
+ // TODO support more then two controllers
+ if (p_controller_id >= 0 && p_controller_id < 2) {
+ return controllers[p_controller_id];
+ };
+
+ return Ref<XRPositionalTracker>();
}
String WebXRInterfaceJS::get_visibility_state() const {
@@ -224,6 +229,13 @@ bool WebXRInterfaceJS::initialize() {
return false;
}
+ // we must create a tracker for our head
+ head_tracker.instantiate();
+ head_tracker->set_tracker_type(XRServer::TRACKER_HEAD);
+ head_tracker->set_tracker_name("head");
+ head_tracker->set_tracker_desc("Players head");
+ xr_server->add_tracker(head_tracker);
+
// make this our primary interface
xr_server->set_primary_interface(this);
@@ -254,9 +266,17 @@ bool WebXRInterfaceJS::initialize() {
void WebXRInterfaceJS::uninitialize() {
if (initialized) {
XRServer *xr_server = XRServer::get_singleton();
- if (xr_server != nullptr && xr_server->get_primary_interface() == this) {
- // no longer our primary interface
- xr_server->set_primary_interface(nullptr);
+ if (xr_server != nullptr) {
+ if (head_tracker.is_valid()) {
+ xr_server->remove_tracker(head_tracker);
+
+ head_tracker.unref();
+ }
+
+ if (xr_server->get_primary_interface() == this) {
+ // no longer our primary interface
+ xr_server->set_primary_interface(nullptr);
+ }
}
godot_webxr_uninitialize();
@@ -373,9 +393,9 @@ Vector<BlitToScreen> WebXRInterfaceJS::commit_views(RID p_render_target, const R
}
// @todo Refactor this to be based on "views" rather than "eyes".
- godot_webxr_commit_for_eye(XRInterface::EYE_LEFT);
+ godot_webxr_commit_for_eye(1);
if (godot_webxr_get_view_count() > 1) {
- godot_webxr_commit_for_eye(XRInterface::EYE_RIGHT);
+ godot_webxr_commit_for_eye(2);
}
return blit_to_screen;
@@ -385,6 +405,11 @@ void WebXRInterfaceJS::process() {
if (initialized) {
godot_webxr_sample_controller_data();
+ if (head_tracker.is_valid()) {
+ // TODO set default pose to our head location (i.e. get_camera_transform without world scale and reference frame applied)
+ // head_tracker->set_pose("default", head_transform, Vector3(), Vector3());
+ }
+
int controller_count = godot_webxr_get_controller_count();
if (controller_count == 0) {
return;
@@ -400,51 +425,70 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1);
+ // need to support more then two controllers...
+ if (p_controller_id < 0 || p_controller_id > 1) {
+ return;
+ }
+
+ Ref<XRPositionalTracker> tracker = controllers[p_controller_id];
if (godot_webxr_is_controller_connected(p_controller_id)) {
if (tracker.is_null()) {
tracker.instantiate();
tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
// Controller id's 0 and 1 are always the left and right hands.
if (p_controller_id < 2) {
- tracker->set_tracker_name(p_controller_id == 0 ? "Left" : "Right");
+ tracker->set_tracker_name(p_controller_id == 0 ? "left_hand" : "right_hand");
+ tracker->set_tracker_desc(p_controller_id == 0 ? "Left hand controller" : "Right hand controller");
tracker->set_tracker_hand(p_controller_id == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT);
+ } else {
+ char name[1024];
+ sprintf(name, "tracker_%i", p_controller_id);
+ tracker->set_tracker_name(name);
+ tracker->set_tracker_desc(name);
}
- // Use the ids we're giving to our "virtual" gamepads.
- tracker->set_joy_id(p_controller_id + 100);
xr_server->add_tracker(tracker);
}
- Input *input = Input::get_singleton();
-
float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id);
if (tracker_matrix) {
+ // Note, poses should NOT have world scale and our reference frame applied!
Transform3D transform = _js_matrix_to_transform(tracker_matrix);
- tracker->set_position(transform.origin);
- tracker->set_orientation(transform.basis);
+ tracker->set_pose("default", transform, Vector3(), Vector3());
free(tracker_matrix);
}
+ // TODO implement additional poses such as "aim" and "grip"
+
int *buttons = godot_webxr_get_controller_buttons(p_controller_id);
if (buttons) {
+ // TODO buttons should be named properly, this is just a temporary fix
for (int i = 0; i < buttons[0]; i++) {
- input->joy_button(p_controller_id + 100, (JoyButton)i, *((float *)buttons + (i + 1)));
+ char name[1024];
+ sprintf(name, "button_%i", i);
+
+ float value = *((float *)buttons + (i + 1));
+ bool state = value > 0.0;
+ tracker->set_input(name, state);
}
free(buttons);
}
int *axes = godot_webxr_get_controller_axes(p_controller_id);
if (axes) {
+ // TODO again just a temporary fix, split these between proper float and vector2 inputs
for (int i = 0; i < axes[0]; i++) {
- Input::JoyAxisValue joy_axis;
- joy_axis.min = -1;
- joy_axis.value = *((float *)axes + (i + 1));
- input->joy_axis(p_controller_id + 100, (JoyAxis)i, joy_axis);
+ char name[1024];
+ sprintf(name, "axis_%i", i);
+
+ float value = *((float *)axes + (i + 1));
+ ;
+ tracker->set_input(name, value);
}
free(axes);
}
} else if (tracker.is_valid()) {
xr_server->remove_tracker(tracker);
+ controllers[p_controller_id].unref();
}
}
@@ -454,7 +498,7 @@ void WebXRInterfaceJS::_on_controller_changed() {
for (int i = 0; i < 2; i++) {
bool controller_connected = godot_webxr_is_controller_connected(i);
if (controllers_state[i] != controller_connected) {
- Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", "");
+ // Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", "");
controllers_state[i] = controller_connected;
}
}
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index eb77f35f39..6e6548c946 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -46,6 +46,7 @@ class WebXRInterfaceJS : public WebXRInterface {
private:
bool initialized;
+ Ref<XRPositionalTracker> head_tracker;
String session_mode;
String required_features;
@@ -53,7 +54,9 @@ private:
String requested_reference_space_types;
String reference_space_type;
+ // TODO maybe turn into a vector to support more then 2 controllers...
bool controllers_state[2];
+ Ref<XRPositionalTracker> controllers[2];
Size2 render_targetsize;
Transform3D _js_matrix_to_transform(float *p_js_matrix);
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 8913ef1b65..58a6216b1e 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -114,7 +114,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
input_mesh.vertexPositionStride = sizeof(float) * 3;
input_mesh.vertexNormalData = p_normals;
input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
- input_mesh.vertexUvData = NULL;
+ input_mesh.vertexUvData = nullptr;
input_mesh.vertexUvStride = 0;
xatlas::ChartOptions chart_options;