diff options
Diffstat (limited to 'modules')
131 files changed, 1932 insertions, 2135 deletions
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 94b7e0ce38..81b832fb42 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(); @@ -190,22 +190,24 @@ void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) co } } -void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) { +void SoftBodyBullet::set_node_mass(int p_node_index, btScalar p_mass) { if (0 >= p_mass) { - pin_node(node_index); + pin_node(p_node_index); } else { - unpin_node(node_index); + unpin_node(p_node_index); } if (bt_soft_body) { - bt_soft_body->setMass(node_index, p_mass); + ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); + bt_soft_body->setMass(p_node_index, p_mass); } } -btScalar SoftBodyBullet::get_node_mass(int node_index) const { +btScalar SoftBodyBullet::get_node_mass(int p_node_index) const { if (bt_soft_body) { - return bt_soft_body->getMass(node_index); + ERR_FAIL_INDEX_V(p_node_index, bt_soft_body->m_nodes.size(), 1); + return bt_soft_body->getMass(p_node_index); } else { - return -1 == search_node_pinned(node_index) ? 1 : 0; + return -1 == search_node_pinned(p_node_index) ? 1 : 0; } } @@ -296,11 +298,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 @@ -418,17 +420,25 @@ void SoftBodyBullet::setup_soft_body() { // Set pinned nodes for (int i = pinned_nodes.size() - 1; 0 <= i; --i) { - bt_soft_body->setMass(pinned_nodes[i], 0); + const int node_index = pinned_nodes[i]; + ERR_CONTINUE(0 > node_index || bt_soft_body->m_nodes.size() <= node_index); + bt_soft_body->setMass(node_index, 0); } } void SoftBodyBullet::pin_node(int p_node_index) { + if (bt_soft_body) { + ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); + } if (-1 == search_node_pinned(p_node_index)) { pinned_nodes.push_back(p_node_index); } } void SoftBodyBullet::unpin_node(int p_node_index) { + if (bt_soft_body) { + ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size()); + } const int id = search_node_pinned(p_node_index); if (-1 != id) { pinned_nodes.remove(id); 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..14e7896295 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); diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml index 00469ab44c..fcdf282a7d 100644 --- a/modules/enet/doc_classes/ENetConnection.xml +++ b/modules/enet/doc_classes/ENetConnection.xml @@ -51,7 +51,7 @@ <argument index="3" name="data" type="int" default="0" /> <description> Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocting the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer. - Note: You must call either [method create_host] or [method create_host_bound] before calling this method. + [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method. </description> </method> <method name="create_host"> @@ -121,7 +121,7 @@ <return type="Array" /> <description> Returns the list of peers associated with this host. - Note: This list might include some peers that are not fully connected or are still being disconnected. + [b]Note:[/b] This list might include some peers that are not fully connected or are still being disconnected. </description> </method> <method name="pop_statistic"> @@ -136,7 +136,7 @@ <argument index="0" name="refuse" type="bool" /> <description> Configures the DTLS server to automatically drop new connections. - Note: This method is only relevant after calling [method dtls_server_setup]. + [b]Note:[/b] This method is only relevant after calling [method dtls_server_setup]. </description> </method> <method name="service"> diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index f9659c092a..22136c3944 100644 --- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -18,7 +18,7 @@ <argument index="1" name="host" type="ENetConnection" /> <description> Add a new remote peer with the given [code]peer_id[/code] connected to the given [code]host[/code]. - Note: The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state. + [b]Note:[/b] The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state. </description> </method> <method name="close_connection"> diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index dcea476275..e1eacc68b3 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -31,6 +31,7 @@ #include "fbx_mesh_data.h" #include "core/templates/local_vector.h" +#include "scene/resources/importer_mesh.h" #include "scene/resources/mesh.h" #include "scene/resources/surface_tool.h" @@ -101,7 +102,7 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash return collection; } -EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) { +ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) { mesh_geometry = p_mesh_geometry; // todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately. const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials(); @@ -344,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s } // Phase 6. Compose the mesh and return it. - Ref<EditorSceneImporterMesh> mesh; + Ref<ImporterMesh> mesh; mesh.instantiate(); // Add blend shape info. @@ -356,7 +357,6 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s 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); @@ -376,11 +376,9 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s } else { mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, mesh_array, blend_shapes); } - - in_mesh_surface_id += 1; } - EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D); + ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D); godot_mesh->set_mesh(mesh); const String name = ImportUtils::FBXNodeToName(model->Name()); godot_mesh->set_name(name); // hurry up compiling >.< diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index 24db4a5469..eec7f38cd6 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -35,7 +35,7 @@ #include "core/templates/local_vector.h" #include "core/templates/ordered_hash_map.h" #include "editor/import/resource_importer_scene.h" -#include "editor/import/scene_importer_mesh_node_3d.h" +#include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/resources/surface_tool.h" @@ -98,7 +98,7 @@ struct FBXMeshData : RefCounted { // translate fbx mesh data from document context to FBX Mesh Geometry Context bool valid_weight_indexes = false; - EditorSceneImporterMeshNode3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression); + ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression); void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const; @@ -107,7 +107,7 @@ struct FBXMeshData : RefCounted { int max_weight_count = 0; uint64_t armature_id = 0; bool valid_armature_id = false; - EditorSceneImporterMeshNode3D *godot_mesh_instance = nullptr; + ImporterMeshInstance3D *godot_mesh_instance = nullptr; private: void sanitize_vertex_weights(const ImportState &state); 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 e0663ab49d..9bdeafbf91 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -40,9 +40,9 @@ #include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/import/resource_importer_scene.h" -#include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/camera_3d.h" +#include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/light_3d.h" #include "scene/main/node.h" #include "scene/resources/material.h" @@ -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, @@ -627,7 +627,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( node_element; node_element = node_element->next()) { Ref<FBXNode> fbx_node = node_element->get(); - EditorSceneImporterMeshNode3D *mesh_node = nullptr; + ImporterMeshInstance3D *mesh_node = nullptr; Ref<FBXMeshData> mesh_data_precached; // check for valid geometry @@ -768,7 +768,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) { Ref<FBXMeshData> mesh = mesh_data.value; const uint64_t mesh_id = mesh_data.key; - EditorSceneImporterMeshNode3D *mesh_instance = mesh->godot_mesh_instance; + ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance; const int mesh_weights = mesh->max_weight_count; Ref<FBXSkeleton> skeleton; const bool valid_armature = mesh->valid_armature_id; @@ -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/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml index 3654870b09..6b3bd714b9 100644 --- a/modules/gdnative/doc_classes/GDNativeLibrary.xml +++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml @@ -7,8 +7,8 @@ A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as XRInterfaceGDNative. The library must be compiled for each platform and architecture that the project will run on. </description> <tutorials> - <link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link> - <link title="GDNative C++ example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link> + <link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/scripting/gdnative/gdnative_c_example.html</link> + <link title="GDNative C++ example">https://docs.godotengine.org/en/latest/tutorials/scripting/gdnative/gdnative_cpp_example.html</link> </tutorials> <methods> <method name="get_current_dependencies" qualifiers="const"> diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml index 9d34e89f02..221374a7a4 100644 --- a/modules/gdnative/doc_classes/NativeScript.xml +++ b/modules/gdnative/doc_classes/NativeScript.xml @@ -38,7 +38,7 @@ <return type="Variant" /> <description> Constructs a new object of the base type with a script of this type already attached. - [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. + [b]Note:[/b] Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension. </description> </method> </methods> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index d45202bd40..0a448ed88c 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -8,7 +8,7 @@ [method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. </description> <tutorials> - <link title="GDScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link> + <link title="GDScript documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/index.html</link> </tutorials> <methods> <method name="get_as_byte_code" qualifiers="const"> diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 2bae838543..e9d3749a8d 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()); } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index c35af9ca5b..cd8fd361c5 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -244,6 +244,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, class_type.kind = GDScriptParser::DataType::CLASS; class_type.class_type = p_class; class_type.script_path = parser->script_path; + class_type.builtin_type = Variant::OBJECT; p_class->set_datatype(class_type); if (!p_class->extends_used) { @@ -469,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); } } @@ -874,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.variable->getter); + } + if (member.variable->setter != nullptr) { + resolve_function_signature(member.variable->setter); - resolve_function_body(member.function); + 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); + } + } } } @@ -901,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); + } + } + } + } } } @@ -988,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: @@ -1035,7 +1117,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * return_type.is_meta_type = false; p_function->set_datatype(return_type); if (p_function->return_type) { - push_error("Constructor cannot have an explicit return type.", p_function->return_type); + GDScriptParser::DataType declared_return = resolve_datatype(p_function->return_type); + if (declared_return.kind != GDScriptParser::DataType::BUILTIN || declared_return.builtin_type != Variant::NIL) { + push_error("Constructor cannot have an explicit return type.", p_function->return_type); + } } } else { GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type); @@ -1198,7 +1283,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { variable_type.kind = GDScriptParser::DataType::BUILTIN; variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else? p_for->variable->set_datatype(variable_type); - } else { + } else if (p_for->list) { resolve_node(p_for->list); if (p_for->list->datatype.has_container_element_type()) { variable_type = p_for->list->datatype.get_container_element_type(); @@ -1213,7 +1298,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { variable_type.kind = GDScriptParser::DataType::VARIANT; } } - p_for->variable->set_datatype(variable_type); + if (p_for->variable) { + p_for->variable->set_datatype(variable_type); + } resolve_suite(p_for->loop); p_for->set_datatype(p_for->loop->get_datatype()); @@ -1523,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(); @@ -1540,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) { @@ -1591,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)); @@ -1707,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); @@ -1737,7 +1834,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig push_error("Cannot assign a new value to a constant.", p_assignment->assignee); } - if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) { + if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) { bool compatible = true; GDScriptParser::DataType op_type = assigned_value_type; if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { @@ -1789,27 +1886,24 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: { GDScriptParser::DataType id_type = identifier->parameter_source->get_datatype(); if (!id_type.is_hard_type()) { - id_type = assigned_value_type; - id_type.type_source = GDScriptParser::DataType::INFERRED; - id_type.is_constant = false; + id_type.kind = GDScriptParser::DataType::VARIANT; + id_type.type_source = GDScriptParser::DataType::UNDETECTED; identifier->parameter_source->set_datatype(id_type); } } break; case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: { GDScriptParser::DataType id_type = identifier->variable_source->get_datatype(); if (!id_type.is_hard_type()) { - id_type = assigned_value_type; - id_type.type_source = GDScriptParser::DataType::INFERRED; - id_type.is_constant = false; + id_type.kind = GDScriptParser::DataType::VARIANT; + id_type.type_source = GDScriptParser::DataType::UNDETECTED; identifier->variable_source->set_datatype(id_type); } } break; case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: { GDScriptParser::DataType id_type = identifier->bind_source->get_datatype(); if (!id_type.is_hard_type()) { - id_type = assigned_value_type; - id_type.type_source = GDScriptParser::DataType::INFERRED; - id_type.is_constant = false; + id_type.kind = GDScriptParser::DataType::VARIANT; + id_type.type_source = GDScriptParser::DataType::UNDETECTED; identifier->variable_source->set_datatype(id_type); } } break; @@ -1835,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); @@ -1964,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++) { @@ -2323,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); } @@ -2591,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; } @@ -2605,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)) { @@ -2936,7 +3047,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri } else { GDScriptParser::DataType base_type = p_subscript->base->get_datatype(); - if (base_type.is_variant()) { + if (base_type.is_variant() || !base_type.is_hard_type()) { result_type.kind = GDScriptParser::DataType::VARIANT; mark_node_unsafe(p_subscript); } else { @@ -3059,6 +3170,9 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri result_type.kind = GDScriptParser::DataType::BUILTIN; result_type.type_source = base_type.is_hard_type() ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED; + if (base_type.kind != GDScriptParser::DataType::BUILTIN) { + base_type.builtin_type = Variant::OBJECT; + } switch (base_type.builtin_type) { // Can't index at all. case Variant::RID: @@ -3119,6 +3233,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::PLANE: case Variant::COLOR: case Variant::DICTIONARY: + case Variant::OBJECT: result_type.kind = GDScriptParser::DataType::VARIANT; result_type.type_source = GDScriptParser::DataType::UNDETECTED; break; @@ -3133,7 +3248,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri } break; // Here for completeness. - case Variant::OBJECT: case Variant::VARIANT_MAX: break; } @@ -3300,7 +3414,13 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va current = current->_owner; } - Ref<GDScriptParserRef> ref = get_parser_for(current->path); + Ref<GDScriptParserRef> ref = get_parser_for(current->get_path()); + if (ref.is_null()) { + push_error("Could not find script in path.", p_source); + GDScriptParser::DataType error_type; + error_type.kind = GDScriptParser::DataType::VARIANT; + return error_type; + } ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED); GDScriptParser::ClassNode *found = ref->get_parser()->head; @@ -3380,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_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 8121053245..bb0d9e9e9b 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -58,27 +58,27 @@ Error GDScriptParserRef::raise_status(Status p_new_status) { while (p_new_status > status) { switch (status) { case EMPTY: - result = parser->parse(GDScriptCache::get_source_code(path), path, false); status = PARSED; + result = parser->parse(GDScriptCache::get_source_code(path), path, false); break; case PARSED: { analyzer = memnew(GDScriptAnalyzer(parser)); - Error inheritance_result = analyzer->resolve_inheritance(); status = INHERITANCE_SOLVED; + Error inheritance_result = analyzer->resolve_inheritance(); if (result == OK) { result = inheritance_result; } } break; case INHERITANCE_SOLVED: { - Error interface_result = analyzer->resolve_interface(); status = INTERFACE_SOLVED; + Error interface_result = analyzer->resolve_interface(); if (result == OK) { result = interface_result; } } break; case INTERFACE_SOLVED: { - Error body_result = analyzer->resolve_body(); status = FULLY_SOLVED; + Error body_result = analyzer->resolve_body(); if (result == OK) { result = body_result; } diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 2c02291795..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(); @@ -1019,25 +1024,32 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code } } else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) { // Assignment to member property. - GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value); + GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value); if (r_error) { return GDScriptCodeGenerator::Address(); } - GDScriptCodeGenerator::Address assign_temp = assigned; + + GDScriptCodeGenerator::Address to_assign = assigned_value; + bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE; StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name; - if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) { + if (has_operation) { + GDScriptCodeGenerator::Address op_result = codegen.add_temporary(); GDScriptCodeGenerator::Address member = codegen.add_temporary(); gen->write_get_member(member, name); - gen->write_binary_operator(assigned, assignment->variant_op, member, assigned); - gen->pop_temporary(); + gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value); + gen->pop_temporary(); // Pop member temp. + to_assign = op_result; } - gen->write_set_member(assigned, name); + gen->write_set_member(to_assign, name); - if (assign_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) { - gen->pop_temporary(); + if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); // Pop the assigned expression or the temp result if it has operation. + } + if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) { + gen->pop_temporary(); // Pop the assigned expression if not done before. } } else { // Regular assignment. @@ -2080,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"; + function = p_variable->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())); - } + _parse_function(error, p_script, p_class, function); - 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); - } -#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); - - 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 83805f626a..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) { @@ -2222,8 +2231,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c if (obj) { List<String> options; obj->get_argument_options(p_method, p_argidx, &options); - for (const String &F : options) { - ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION); + for (String &opt : options) { + if (opt.is_quoted()) { + opt = opt.unquote().quote(quote_style); // Handle user preference. + } + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION); r_result.insert(option.display, option); } } @@ -2322,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; @@ -2643,23 +2659,26 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c } } break; case GDScriptParser::COMPLETION_GET_NODE: { + // Handles the `$Node/Path` or `$"Some NodePath"` syntax specifically. if (p_owner) { List<String> opts; p_owner->get_argument_options("get_node", 0, &opts); for (const String &E : opts) { + r_forced = true; String opt = E.strip_edges(); if (opt.is_quoted()) { - r_forced = true; - String idopt = opt.unquote(); - if (idopt.replace("/", "_").is_valid_identifier()) { - ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH); - options.insert(option.display, option); - } else { - ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); - options.insert(option.display, option); - } + // Remove quotes so that we can handle user preferred quote style, + // or handle NodePaths which are valid identifiers and don't need quotes. + opt = opt.unquote(); + } + // The path needs quotes if it's not a valid identifier (with an exception + // for "/" as path separator, which also doesn't require quotes). + if (!opt.replace("/", "_").is_valid_identifier()) { + opt = opt.quote(quote_style); // Handle user preference. } + ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH); + options.insert(option.display, option); } // Get autoloads. diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 63817e970a..7ddb9b93b4 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); @@ -1620,6 +1657,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() { n_for->list = parse_expression(false); + if (!n_for->list) { + push_error(R"(Expected a list or range after "in".)"); + } + consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)"); // Save break/continue state. @@ -3419,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(); @@ -3486,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") { @@ -3496,7 +3537,7 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod } else if (mode == "unreliable_ordered") { rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED; } else { - push_error(R"(Invalid RPC argument. Must be one of: 'call_local'/'no_call_local' (local calls), 'any_peer'/'authority' (permission), 'reliable'/'unreliable'/'unreliable_ordered' (transfer mode).)", p_annotation); + push_error(R"(Invalid RPC argument. Must be one of: 'call_local'/'call_remote' (local calls), 'any_peer'/'authority' (permission), 'reliable'/'unreliable'/'unreliable_ordered' (transfer mode).)", p_annotation); } } } @@ -4433,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(" ="); @@ -4453,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..7018c339d7 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; 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/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index c383830c82..50c1f68440 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -133,13 +133,12 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l if (do_init_languages) { init_language(p_source_dir); - - // Enable all warnings for GDScript, so we can test them. - ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true); - for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { - String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); - ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true); - } + } + // Enable all warnings for GDScript, so we can test them. + ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true); + for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { + String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower(); + ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true); } // Enable printing to show results 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/auto_inferred_type_dont_error.out b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out index 0e9f482af4..481016138a 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out +++ b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out @@ -1,2 +1,6 @@ GDTEST_OK +>> WARNING +>> Line: 6 +>> UNSAFE_METHOD_ACCESS +>> The method 'free' is not present on the inferred type 'Variant' (but may be present on a subtype). Ok 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/class_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd new file mode 100644 index 0000000000..630b20c282 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd @@ -0,0 +1,11 @@ +# https://github.com/godotengine/godot/issues/43503 + +var test_var = null + + +func test(): + print(test_var.x) + + +func _init(): + test_var = Vector3() diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out new file mode 100644 index 0000000000..94e2ec2af8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out @@ -0,0 +1,2 @@ +GDTEST_OK +0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd new file mode 100644 index 0000000000..b3784dffa3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd @@ -0,0 +1,14 @@ +# https://github.com/godotengine/godot/issues/41064 +var x = true + +func test(): + var int_var: int = 0 + var dyn_var = 2 + + if x: + dyn_var = 5 + else: + dyn_var = Node.new() + + int_var = dyn_var + print(int_var) diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out new file mode 100644 index 0000000000..952029f665 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out @@ -0,0 +1,2 @@ +GDTEST_OK +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/subscript_self.gd b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd new file mode 100644 index 0000000000..f9a8b23b92 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd @@ -0,0 +1,8 @@ +# https://github.com/godotengine/godot/issues/43221 +extends Node + +func test(): + name = "Node" + print(self["name"]) + self["name"] = "Changed" + print(name) diff --git a/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out new file mode 100644 index 0000000000..6417f4f8da --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out @@ -0,0 +1,3 @@ +GDTEST_OK +Node +Changed 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/assign_member_with_operation.gd b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd new file mode 100644 index 0000000000..f6526aefb4 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd @@ -0,0 +1,13 @@ +extends Node + +func test(): + process_priority = 10 + var change = 20 + + print(process_priority) + print(change) + + process_priority += change + + print(process_priority) + print(change) diff --git a/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out new file mode 100644 index 0000000000..c9e6b34c77 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out @@ -0,0 +1,5 @@ +GDTEST_OK +10 +20 +30 +20 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..de269b92b3 --- /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(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/config.py b/modules/gltf/config.py index 52a97c93aa..a4736321fa 100644 --- a/modules/gltf/config.py +++ b/modules/gltf/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return env["tools"] and not env["disable_3d"] + return not env["disable_3d"] def configure(env): @@ -22,6 +22,8 @@ def get_doc_classes(): "GLTFSpecGloss", "GLTFState", "GLTFTexture", + "GLTFDocumentExtension", + "GLTFDocumentExtensionConvertImporterMesh", ] diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml index 16e649f390..8d8e25e8b3 100644 --- a/modules/gltf/doc_classes/GLTFDocument.xml +++ b/modules/gltf/doc_classes/GLTFDocument.xml @@ -30,4 +30,8 @@ </description> </method> </methods> + <members> + <member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[]"> + </member> + </members> </class> diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml new file mode 100644 index 0000000000..390bd3b30b --- /dev/null +++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="GLTFDocumentExtension" inherits="Resource" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="export_post"> + <return type="int" enum="Error" /> + <argument index="0" name="document" type="GLTFDocument" /> + <description> + </description> + </method> + <method name="export_preflight"> + <return type="int" enum="Error" /> + <argument index="0" name="document" type="GLTFDocument" /> + <argument index="1" name="node" type="Node" /> + <description> + </description> + </method> + <method name="get_export_setting" qualifiers="const"> + <return type="Variant" /> + <argument index="0" name="key" type="StringName" /> + <description> + </description> + </method> + <method name="get_export_setting_keys" qualifiers="const"> + <return type="Array" /> + <description> + </description> + </method> + <method name="get_import_setting" qualifiers="const"> + <return type="Variant" /> + <argument index="0" name="key" type="StringName" /> + <description> + </description> + </method> + <method name="get_import_setting_keys" qualifiers="const"> + <return type="Array" /> + <description> + </description> + </method> + <method name="import_post"> + <return type="int" enum="Error" /> + <argument index="0" name="document" type="GLTFDocument" /> + <argument index="1" name="node" type="Node" /> + <description> + </description> + </method> + <method name="import_preflight"> + <return type="int" enum="Error" /> + <argument index="0" name="document" type="GLTFDocument" /> + <description> + </description> + </method> + <method name="set_export_setting"> + <return type="void" /> + <argument index="0" name="key" type="StringName" /> + <argument index="1" name="value" type="Variant" /> + <description> + </description> + </method> + <method name="set_import_setting"> + <return type="void" /> + <argument index="0" name="key" type="StringName" /> + <argument index="1" name="value" type="Variant" /> + <description> + </description> + </method> + </methods> +</class> diff --git a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml index c85fce7b9d..452eec5f4f 100644 --- a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml +++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorSceneImporterGLTF" inherits="EditorSceneImporter" version="4.0"> +<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0"> <brief_description> </brief_description> <description> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index 51e9fc032a..1e7199d229 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -9,7 +9,7 @@ <members> <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()"> </member> - <member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh"> + <member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh"> </member> </members> </class> diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp index 3ce5ea23dc..25fda7ef3b 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#if TOOLS_ENABLED #include "editor_scene_exporter_gltf_plugin.h" #include "core/config/project_settings.h" #include "core/error/error_list.h" @@ -93,3 +94,5 @@ void SceneExporterGLTFPlugin::convert_scene_to_gltf2() { file_export_lib->set_current_file(filename + String(".gltf")); file_export_lib->popup_centered_ratio(); } + +#endif // TOOLS_ENABLED diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor_scene_exporter_gltf_plugin.h index c4f277fca2..89a8e27053 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.h +++ b/modules/gltf/editor_scene_exporter_gltf_plugin.h @@ -31,7 +31,9 @@ #ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H #define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H +#if TOOLS_ENABLED #include "editor/editor_plugin.h" + #include "editor_scene_importer_gltf.h" class SceneExporterGLTFPlugin : public EditorPlugin { @@ -47,5 +49,5 @@ public: bool has_main_screen() const override; SceneExporterGLTFPlugin(class EditorNode *p_node); }; - +#endif // TOOLS_ENABLED #endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index 12796c41d7..1a172877a0 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -28,6 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#if TOOLS_ENABLED #include "editor_scene_importer_gltf.h" #include "gltf_document.h" @@ -37,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) { @@ -55,8 +56,10 @@ 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>(); } + +#endif // TOOLS_ENABLED diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index eb8775b137..28963adc28 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -30,18 +30,19 @@ #ifndef EDITOR_SCENE_IMPORTER_GLTF_H #define EDITOR_SCENE_IMPORTER_GLTF_H - +#ifdef TOOLS_ENABLED #include "gltf_state.h" +#include "gltf_document_extension.h" + #include "editor/import/resource_importer_scene.h" #include "scene/main/node.h" #include "scene/resources/packed_scene.h" class Animation; -#ifdef TOOLS_ENABLED -class EditorSceneImporterGLTF : public EditorSceneImporter { - GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter); +class EditorSceneFormatImporterGLTF : public EditorSceneFormatImporter { + GDCLASS(EditorSceneFormatImporterGLTF, EditorSceneFormatImporter); public: virtual uint32_t get_import_flags() const override; @@ -50,5 +51,5 @@ public: virtual Ref<Animation> import_animation(const String &p_path, uint32_t p_flags, int p_bake_fps) override; }; -#endif +#endif // TOOLS_ENABLED #endif // EDITOR_SCENE_IMPORTER_GLTF_H diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp index daeb084916..85cec3fec4 100644 --- a/modules/gltf/gltf_accessor.cpp +++ b/modules/gltf/gltf_accessor.cpp @@ -30,6 +30,8 @@ #include "gltf_accessor.h" +#include "gltf_document_extension.h" + void GLTFAccessor::_bind_methods() { ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view); ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view); diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h index 57aea1026c..bec511f974 100644 --- a/modules/gltf/gltf_accessor.h +++ b/modules/gltf/gltf_accessor.h @@ -32,7 +32,9 @@ #define GLTF_ACCESSOR_H #include "core/io/resource.h" + #include "gltf_document.h" +#include "gltf_document_extension.h" struct GLTFAccessor : public Resource { GDCLASS(GLTFAccessor, Resource); diff --git a/modules/gltf/gltf_buffer_view.cpp b/modules/gltf/gltf_buffer_view.cpp index ba38a11c4c..d00e0f040f 100644 --- a/modules/gltf/gltf_buffer_view.cpp +++ b/modules/gltf/gltf_buffer_view.cpp @@ -30,6 +30,8 @@ #include "gltf_buffer_view.h" +#include "gltf_document_extension.h" + void GLTFBufferView::_bind_methods() { ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer); ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer); diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index 3f1f218e78..7d4bd998f5 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -33,6 +33,8 @@ #include "gltf_accessor.h" #include "gltf_animation.h" #include "gltf_camera.h" +#include "gltf_document_extension.h" +#include "gltf_document_extension_convert_importer_mesh.h" #include "gltf_light.h" #include "gltf_mesh.h" #include "gltf_node.h" @@ -49,6 +51,7 @@ #include "core/io/json.h" #include "core/math/disjoint_set.h" #include "core/math/vector2.h" +#include "core/variant/dictionary.h" #include "core/variant/typed_array.h" #include "core/variant/variant.h" #include "core/version.h" @@ -57,8 +60,12 @@ #include "editor/import/resource_importer_scene.h" #include "scene/2d/node_2d.h" #include "scene/3d/camera_3d.h" +#include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" #include "scene/animation/animation_player.h" +#include "scene/resources/importer_mesh.h" +#include "scene/resources/mesh.h" +#include "scene/resources/multimesh.h" #include "scene/resources/surface_tool.h" #include "modules/modules_enabled.gen.h" @@ -2101,7 +2108,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { Array meshes; for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) { print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i)); - Ref<EditorSceneImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh(); + Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh(); if (import_mesh.is_null()) { continue; } @@ -2493,7 +2500,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Array primitives = d["primitives"]; const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary(); - Ref<EditorSceneImporterMesh> import_mesh; + Ref<ImporterMesh> import_mesh; import_mesh.instantiate(); String mesh_name = "mesh"; if (d.has("name") && !String(d["name"]).is_empty()) { @@ -2732,17 +2739,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL")); + Ref<SurfaceTool> mesh_surface_tool; + mesh_surface_tool.instantiate(); + mesh_surface_tool->create_from_triangle_arrays(array); + if (a.has("JOINTS_0") && a.has("JOINTS_1")) { + mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); + } + mesh_surface_tool->index(); if (generate_tangents) { //must generate mikktspace tangents.. ergh.. - Ref<SurfaceTool> st; - st.instantiate(); - st->create_from_triangle_arrays(array); - if (a.has("JOINTS_0") && a.has("JOINTS_1")) { - st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); - } - st->generate_tangents(); - array = st->commit_to_arrays(); + mesh_surface_tool->generate_tangents(); } + array = mesh_surface_tool->commit_to_arrays(); Array morphs; //blend shapes @@ -2772,8 +2780,6 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { array_copy[l] = array[l]; } - array_copy[Mesh::ARRAY_INDEX] = Variant(); - if (t.has("POSITION")) { Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true); const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX]; @@ -2852,17 +2858,17 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { array_copy[Mesh::ARRAY_TANGENT] = tangents_v4; } + Ref<SurfaceTool> blend_surface_tool; + blend_surface_tool.instantiate(); + blend_surface_tool->create_from_triangle_arrays(array_copy); + if (a.has("JOINTS_0") && a.has("JOINTS_1")) { + blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); + } + blend_surface_tool->index(); if (generate_tangents) { - Ref<SurfaceTool> st; - st.instantiate(); - st->create_from_triangle_arrays(array_copy); - if (a.has("JOINTS_0") && a.has("JOINTS_1")) { - st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); - } - st->deindex(); - st->generate_tangents(); - array_copy = st->commit_to_arrays(); + blend_surface_tool->generate_tangents(); } + array_copy = blend_surface_tool->commit_to_arrays(); morphs.push_back(array_copy); } @@ -2875,19 +2881,23 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { const int material = p["material"]; ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT); Ref<BaseMaterial3D> mat3d = state->materials[material]; + ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT); if (has_vertex_color) { mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); } mat = mat3d; - } else if (has_vertex_color) { + } else { Ref<StandardMaterial3D> mat3d; mat3d.instantiate(); - mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + if (has_vertex_color) { + mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } mat = mat3d; } - - import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat.is_valid() ? mat->get_name() : String(), flags); + ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT); + import_mesh->add_surface(primitive, array, morphs, + Dictionary(), mat, mat->get_name(), flags); } Vector<float> blend_weights; @@ -3610,7 +3620,6 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { material->set_cull_mode(BaseMaterial3D::CULL_DISABLED); } } - if (d.has("alphaMode")) { const String &am = d["alphaMode"]; if (am == "BLEND") { @@ -4310,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()); @@ -5007,72 +5019,65 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst if (p_mesh_instance->get_mesh().is_null()) { return -1; } - Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instantiate(); - Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh(); - if (godot_mesh.is_null()) { - return -1; - } + Ref<ImporterMesh> current_mesh; + current_mesh.instantiate(); Vector<float> blend_weights; - Vector<String> blend_names; - int32_t blend_count = godot_mesh->get_blend_shape_count(); - blend_names.resize(blend_count); - blend_weights.resize(blend_count); - for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) { - String blend_name = godot_mesh->get_blend_shape_name(blend_i); - blend_names.write[blend_i] = blend_name; - import_mesh->add_blend_shape(blend_name); - } - for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) { - Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i); - Array arrays = godot_mesh->surface_get_arrays(surface_i); - Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i); - Ref<Material> mat = godot_mesh->surface_get_material(surface_i); - Ref<ArrayMesh> godot_array_mesh = godot_mesh; - String surface_name; - if (godot_array_mesh.is_valid()) { - surface_name = godot_array_mesh->surface_get_name(surface_i); - } - if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) { - mat = p_mesh_instance->get_surface_override_material(surface_i); - } - if (p_mesh_instance->get_material_override().is_valid()) { - mat = p_mesh_instance->get_material_override(); - } - import_mesh->add_surface(primitive_type, arrays, blend_shape_arrays, Dictionary(), mat, surface_name, godot_mesh->surface_get_format(surface_i)); - } - for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { - blend_weights.write[blend_i] = 0.0f; + { + Ref<Mesh> import_mesh = p_mesh_instance->get_mesh(); + Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh(); + if (import_mesh->get_blend_shape_count()) { + ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED; + if (import_array_mesh.is_valid()) { + shape_mode = import_array_mesh->get_blend_shape_mode(); + } + current_mesh->set_blend_shape_mode(shape_mode); + for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) { + current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i)); + } + } + for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) { + Array array = import_mesh->surface_get_arrays(surface_i); + Ref<Material> mat = import_mesh->surface_get_material(surface_i); + String mat_name; + if (mat.is_valid()) { + mat_name = mat->get_name(); + } + current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i), + array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat, + mat_name, import_mesh->surface_get_format(surface_i)); + } + int32_t blend_count = import_mesh->get_blend_shape_count(); + blend_weights.resize(blend_count); + for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) { + blend_weights.write[blend_i] = 0.0f; + } } Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - gltf_mesh->set_mesh(import_mesh); + gltf_mesh->set_mesh(current_mesh); gltf_mesh->set_blend_weights(blend_weights); GLTFMeshIndex mesh_i = state->meshes.size(); state->meshes.push_back(gltf_mesh); return mesh_i; } -EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) { +ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) { Ref<GLTFNode> gltf_node = state->nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr); - EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D); + ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); print_verbose("glTF: Creating mesh for: " + gltf_node->get_name()); Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh]; if (mesh.is_null()) { return mi; } - Ref<EditorSceneImporterMesh> import_mesh = mesh->get_mesh(); + Ref<ImporterMesh> import_mesh = mesh->get_mesh(); if (import_mesh.is_null()) { return mi; } mi->set_mesh(import_mesh); - for (int i = 0; i < mesh->get_blend_weights().size(); i++) { - mi->set("blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i), mesh->get_blend_weights()[i]); - } return mi; } @@ -5241,7 +5246,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co return; } else if (cast_to<MultiMeshInstance3D>(p_current)) { MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current); - _convert_mult_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state); + _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state); #ifdef MODULE_CSG_ENABLED } else if (cast_to<CSGShape3D>(p_current)) { CSGShape3D *shape = cast_to<CSGShape3D>(p_current); @@ -5292,13 +5297,8 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd } Ref<GLTFMesh> gltf_mesh; gltf_mesh.instantiate(); - Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instantiate(); - Ref<ArrayMesh> array_mesh = csg->get_meshes()[1]; - for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) { - import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i)); - } - gltf_mesh->set_mesh(import_mesh); + Ref<ImporterMesh> array_mesh = csg->get_meshes()[1]; + gltf_mesh->set_mesh(array_mesh); GLTFMeshIndex mesh_i = state->meshes.size(); state->meshes.push_back(gltf_mesh); gltf_node->mesh = mesh_i; @@ -5364,7 +5364,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex Vector3 cell_location = cells[k]; int32_t cell = p_grid_map->get_cell_item( Vector3(cell_location.x, cell_location.y, cell_location.z)); - EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D); + ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D); import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell)); Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( @@ -5386,50 +5386,73 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex } #endif // MODULE_GRIDMAP_ENABLED -void GLTFDocument::_convert_mult_mesh_instance_to_gltf(MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) { +void GLTFDocument::_convert_multi_mesh_instance_to_gltf( + MultiMeshInstance3D *p_multi_mesh_instance, + GLTFNodeIndex p_parent_node_index, + GLTFNodeIndex p_root_node_index, + Ref<GLTFNode> gltf_node, Ref<GLTFState> state) { + ERR_FAIL_COND(!p_multi_mesh_instance); Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh(); - if (multi_mesh.is_valid()) { - for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); - instance_i++) { - GLTFNode *new_gltf_node = memnew(GLTFNode); - Transform3D transform; - if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) { - Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i); - transform.origin = - Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y); - real_t rotation = xform_2d.get_rotation(); - Quaternion quaternion(Vector3(0, 1, 0), rotation); - Size2 scale = xform_2d.get_scale(); - transform.basis.set_quaternion_scale(quaternion, - Vector3(scale.x, 0, scale.y)); - transform = - p_multi_mesh_instance->get_transform() * transform; - } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) { - transform = p_multi_mesh_instance->get_transform() * - multi_mesh->get_instance_transform(instance_i); - } - Ref<ArrayMesh> mm = multi_mesh->get_mesh(); - if (mm.is_valid()) { - Ref<EditorSceneImporterMesh> mesh; - mesh.instantiate(); - for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) { - Array surface = mm->surface_get_arrays(surface_i); - mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(), - mm->surface_get_material(surface_i), mm->get_name()); - } - Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instantiate(); - gltf_mesh->set_name(multi_mesh->get_name()); - gltf_mesh->set_mesh(mesh); - new_gltf_node->mesh = state->meshes.size(); - state->meshes.push_back(gltf_mesh); - } - new_gltf_node->xform = transform; - new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name())); - gltf_node->children.push_back(state->nodes.size()); - state->nodes.push_back(new_gltf_node); + if (multi_mesh.is_null()) { + return; + } + Ref<GLTFMesh> gltf_mesh; + gltf_mesh.instantiate(); + Ref<Mesh> mesh = multi_mesh->get_mesh(); + if (mesh.is_null()) { + return; + } + gltf_mesh->set_name(multi_mesh->get_name()); + Ref<ImporterMesh> importer_mesh; + importer_mesh.instantiate(); + Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh(); + if (array_mesh.is_valid()) { + importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode()); + for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) { + importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i)); } } + for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) { + Ref<Material> mat = mesh->surface_get_material(surface_i); + String material_name; + if (mat.is_valid()) { + material_name = mat->get_name(); + } + Array blend_arrays; + if (array_mesh.is_valid()) { + blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i); + } + importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i), + blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i)); + } + gltf_mesh->set_mesh(importer_mesh); + GLTFMeshIndex mesh_index = state->meshes.size(); + state->meshes.push_back(gltf_mesh); + for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); + instance_i++) { + Transform3D transform; + if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) { + Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i); + transform.origin = + Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y); + real_t rotation = xform_2d.get_rotation(); + Quaternion quaternion(Vector3(0, 1, 0), rotation); + Size2 scale = xform_2d.get_scale(); + transform.basis.set_quaternion_scale(quaternion, + Vector3(scale.x, 0, scale.y)); + transform = p_multi_mesh_instance->get_transform() * transform; + } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) { + transform = p_multi_mesh_instance->get_transform() * + multi_mesh->get_instance_transform(instance_i); + } + Ref<GLTFNode> new_gltf_node; + new_gltf_node.instantiate(); + new_gltf_node->mesh = mesh_index; + new_gltf_node->xform = transform; + new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name())); + gltf_node->children.push_back(state->nodes.size()); + state->nodes.push_back(new_gltf_node); + } } void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) { @@ -5450,7 +5473,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; @@ -5661,7 +5684,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; } @@ -5687,7 +5710,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."); @@ -5713,7 +5736,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]; } @@ -5726,7 +5749,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: { @@ -5848,9 +5871,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; @@ -5860,15 +5941,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; } @@ -5878,35 +5959,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; } @@ -5924,12 +5991,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, @@ -5940,7 +6006,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. @@ -5948,7 +6014,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; } @@ -6022,7 +6089,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; @@ -6106,8 +6173,8 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i); ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i)); - EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get()); - ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", node_i, mi_element->get()->get_class_name())); + ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->get()); + ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->get()->get_class_name())); const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton; Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i]; @@ -6125,7 +6192,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; @@ -6144,33 +6211,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; @@ -6262,13 +6331,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; } @@ -6291,19 +6357,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; } @@ -6330,7 +6392,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); } } @@ -6346,7 +6408,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); } } @@ -6362,7 +6424,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); } } @@ -6373,7 +6435,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); } } @@ -6397,7 +6459,7 @@ 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; + NodePath shape_path = String(path) + ":" + shape_name; int32_t shape_track_i = animation->find_track(shape_path); if (shape_track_i == -1) { GLTFAnimation::Channel<float> weight; @@ -6450,7 +6512,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; } @@ -6460,27 +6521,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; } } } @@ -6748,10 +6806,25 @@ Error GLTFDocument::save_scene(Node *p_node, const String &p_path, Ref<GLTFDocument> gltf_document; gltf_document.instantiate(); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Error err = ext->export_preflight(this, p_node); + ERR_FAIL_COND_V(err != OK, err); + } + if (r_state == Ref<GLTFState>()) { r_state.instantiate(); } - return gltf_document->serialize(r_state, p_node, p_path); + Error err = gltf_document->serialize(r_state, p_node, p_path); + ERR_FAIL_COND_V(err != OK, err); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->export_post(this); + ERR_FAIL_COND_V(err != OK, err); + } + return OK; } Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) { @@ -6760,10 +6833,19 @@ 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(); + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + Error err = ext->import_preflight(this); + if (r_err) { + *r_err = err; + } + ERR_FAIL_COND_V(err != OK, nullptr); + } Error err = gltf_document->parse(r_state, p_path); if (r_err) { *r_err = err; @@ -6783,7 +6865,15 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in gltf_document->_import_animation(r_state, ap, i, p_bake_fps); } } - + for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) { + Ref<GLTFDocumentExtension> ext = document_extensions[ext_i]; + ERR_CONTINUE(ext.is_null()); + err = ext->import_post(this, root); + if (r_err) { + *r_err = err; + } + ERR_FAIL_COND_V(err != OK, nullptr); + } return root; } @@ -6792,6 +6882,14 @@ void GLTFDocument::_bind_methods() { &GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"), &GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>())); + ClassDB::bind_method(D_METHOD("set_extensions", "extensions"), + &GLTFDocument::set_extensions); + ClassDB::bind_method(D_METHOD("get_extensions"), + &GLTFDocument::get_extensions); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE, + vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"), + PROPERTY_USAGE_DEFAULT), + "set_extensions", "get_extensions"); } void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) { @@ -6817,3 +6915,21 @@ Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t } return node; } + +void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) { + document_extensions = p_extensions; +} + +TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const { + return document_extensions; +} + +GLTFDocument::GLTFDocument() { + bool is_editor = ::Engine::get_singleton()->is_editor_hint(); + if (is_editor) { + return; + } + Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor; + extension_editor.instantiate(); + document_extensions.push_back(extension_editor); +} diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 18aeb81bc0..a1d82a4649 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -33,8 +33,11 @@ #include "gltf_animation.h" -#include "editor/import/scene_importer_mesh_node_3d.h" +#include "core/variant/dictionary.h" +#include "core/variant/variant.h" +#include "gltf_document_extension_convert_importer_mesh.h" #include "scene/3d/bone_attachment_3d.h" +#include "scene/3d/importer_mesh_instance_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/node_3d.h" @@ -54,6 +57,7 @@ class GLTFSkeleton; class CSGShape3D; class GridMap; class MultiMeshInstance3D; +class GLTFDocumentExtension; using GLTFAccessorIndex = int; using GLTFAnimationIndex = int; @@ -74,11 +78,13 @@ class GLTFDocument : public Resource { friend class GLTFState; friend class GLTFSkin; friend class GLTFSkeleton; + TypedArray<GLTFDocumentExtension> document_extensions; private: const float BAKE_FPS = 30.0f; public: + GLTFDocument(); const int32_t JOINT_GROUP_SIZE = 4; enum GLTFType { TYPE_SCALAR, @@ -118,6 +124,8 @@ public: Error save_scene(Node *p_node, const String &p_path, const String &p_src_path, uint32_t p_flags, float p_bake_fps, Ref<GLTFState> r_state); + void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions); + TypedArray<GLTFDocumentExtension> get_extensions() const; private: template <class T> @@ -280,12 +288,10 @@ private: Skeleton3D *skeleton, const GLTFNodeIndex node_index, const GLTFNodeIndex bone_index); - EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index); - Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent, - const GLTFNodeIndex node_index); - Node3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index); - Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent, - const GLTFNodeIndex node_index); + ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); + Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); + Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); + Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index); void _assign_scene_names(Ref<GLTFState> state); template <class T> T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, @@ -351,7 +357,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); @@ -420,8 +426,8 @@ public: GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state); #endif // MODULE_GRIDMAP_ENABLED - void _convert_mult_mesh_instance_to_gltf( - MultiMeshInstance3D *p_scene_parent, + void _convert_multi_mesh_instance_to_gltf( + MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state); diff --git a/modules/webm/register_types.h b/modules/gltf/gltf_document_extension.cpp index d090fe745b..a423059a9c 100644 --- a/modules/webm/register_types.h +++ b/modules/gltf/gltf_document_extension.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.h */ +/* gltf_document_extension.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,61 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef WEBM_REGISTER_TYPES_H -#define WEBM_REGISTER_TYPES_H +#include "gltf_document_extension.h" -void register_webm_types(); -void unregister_webm_types(); +#include "gltf_document.h" -#endif // WEBM_REGISTER_TYPES_H +void GLTFDocumentExtension::_bind_methods() { + // Import + ClassDB::bind_method(D_METHOD("get_import_setting_keys"), + &GLTFDocumentExtension::get_import_setting_keys); + ClassDB::bind_method(D_METHOD("import_preflight", "document"), + &GLTFDocumentExtension::import_preflight); + ClassDB::bind_method(D_METHOD("get_import_setting", "key"), + &GLTFDocumentExtension::get_import_setting); + ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"), + &GLTFDocumentExtension::set_import_setting); + ClassDB::bind_method(D_METHOD("import_post", "document", "node"), + &GLTFDocumentExtension::import_post); + // Export + ClassDB::bind_method(D_METHOD("get_export_setting_keys"), + &GLTFDocumentExtension::get_export_setting_keys); + ClassDB::bind_method(D_METHOD("get_export_setting", "key"), + &GLTFDocumentExtension::get_export_setting); + ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"), + &GLTFDocumentExtension::set_export_setting); + ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"), + &GLTFDocumentExtension::export_preflight); + ClassDB::bind_method(D_METHOD("export_post", "document"), + &GLTFDocumentExtension::export_post); +} + +Array GLTFDocumentExtension::get_import_setting_keys() const { + return import_settings.keys(); +} + +Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const { + if (!import_settings.has(p_key)) { + return Variant(); + } + return import_settings[p_key]; +} + +void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) { + import_settings[p_key] = p_var; +} + +Array GLTFDocumentExtension::get_export_setting_keys() const { + return import_settings.keys(); +} + +Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const { + if (!import_settings.has(p_key)) { + return Variant(); + } + return import_settings[p_key]; +} + +void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) { + import_settings[p_key] = p_var; +} diff --git a/modules/opus/register_types.cpp b/modules/gltf/gltf_document_extension.h index 02874a9a4b..622a65708c 100644 --- a/modules/opus/register_types.cpp +++ b/modules/gltf/gltf_document_extension.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.cpp */ +/* gltf_document_extension.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,36 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "register_types.h" +#ifndef GLTF_DOCUMENT_EXTENSION_H +#define GLTF_DOCUMENT_EXTENSION_H -// Dummy module as libvorbis is needed by other modules (theora ...) +#include "core/io/resource.h" +#include "core/variant/dictionary.h" +#include "core/variant/typed_array.h" +#include "core/variant/variant.h" +class GLTFDocument; +class GLTFDocumentExtension : public Resource { + GDCLASS(GLTFDocumentExtension, Resource); -void register_opus_types() {} + Dictionary import_settings; + Dictionary export_settings; -void unregister_opus_types() {} +protected: + static void _bind_methods(); + +public: + virtual Array get_import_setting_keys() const; + virtual Variant get_import_setting(const StringName &p_key) const; + virtual void set_import_setting(const StringName &p_key, Variant p_var); + virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; } + virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; } + +public: + virtual Array get_export_setting_keys() const; + virtual Variant get_export_setting(const StringName &p_key) const; + virtual void set_export_setting(const StringName &p_key, Variant p_var); + virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; } + virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; } +}; + +#endif // GLTF_DOCUMENT_EXTENSION_H diff --git a/modules/opus/register_types.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp index af889cf809..78a98dfa3e 100644 --- a/modules/opus/register_types.h +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.h */ +/* gltf_document_extension_convert_importer_mesh.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,52 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef OPUS_REGISTER_TYPES_H -#define OPUS_REGISTER_TYPES_H +#include "gltf_document_extension_convert_importer_mesh.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/resources/importer_mesh.h" -void register_opus_types(); -void unregister_opus_types(); +#include <cstddef> -#endif // OPUS_REGISTER_TYPES_H +void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() { +} + +Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) { + List<Node *> queue; + queue.push_back(p_node); + List<Node *> delete_queue; + while (!queue.is_empty()) { + List<Node *>::Element *E = queue.front(); + Node *node = E->get(); + { + ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node); + if (mesh_3d) { + MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D); + Ref<ImporterMesh> mesh = mesh_3d->get_mesh(); + if (mesh.is_valid()) { + Ref<ArrayMesh> array_mesh = mesh->get_mesh(); + mesh_instance_node_3d->set_name(node->get_name()); + mesh_instance_node_3d->set_transform(mesh_3d->get_transform()); + mesh_instance_node_3d->set_mesh(array_mesh); + mesh_instance_node_3d->set_skin(mesh_3d->get_skin()); + mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path()); + node->replace_by(mesh_instance_node_3d); + delete_queue.push_back(node); + } else { + memdelete(mesh_instance_node_3d); + } + } + } + int child_count = node->get_child_count(); + for (int i = 0; i < child_count; i++) { + queue.push_back(node->get_child(i)); + } + queue.pop_front(); + } + while (!queue.is_empty()) { + List<Node *>::Element *E = delete_queue.front(); + Node *node = E->get(); + memdelete(node); + delete_queue.pop_front(); + } + return OK; +} diff --git a/modules/webm/register_types.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.h index 8f690a6892..85ddb4d250 100644 --- a/modules/webm/register_types.cpp +++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.cpp */ +/* gltf_document_extension_convert_importer_mesh.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "register_types.h" +#ifndef GLTF_EXTENSION_EDITOR_H +#define GLTF_EXTENSION_EDITOR_H -#include "video_stream_webm.h" +#include "core/io/resource.h" +#include "core/variant/dictionary.h" -static Ref<ResourceFormatLoaderWebm> resource_loader_webm; +#include "gltf_document.h" +#include "gltf_document_extension.h" +#include "scene/3d/importer_mesh_instance_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/main/node.h" +#include "scene/resources/importer_mesh.h" -void register_webm_types() { - resource_loader_webm.instantiate(); - ResourceLoader::add_resource_format_loader(resource_loader_webm, true); +class GLTFDocumentExtension; +class GLTFDocument; +class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension { + GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension); - GDREGISTER_CLASS(VideoStreamWebm); -} +protected: + static void _bind_methods(); -void unregister_webm_types() { - ResourceLoader::remove_resource_format_loader(resource_loader_webm); - resource_loader_webm.unref(); -} +public: + Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override; +}; +#endif // GLTF_EXTENSION_EDITOR_H diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp index 8c10e42c89..747820521a 100644 --- a/modules/gltf/gltf_mesh.cpp +++ b/modules/gltf/gltf_mesh.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "gltf_mesh.h" -#include "editor/import/scene_importer_mesh.h" +#include "scene/resources/importer_mesh.h" void GLTFMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFMesh::get_mesh); @@ -41,11 +41,11 @@ void GLTFMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float> } -Ref<EditorSceneImporterMesh> GLTFMesh::get_mesh() { +Ref<ImporterMesh> GLTFMesh::get_mesh() { return mesh; } -void GLTFMesh::set_mesh(Ref<EditorSceneImporterMesh> p_mesh) { +void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) { mesh = p_mesh; } diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h index 0fc750fc9f..3aba0ede32 100644 --- a/modules/gltf/gltf_mesh.h +++ b/modules/gltf/gltf_mesh.h @@ -33,22 +33,23 @@ #include "core/io/resource.h" #include "editor/import/resource_importer_scene.h" -#include "editor/import/scene_importer_mesh.h" +#include "scene/3d/importer_mesh_instance_3d.h" +#include "scene/resources/importer_mesh.h" #include "scene/resources/mesh.h" class GLTFMesh : public Resource { GDCLASS(GLTFMesh, Resource); private: - Ref<EditorSceneImporterMesh> mesh; + Ref<ImporterMesh> mesh; Vector<float> blend_weights; protected: static void _bind_methods(); public: - Ref<EditorSceneImporterMesh> get_mesh(); - void set_mesh(Ref<EditorSceneImporterMesh> p_mesh); + Ref<ImporterMesh> get_mesh(); + void set_mesh(Ref<ImporterMesh> p_mesh); Vector<float> get_blend_weights(); void set_blend_weights(Vector<float> p_blend_weights); }; diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h index d6614da804..61faba0dc5 100644 --- a/modules/gltf/gltf_state.h +++ b/modules/gltf/gltf_state.h @@ -36,6 +36,7 @@ #include "gltf_buffer_view.h" #include "gltf_camera.h" #include "gltf_document.h" +#include "gltf_document_extension.h" #include "gltf_light.h" #include "gltf_mesh.h" #include "gltf_node.h" diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index d6020f50f0..5a60c2d328 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -38,6 +38,8 @@ #include "gltf_buffer_view.h" #include "gltf_camera.h" #include "gltf_document.h" +#include "gltf_document_extension.h" +#include "gltf_document_extension_convert_importer_mesh.h" #include "gltf_light.h" #include "gltf_mesh.h" #include "gltf_node.h" @@ -50,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); } @@ -62,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); @@ -79,6 +81,8 @@ void register_gltf_types() { GDREGISTER_CLASS(GLTFCamera); GDREGISTER_CLASS(GLTFLight); GDREGISTER_CLASS(GLTFState); + GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh); + GDREGISTER_CLASS(GLTFDocumentExtension); GDREGISTER_CLASS(GLTFDocument); #endif } diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index c170bb107e..08d55de976 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -603,9 +603,9 @@ void GridMapEditor::_do_paste() { _clear_clipboard_data(); } -bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) { +EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) { if (!node) { - return false; + return EditorPlugin::AFTER_GUI_INPUT_PASS; } Ref<InputEventMouseButton> mb = p_event; @@ -616,12 +616,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In floor->set_value(floor->get_value() + mb->get_factor()); } - return true; // Eaten. + return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten. } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->is_command_pressed() || mb->is_shift_pressed())) { if (mb->is_pressed()) { floor->set_value(floor->get_value() - mb->get_factor()); } - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } if (mb->is_pressed()) { @@ -648,19 +648,22 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In _clear_clipboard_data(); input_action = INPUT_NONE; _update_paste_indicator(); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (selection.active) { _set_selection(false); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } else { input_action = INPUT_ERASE; set_items.clear(); } } else { - return false; + return EditorPlugin::AFTER_GUI_INPUT_PASS; } - return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true); + if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) { + return EditorPlugin::AFTER_GUI_INPUT_STOP; + } + return EditorPlugin::AFTER_GUI_INPUT_PASS; } else { if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) { if (set_items.size()) { @@ -677,7 +680,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In } set_items.clear(); input_action = INPUT_NONE; - return set_items.size() > 0; + + if (set_items.size() > 0) { + return EditorPlugin::AFTER_GUI_INPUT_STOP; + } + return EditorPlugin::AFTER_GUI_INPUT_PASS; } if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) { @@ -690,11 +697,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action != INPUT_NONE) { set_items.clear(); input_action = INPUT_NONE; - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) { input_action = INPUT_NONE; - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } } } @@ -702,7 +709,10 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - return do_input_action(p_camera, mm->get_position(), false); + if (do_input_action(p_camera, mm->get_position(), false)) { + return EditorPlugin::AFTER_GUI_INPUT_STOP; + } + return EditorPlugin::AFTER_GUI_INPUT_PASS; } Ref<InputEventKey> k = p_event; @@ -714,16 +724,16 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In _clear_clipboard_data(); input_action = INPUT_NONE; _update_paste_indicator(); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } else if (selection.active) { _set_selection(false); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } else { selected_palette = -1; mesh_library_palette->deselect_all(); update_palette(); _update_cursor_instance(); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } } @@ -731,12 +741,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_PREV_LEVEL))) { selection.click[edit_axis]--; _validate_selection(); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_NEXT_LEVEL))) { selection.click[edit_axis]++; _validate_selection(); - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } } } @@ -755,12 +765,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In if (step) { floor->set_value(floor->get_value() + step); } - return true; + return EditorPlugin::AFTER_GUI_INPUT_STOP; } } accumulated_floor_delta = 0.0; - return false; + return EditorPlugin::AFTER_GUI_INPUT_PASS; } struct _CGMEItemSort { diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 4bc849e071..1a6b1310d8 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -232,7 +232,7 @@ protected: static void _bind_methods(); public: - bool forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event); + EditorPlugin::AfterGUIInput forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event); void edit(GridMap *p_gridmap); GridMapEditor() {} @@ -250,7 +250,7 @@ protected: void _notification(int p_what); public: - virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); } + virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); } virtual String get_name() const override { return "GridMap"; } bool has_main_screen() const override { return false; } virtual void edit(Object *p_object) override; 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/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/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/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/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml index 45a6f991bf..abd860a55f 100644 --- a/modules/mono/doc_classes/CSharpScript.xml +++ b/modules/mono/doc_classes/CSharpScript.xml @@ -8,7 +8,7 @@ See also [GodotSharp]. </description> <tutorials> - <link title="C# tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html</link> + <link title="C# documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/index.html</link> </tutorials> <methods> <method name="new" qualifiers="vararg"> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs index 0f50c90531..1d7bfaf0a4 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs @@ -121,6 +121,7 @@ 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"); MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 8fe08e7e1d..746612477d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -117,7 +117,7 @@ namespace Godot /// { /// for (int i = 0; i < 100; i++) /// { - /// await ToSignal(GetTree(), "idle_frame"); + /// await ToSignal(GetTree(), "process_frame"); /// GD.Print($"Frame {i}"); /// } /// } diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 375ad413c4..24bd1ed492 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -122,7 +122,7 @@ public: private: _GodotSharpDirs() { - res_data_dir = "res://.godot/mono"; + res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().plus_file("mono"); res_metadata_dir = res_data_dir.plus_file("metadata"); res_assemblies_base_dir = res_data_dir.plus_file("assemblies"); res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config()); 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/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index 6b616dd52d..d0a27b27c1 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -35,7 +35,7 @@ #include "core/os/os.h" -// Here, after os/os.h +#define WIN32_LEAN_AND_MEAN #include <windows.h> namespace MonoRegUtils { diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index ec04d50704..64aec5d359 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -36,6 +36,7 @@ #include "core/os/os.h" #ifdef WINDOWS_ENABLED +#define WIN32_LEAN_AND_MEAN #include <windows.h> #define ENV_PATH_SEP ";" 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/text_server_adv/SCsub b/modules/text_server_adv/SCsub index 7cd4db6f67..68d1af84df 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') diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f5d159040f..e95369ead7 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); @@ -1221,7 +1217,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced 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 +1590,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 +2119,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 +2477,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 +2502,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 +2555,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 +3163,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 +3191,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 +3353,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 +3381,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 +4487,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 +4515,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 +4681,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 +4885,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 +4912,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 "%"; @@ -4814,11 +4926,11 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { 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..333b68e074 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -79,6 +79,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 +271,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(){}; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 3d868d7be3..193588c4ed 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: { @@ -683,7 +676,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback 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 +1297,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 +1655,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 +1715,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 +2267,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 +2295,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 +2418,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 +2446,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 +2958,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 +2986,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 +3146,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/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/config.py b/modules/visual_script/config.py index b15479797c..e8990c43c8 100644 --- a/modules/visual_script/config.py +++ b/modules/visual_script/config.py @@ -17,6 +17,7 @@ def get_doc_classes(): "VisualScriptConstant", "VisualScriptConstructor", "VisualScriptCustomNode", + "VisualScriptCustomNodes", "VisualScriptDeconstruct", "VisualScriptEditor", "VisualScriptEmitSignal", diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index 372d46bc10..be6bf00e50 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -9,7 +9,7 @@ You are most likely to use this class via the Visual Script editor or when writing plugins for it. </description> <tutorials> - <link title="VisualScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link> + <link title="VisualScript documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/visual_script/index.html</link> </tutorials> <methods> <method name="add_custom_signal"> diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml new file mode 100644 index 0000000000..1681da7653 --- /dev/null +++ b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualScriptCustomNodes" inherits="Object" version="4.0"> + <brief_description> + Manages custom nodes for the Visual Script editor. + </brief_description> + <description> + This singleton can be used to manage (i.e., add or remove) custom nodes for the Visual Script editor. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_custom_node"> + <return type="void" /> + <argument index="0" name="name" type="String" /> + <argument index="1" name="category" type="String" /> + <argument index="2" name="script" type="Script" /> + <description> + Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter. + </description> + </method> + <method name="remove_custom_node"> + <return type="void" /> + <argument index="0" name="name" type="String" /> + <argument index="1" name="category" type="String" /> + <description> + Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed. + </description> + </method> + </methods> + <signals> + <signal name="custom_nodes_updated"> + <description> + Emitted when a custom Visual Script node is added or removed. + </description> + </signal> + </signals> +</class> 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_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index cded1e587c..c62de64a85 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -121,7 +121,7 @@ public: ret = STEP_EXIT_FUNCTION_BIT; break; //return the yield case VisualScriptYield::YIELD_FRAME: - state->connect_to_signal(tree, "idle_frame", Array()); + state->connect_to_signal(tree, "process_frame", Array()); break; case VisualScriptYield::YIELD_PHYSICS_FRAME: state->connect_to_signal(tree, "physics_frame", Array()); 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/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/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index f6f360503f..618fe14137 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -26,7 +26,8 @@ <method name="close"> <return type="void" /> <description> - Close the peer connection and all data channels associated with it. Note, you cannot reuse this object for a new connection unless you call [method initialize]. + Close the peer connection and all data channels associated with it. + [b]Note:[/b] You cannot reuse this object for a new connection unless you call [method initialize]. </description> </method> <method name="create_data_channel"> diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml index ab7ef6c4d0..2f455c32fd 100644 --- a/modules/websocket/doc_classes/WebSocketPeer.xml +++ b/modules/websocket/doc_classes/WebSocketPeer.xml @@ -4,7 +4,7 @@ A class representing a specific WebSocket connection. </brief_description> <description> - This class represent a specific WebSocket connection, you can do lower level operations with it. + This class represents a specific WebSocket connection, allowing you to do lower level operations with it. You can choose to write to the socket in binary or text mode, and you can recognize the mode used for writing by the other peer. </description> <tutorials> 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_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/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; |